{"id":168,"date":"2026-07-25T11:20:24","date_gmt":"2026-07-25T17:20:24","guid":{"rendered":"https:\/\/dionysismedia.ca\/?p=168"},"modified":"2026-07-25T11:26:11","modified_gmt":"2026-07-25T17:26:11","slug":"comparing-ai-memory-systems-from-qmd-to-mnemosyne-on-a-cpu-only-server","status":"publish","type":"post","link":"https:\/\/dionysismedia.ca\/?p=168","title":{"rendered":"Comparing AI Memory Systems: From QMD to Mnemosyne on a CPU-Only Server"},"content":{"rendered":"<h2>Why I looked for a new memory backend<\/h2>\n<p>My Hermes Agent setup runs on a headless Ubuntu server with no usable local GPU. The existing long-term memory backend, QMD, is a capable semantic-search engine, but it embeds markdown with GGUF models through <code>node-llama-cpp<\/code>. On a CPU that becomes the bottleneck: every re-indexing batch and every hybrid query carries the overhead of loading and running local embedding and reranking models.<\/p>\n<p>I wanted something that could:<\/p>\n<ul>\n<li>keep search fast on a CPU,<\/li>\n<li>still offer semantic recall when needed,<\/li>\n<li>integrate natively with Hermes,<\/li>\n<li>and optionally offload embedding compute to a remote Ollama box.<\/li>\n<\/ul>\n<h2>The candidates<\/h2>\n<p>I evaluated three systems:<\/p>\n<ul>\n<li><strong>QMD<\/strong> \u2014 the incumbent. SQLite + BM25 keyword search, optional dense embeddings and LLM reranking via local GGUF models.<\/li>\n<li><strong>MemPalace<\/strong> \u2014 a heavily benchmarked palace-structure memory system (ChromaDB + small embeddings, knowledge graph, compression). It targets AI-agent retention hooks rather than arbitrary markdown knowledge bases.<\/li>\n<li><strong>Mnemosyne<\/strong> \u2014 a Hermes-first memory provider. SQLite-backed, FTS5 keyword search by default, optional embeddings through fastembed or a remote OpenAI-compatible endpoint.<\/li>\n<\/ul>\n<h2>How I tested<\/h2>\n<p>I used a mix of representative notes: a system configuration file, a user-profile file, a contact list, and several long-form markdown creative documents. Names, addresses, and phone numbers in the contact sample were replaced with placeholders before any reporting.<\/p>\n<p>For each candidate I measured:<\/p>\n<ul>\n<li>installation footprint,<\/li>\n<li>time to store a memory,<\/li>\n<li>time to recall a memory,<\/li>\n<li>local RAM usage,<\/li>\n<li>and recall quality for keyword and semantic queries.<\/li>\n<\/ul>\n<h2>Key results<\/h2>\n<table>\n<thead>\n<tr>\n<th>System<\/th>\n<th>Local RAM<\/th>\n<th>Store latency<\/th>\n<th>Recall latency<\/th>\n<th>Notes<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>QMD (local GGUF)<\/td>\n<td>Moderate\u2013high<\/td>\n<td>Slow on CPU<\/td>\n<td>Slow on CPU<\/td>\n<td>Best hybrid quality, but CPU-bound<\/td>\n<\/tr>\n<tr>\n<td>MemPalace<\/td>\n<td>~800 MB\u20131.5 GB<\/td>\n<td>Embedding-bound<\/td>\n<td>Fast after embedding<\/td>\n<td>Agent-retention focused, heavier for a raw markdown archive<\/td>\n<\/tr>\n<tr>\n<td>Mnemosyne (no embeddings)<\/td>\n<td>~84 MB<\/td>\n<td>~0.2\u20130.4 s<\/td>\n<td>~0.03\u20130.06 s<\/td>\n<td>Keyword-only, very fast, lower semantic recall<\/td>\n<\/tr>\n<tr>\n<td>Mnemosyne + remote Ollama<\/td>\n<td>~87 MB<\/td>\n<td>~0.5\u20132.8 s<\/td>\n<td>~0.1\u20131.3 s<\/td>\n<td>Semantic search offloaded to GPU; local footprint stays tiny<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2>What the numbers mean<\/h2>\n<p>QMD and MemPalace both do good work, but they are embedding-first. On a CPU-only box the embedding step dominates every operation. Mnemosyne&#8217;s default mode avoids that entirely by using SQLite FTS5. Search is genuinely sub-second and RAM stays under 100 MB.<\/p>\n<p>The trade-off is recall quality. In pure keyword mode, Mnemosyne can rank a profile note above a note that is literally <em>about<\/em> the queried topic, because keyword frequency wins over semantic intent. Enabling remote embeddings fixes that: queries like &#8220;QMD memory&#8221; returned the correct document first, and music-related queries surfaced the right creative files.<\/p>\n<h2>Migration and cleanup<\/h2>\n<p>The old QMD collection had grown to about 244 files and 4.1 MB, dominated by multiple drafts of two novels and their compiled full manuscripts. After reviewing an inventory I removed the duplicate and draft material, keeping only a small set of creative notes. The remaining files were migrated into Mnemosyne as global-scope memories with Ollama-generated embeddings.<\/p>\n<p>I then:<\/p>\n<ul>\n<li>installed <code>mnemosyne-hermes<\/code> into the active Hermes virtual environment,<\/li>\n<li>linked the Mnemosyne plugin wrapper into <code>~\/.hermes\/plugins\/mnemosyne<\/code>,<\/li>\n<li>set <code>memory.provider = mnemosyne<\/code> in Hermes config,<\/li>\n<li>added the Ollama embedding environment variables to the Hermes gateway systemd service,<\/li>\n<li>and removed QMD&#8217;s markdown tree, index, and binary symlinks.<\/li>\n<\/ul>\n<h2>Final configuration<\/h2>\n<p>The gateway now starts with these environment variables baked into its systemd unit:<\/p>\n<pre>MNEMOSYNE_DATA_DIR=\/home\/jess\/.hermes\/mnemosyne\nMNEMOSYNE_EMBEDDING_API_URL=http:\/\/192.168.X.XXX:11434\/v1\nMNEMOSYNE_EMBEDDING_MODEL=nomic-embed-text:latest\nMNEMOSYNE_EMBEDDING_DIM=768\nMNEMOSYNE_LLM_ENABLED=false\n<\/pre>\n<p>This keeps all memory data local in SQLite while sending only embedding requests to the GPU box. A live test confirmed the provider is active and recall works: a newly stored memory was retrieved correctly by semantic query.<\/p>\n<h2>Bottom line<\/h2>\n<p>For a CPU-only Hermes deployment that still wants semantic memory, Mnemosyne with a remote Ollama embedding endpoint is the sweet spot. It preserves local speed and privacy, keeps RAM tiny, and only uses remote compute for the parts that actually need a GPU. QMD and MemPalace are better suited to machines that can run embeddings locally without pain.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Why I looked for a new memory backend My Hermes Agent setup runs on a headless Ubuntu server with no usable local GPU. The existing long-term memory backend, QMD, is a capable semantic-search engine, but it embeds markdown with GGUF models through node-llama-cpp. On a CPU that becomes the bottleneck: every re-indexing batch and every<\/p>\n<p><a href=\"https:\/\/dionysismedia.ca\/?p=168\" class=\"more-link themebutton\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[12],"class_list":["post-168","post","type-post","status-publish","format-standard","hentry","category-general","tag-ai"],"_links":{"self":[{"href":"https:\/\/dionysismedia.ca\/index.php?rest_route=\/wp\/v2\/posts\/168","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dionysismedia.ca\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dionysismedia.ca\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dionysismedia.ca\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dionysismedia.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=168"}],"version-history":[{"count":1,"href":"https:\/\/dionysismedia.ca\/index.php?rest_route=\/wp\/v2\/posts\/168\/revisions"}],"predecessor-version":[{"id":169,"href":"https:\/\/dionysismedia.ca\/index.php?rest_route=\/wp\/v2\/posts\/168\/revisions\/169"}],"wp:attachment":[{"href":"https:\/\/dionysismedia.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=168"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dionysismedia.ca\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=168"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dionysismedia.ca\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=168"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}