Mnemos
About
Local-first MCP memory server with no external dependency, source citations and OKF/Markdown KB.
Details
- Author
- arhuman
- Categories
- AI, Knowledge Base, Other
Jump to
Setup
Install Mnemos in your MCP client (Claude Desktop, Cursor, Windsurf, and others).
Repository: https://github.com/arhuman/mnemos
Follow the installation instructions in the repository README, then restart your MCP client.
Give your AI agent a memory it can cite.
Local memory for AI agents. Source citations included.
Claude Code is powerful, but it forgets your project context:
- it forgets why you rejected an architecture,
- it misses your ADRs,
- it invents answers instead of reading your docs,
- it can't reliably cite where a claim came from.
mnemosfixes that by giving it a local, cited memory of:
- your ADRs and design docs
- your notes and runbooks
- your source code
- your OKF knowledge base
No vector database. No Ollama. No Python or Node service. Just one cgo-free Go binary that indexes your files — any plain-Markdown folder works as-is — and serves them overMCP, so Claude cansearch, read, and cite your own knowledgeinstead of guessing, with every answer landing on the exactfile#sectionand line range.
# 1. install — one cgo-free binary into $GOBIN (requires Go 1.25+) git clone https://github.com/arhuman/mnemos.git && cd mnemos make install # 2. index a project cd ~/work/myproject mnemos init # creates ./.mnemos/ (mnemos.toml, kb, db, models) mnemos ingest docs --collection myproject # index a directory mnemos search "why did we choose this architecture"
Prefermake build(→./bin/mnemos) to keep it off your$PATH. The default build is pure Go / cgo-free (CGO_ENABLED=0).
1. security/scim.md#Provisioning lines 42-88 score 12.7
Then wire it into Claude Code (note theabsolute--configpath):
claude mcp add mnemos -- mnemos serve --config /abs/path/to/myproject/.mnemos/mnemos.toml
Now Claude answers from your project instead of guessing, and shows its source:
Claude:Perrecovery/reflog.md, the reflog records whereHEADand each branch tip has pointed — even after a hard reset — so you can check out the lost commit's hash.(recovery/reflog.md — "Reflog: recover lost commits")
That's the whole loop —index → ask → cited answer.Everything below is depth:why it's built this way,how it works, and the fullcapabilities.
A document's URI is its path relative to the scan root you ingested (docsabove), not your working directory. Ingesting two directories that each contain (say)index.mdresolves both to the same URI: thesecond ingest silently overwrites the first. To index several trees cleanly, ingest from one common root (mnemos ingest .). Details indocs/paths-and-indexing.md.
- Truly local-first: runs entirely on your machine. No network, no telemetry, no data leaves your project.
- Zero dependencies: one self-contained, cgo-free Go binary. No Python, Docker, Qdrant, or Ollama.
- Any MCP client: built for Claude Code, works with anything that speaks MCP.
- Cited answers: every result links back to the exactfile#sectionand line range, so claims are verifiable.
- Fast search by default: SQLite FTS5 / bm25 out of the box; optional local semantic + hybrid search behind a build tag.
- Read-write memory: the agent can capture durable notes (remember); you can manage the tree (forget,move,list).
- Safe by default: read-only unless you opt in; writes are path-confined and content is secret-scanned.
your files → mnemos index (SQLite/FTS5) → Claude Code memory → cited answers
Once wired in, Claude can answer from your project instead of hand-waving, and point back to the source:
- "Why did we choose this architecture?"
- "Where is the ADR about the rule engine?"
- "Summarize what we know about SCIM provisioning."
- "What changed in this project's memory recently?"
Under the hood, the binary embeds an MCP server, an indexing pipeline, a SQLite store, full-text search, an incremental file watcher, and an admin CLI. Seedocs/architecture.md.
A cited hit, out of the box(default lexical build, on a shipped example bundle):
$ mnemos ingest examples/git-recipes/bundle --collection git $ mnemos search "recover lost commits" --limit 1 1. recovery/reflog.md#Gotcha lines 24-28 score 7.8
Every result is a realfile#sectionand line range you can open — that is the whole point.
Retrieval quality, measured.mnemos evalauto-derives held-out query→source pairs from an OKF bundle (it strips each example block from its own document, then checks whether retrieval still finds the right document) and reports doc-level metrics. On the shippedexamples/git-recipesbundle (6 recipes, keyword-style queries):
All three arefractions in[0,1](×100 for a percentage); higher is better. The@Kis the retrieval depth — top‑1 for Hit, top‑12 for the rest:
- Hit@1— share of queries whose#1result is the correct document (0.83= 5/6).
- Recall@12— share where the correct document appearsanywhere in the top 12.
- MRR@12— mean reciprocal rank: average of1/(rank of the first correct doc)over the top 12 (1.0= always ranked first).
The default lexical build already nails keyword retrieval. The optional embed build (seeSemantic search) earns its keep on harder, natural-language-over-structured-data queries: on theexamples/onpage-seobundle, whose held-out answers are JSON-LD / sitemap-XML blocks that sharenokeywords with their prose, lexical scores0.00while--semanticrecovers Hit@10.57/ Recall@120.86. Reproduce (N is 6 and 7 respectively — smoke signals, not benchmarks):
mnemos eval examples/git-recipes/bundle # lexical → 0.83 make build-embed && mnemos models install all-MiniLM-L6-v2 mnemos eval examples/git-recipes/bundle --semantic # hybrid → 1.00 mnemos eval examples/onpage-seo/bundle --semantic # the hard case → 0.57
The 60-second path above usedclaude mcp addwith anabsolute--configpath:
claude mcp add mnemos -- mnemos serve --config /abs/path/to/project/.mnemos/mnemos.toml
To share it with the repo, commit it via.mcp.jsoninstead:
{ "mcpServers": { "mnemos": { "command": "mnemos", "args": ["serve", "--config", "/abs/path/to/project/.mnemos/mnemos.toml"] } } }
Verify withclaude mcp list(should showmnemos ✓ connected) and/mcpinside a session. Claude then calls the tools automatically; seeCapabilities.
Claude Code does not guarantee the working directory it spawns the server in, so anchoring to the config file is what makes retrieval reliable.mnemos serveresolves a relative[storage].pathagainst the config file's directory, so an absolute--configis all you need: the database, capture directory, and tree root all anchor next to that file regardless of where Claude Code launches the server. A baremnemos serveonly finds your data when the server's working directory happens to be the project root, which Claude Code does not promise; when the database can't be found,servefails with a clear error instead of silently returning empty results.
One command wires it in: Claude Code reportsmnemos ✓ connected.
Semantic search:the question says"disappeared"— a word that appears nowhere in the notes — yet Claude finds and citesrecovery/reflog.md.
This clip uses theoptional semantic build(make install-embed+mnemos models install all-MiniLM-L6-v2+use_vectors = true; seeSemantic search). Thedefaultmake installbinary is lexical-only, so it won't answer a keyword-free question like this — search by keyword instead (e.g.mnemos search "recover lost commits", which hits the same doc).
Make Claude use memory automatically (optional skill)
MCP tools arepassive: they're available, but Claude still has to decide to callmnemos.searchbefore answering ormnemos.rememberwhen you say something worth keeping, and models often don't. The bundledmnemos-okfskillcloses that gap by encodingwhento reach for memory: recall before answering from assumption, capture durable facts, and drive the OKF tools.
It's optional and Claude Code-specific: the server works with any MCP client without it. Install it user-wide (all projects):
make install-skill # copies skills/mnemos-okf -> ~/.claude/skills/ and merges its hooks
Or place it manually, e.g. project-level for this repo only:
mkdir -p .claude/skills && cp -r skills/mnemos-okf .claude/skills/mnemos-okf
Capture is deliberately conservative (durable facts only, secret-scanned) and stays gated behindallow_write/allow_delete: the skill never grants access the config hasn't opted into. Seeskills/mnemos-okf/SKILL.md.
mnemos is local project memory for coding agents: cited recall, durable project state, knowledge consolidation.
prompt -> recall (search first, cite) -> act -> capture durable facts to the inbox -> update project/task state -> consolidate raw captures into canonical docs -> cite everything
The reference layout is inexamples/project-memory/bundle/, a fictional project with status, constraints, decisions, tasks (state/history split), and a consolidation journal. Ingest it to seemnemos task listin action:
mnemos add examples/project-memory/bundle --into aurora --collection aurora mnemos task list
in_progress (1) aurora/tasks/rate-limit-ingest.md Rate-limit the ingest endpoint todo (1) aurora/tasks/csv-export.md Add CSV export done (1) aurora/tasks/fix-auth-timeout.md Fix auth token timeout
The skill is advisory: the model decides when to fire each mode. Claude Code hooks make the memory loop deterministic.make install-skill(ormake install-hookson its own) mergesskills/mnemos-okf/hooks/settings.example.jsoninto your~/.claude/settings.jsonidempotently, keeping a.bak; passSKIP_HOOKS=1to opt out, or merge the file by hand for a project-level.claude/settings.json. Two hooks are activated:
PreCompact and Stop persistence (session summaries, capture flush) stays in the skill because those hook events cannot inject context into the model.
Claude reaches your memory through MCP tools (and you through the matching CLI commands). Note the spelling:mnemos.searchis theMCP toolClaude calls;mnemos searchis theCLI commandyou run.
- mnemos.search: ranked, filtered retrieval with citations.
- mnemos.read: read a precise chunk (bychunk_id) or a whole document (byuri). Passfollow_links: trueto also attach the document's 1-hop link neighbors.
- mnemos.context: top-k results as LLM-ready context blocks (uri:start-end→ content). Passfollow_links: trueto attach each block document's 1-hop link neighbors.
- mnemos.related: the link-graph neighbors of a document, its outbound links and inbound backlinks (1 hop, document-level). Dangling outbound targets are returned withresolved: false. Filter withdirection(outbound/inbound/both) andlimit.
- mnemos.list: walk the OKF tree on disk and annotate each file with index metadata (title, type, tags, collection) plus anindexedflag, so both stored and not-yet-indexed files are visible. Filter bypath,collection,type, or indexed state.
- mnemos.remember: write a note into memory. Pass an optionalpath(e.g."adr/0003-rule-engine.md") to place it at an explicit location in the OKF tree instead of auto-naming under[capture].dir. Content issecret-scannedbefore it is written and indexed.
- mnemos.okfy: convert an existing.txt/.mdfile in the tree into an OKF document (frontmatter + body) atout(defaults to the source path with a.mdextension) and index it, leaving the source intact. The source body issecret-scannedfirst.
mnemos edit <uri>is the human counterpart: a terminal editor for one document, gated by the sameallow_writeflag, with no MCP tool of its own. SeeEdit documents interactively.
- mnemos.forget: remove a file from the OKF tree and de-index it; idempotent.
- mnemos.move: move a fileor directorywithin the tree and re-index it under the new path. A directory moves its whole subtree, preserving each document's collection. Inbound markdown links to the old paths are not rewritten in V0 (logged as a warning).
Run a watcher to reindex on change (incremental; removes deleted files):
Enable write-back in.mnemos/mnemos.tomlso Claude can capture and manage notes:
[mcp] allow_write = true # gates mnemos.remember and mnemos.okfy allow_delete = true # gates mnemos.forget and mnemos.move
If a watcher is running over the tree,forget/moveoperations are also seen by the watcher (redundant but idempotent); the tools update the index directly and work without a watcher. Set[capture] defer_to_watcher = truewhen a watcher coverscapture_dirto avoid double indexation of remembered notes.
mnemos edit <uri>opens a terminal editor over one OKF document at a time, split into three panes:
- NAV: the document's outbound links, inbound backlinks, and (once an embed build has computed embeddings for the corpus) semantically similar documents; otherwise that section shows an unavailable hint instead of results.
- METADATA: frontmatter fields, typed per the document's OKFtype. A known enum (a task'sstatusorpriority) cycles with the arrow keys,tagsis retyped as a whole list, unknown fields fall back to free text, and index-owned fields liketypeare read-only.
- CONTENT: the body, handed to$EDITORfor editing and reloaded on exit.
Keys:tabfocus,↑↓move,enteropen/edit,←→cycle an enum,e$EDITOR,mmove/rename,ssave,b/backspace back,qquit. Saving writes the file first and then reindexes just that document, so an edit is never lost even if reindexing fails; frontmatter writes preserve the rest of the file (comments, key order, unrelated fields) instead of rewriting it. Navigating to another document while the current one is unsaved saves it first.
mmoves or renames the open document. It prompts with the current uri: edit it freely, or presstabfor a fuzzy-filtered picker of the directories that already hold documents (enterrelocates the filename under the picked one,escreturns to the prompt). Committing renames the file on disk, reindexes it under the new uri, and reopens the editor there; inbound links still pointing at the old path are reported, not rewritten. Likemnemos mv, it needs[mcp].allow_delete = truesince the old index entries are deleted.
It requires a uri: baremnemos editerrors, there is no tree-browsing picker yet. It is gated the same way asmnemos.remember/mnemos.okfy:
[mcp] allow_write = true # also gates mnemos edit
There is no matching MCP tool:mnemos editis CLI-only, for a human at the keyboard.
The default binary islexical only(FTS5 / bm25) and stays small and cgo-free. Local semantic + hybrid retrieval is fully implemented but compiled behind theembedbuild tag, so the ONNX/tokenizer dependencies never enter the default binary. To enable it:
make build-embed # or: make install-embed (still cgo-free, CGO_ENABLED=0) mnemos models install all-MiniLM-L6-v2 # downloads the embedding model into ~/.mnemos/models mnemos reindex --embeddings # compute vectors for already-indexed chunks mnemos search "why did we choose this architecture" --semantic
--semanticfuses bm25 with vector similarity, so natural-language queries that the lexical index misses still resolve. Without the embed build (or an installed model) the flag is rejected with a clear message; plainmnemos searchalways works.
How it works under the hood (model, pure-Go ONNX inference, RRF fusion):docs/architecture.md.
mnemos natively understandsOKF(Open Knowledge Format) bundles, and any Markdown vault with YAML frontmatter and cross-links, with no special mode:
- frontmattertags/typebecome fuzzy ranking signals in FTS,
- markdown links are captured as edges (stored, not yet traversed),
- index.mdfiles are treated as structure only (kept out of FTS and the link graph).
OKF bundles double as the corpus formnemos eval, which auto-derives held-out query→source pairs and reports Hit@1 / Recall@12 / MRR@12 against a committed baseline. Seedocs/architecture.md.
- docs/commands.md— every CLI command and its flags.
- docs/configuration.md— the layered.mnemos/mnemos.toml, with all defaults.
- docs/paths-and-indexing.md— how state is located, what gets indexed, where writes land, and the idempotency/URI rules.
- docs/architecture.md— design principles and the retrieval-evaluation methodology.
- No network, no telemetry; the MCP server is stdio-only.
- Shipped binaries carry SBOMs (generated with syft) and are signed with cosign (keyless OIDC).
- Read-only by default. Write-back is opt-in (allow_write = true). Destructive operations (forget, move) require a separate opt-in (allow_delete = true).
- All caller-supplied paths are validated by a confinement guard before any disk operation:..traversal, absolute paths outside the tree root, symlink escapes, access to.mnemos/, and[security].excludeglobs are all rejected.
- Captured content is secret-scanned before it is written or indexed.
- Path/secret exclusion patterns keep.env, keys, and secret dirs out of the index.
make build # cgo-free binary -> bin/ make test # go test -race ./... make audit # golangci-lint (incl. govet + staticcheck) + govulncheck + race tests make tools # install pinned dev tools (golangci-lint, govulncheck) make help # list all targets
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.





