mnemos
Local-first MCP memory server for AI agents, with source citations and OKF/Markdown knowledge bases.
Documentation
mnemos
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.
mnemos fixes 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 over
MCP, so Claude can **search, read, and cite your own
knowledge** instead of guessing, with every answer landing on the exact `file#section`
and line range.
Try it in 60 seconds
# 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"> Prefer `make build` (→ `./bin/mnemos`) to keep it off your `$PATH`. The default build
> is pure Go / cgo-free (`CGO_ENABLED=0`).
`search` prints citations you can open:
1. security/scim.md#Provisioning
lines 42-88
score 12.7Then wire it into Claude Code (note the absolute `--config` path):
claude mcp add mnemos -- mnemos serve --config /abs/path/to/myproject/.mnemos/mnemos.tomlNow Claude answers from your project instead of guessing, and shows its source:
> You: How do I recover lost commits?
>
> Claude: Per `recovery/reflog.md`, the reflog records where `HEAD` and 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 full
⚠️ One gotcha: a document's identity is its path relative to where you ran ingest
A document's URI is its path relative to the scan root you ingested (`docs` above), not
your working directory. Ingesting two directories that each contain (say) `index.md`
resolves both to the same URI: the second ingest silently overwrites the first. To
index several trees cleanly, ingest from one common root (`mnemos ingest .`). Details in
Why mnemos
- 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 exact `file#section` and 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.
How it works
your files → mnemos index (SQLite/FTS5) → Claude Code memory → cited answersOnce 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. See
Does it actually retrieve?
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.8Every result is a real `file#section` and line range you can open — that is the whole
point.
Retrieval quality, measured. `mnemos eval` auto-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
shipped `examples/git-recipes` bundle (6 recipes, keyword-style queries):
| Retriever | Hit@1 | Recall@12 | MRR@12 |
|---|---|---|---|
| Lexical, default (FTS5 / bm25) | 0.83 | 0.83 | 0.83 |
| Semantic + hybrid (`--semantic`) | 1.00 | 1.00 | 1.00 |
All three are fractions in `[0,1]` (×100 for a percentage); higher is better. The
`@K` is the retrieval depth — top‑1 for Hit, top‑12 for the rest:
- Hit@1 — share of queries whose #1 result is the correct document (`0.83` = 5/6).
- Recall@12 — share where the correct document appears anywhere in the top 12.
- MRR@12 — mean reciprocal rank: average of `1/(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 (see
Semantic search) earns its keep on harder,
natural-language-over-structured-data queries: on the `examples/onpage-seo` bundle, whose
held-out answers are JSON-LD / sitemap-XML blocks that share *no* keywords with their
prose, lexical scores `0.00` while `--semantic` recovers Hit@1 `0.57` / Recall@12 `0.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.57Connect Claude Code
The 60-second path above used `claude mcp add` with an absolute `--config` path:
claude mcp add mnemos -- mnemos serve --config /abs/path/to/project/.mnemos/mnemos.tomlTo share it with the repo, commit it via `.mcp.json` instead:
{ "mcpServers": { "mnemos": { "command": "mnemos", "args": ["serve", "--config", "/abs/path/to/project/.mnemos/mnemos.toml"] } } }Verify with `claude mcp list` (should show `mnemos ✓ connected`) and `/mcp` inside
a session. Claude then calls the tools automatically; see Capabilities.
Why the --config path must be absolute
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 serve`
resolves a relative `[storage].path` against the config file's directory, so an
absolute `--config` is 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 bare `mnemos serve` only 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, `serve` fails with a clear error instead of silently
returning empty results.
One command wires it in: Claude Code reports mnemos ✓ connected.
Semantic search: the question says "disappeared" — a word that appears nowhere in the notes — yet Claude finds and cites recovery/reflog.md.
> This clip uses the optional semantic build (`make install-embed` + `mnemos models install all-MiniLM-L6-v2` + `use_vectors = true`; see Semantic search). The default `make install` binary 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 are *passive*: they're available, but Claude still has to decide to call
`mnemos.search` before answering or `mnemos.remember` when you say something worth
keeping, and models often don't. The bundled `mnemos-okf` skill closes that
gap by encoding *when* to 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 hooksOr place it manually, e.g. project-level for this repo only:
mkdir -p .claude/skills && cp -r skills/mnemos-okf .claude/skills/mnemos-okfCapture is deliberately conservative (durable facts only, secret-scanned) and stays
gated behind `allow_write`/`allow_delete`: the skill never grants access the config
hasn't opted into. See `skills/mnemos-okf/SKILL.md`.
The memory loop
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 everythingThe bundled `mnemos-okf` skill encodes this as six modes: RECALL, CAPTURE, OKF, RESTORE, TASK, and CONSOLIDATE. Tasks are `Task` documents grouped by `mnemos task list`. Consolidation never overwrites silently: conflicts are surfaced and passes are journaled.
The reference layout is in `examples/project-memory/bundle/`, a fictional project with status, constraints, decisions, tasks (state/history split), and a consolidation journal. Ingest it to see `mnemos task list` in action:
mnemos add examples/project-memory/bundle --into aurora --collection aurora
mnemos task listin_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 timeoutAutomation with hooks
The skill is advisory: the model decides when to fire each mode. Claude Code hooks make the memory loop deterministic. `make install-skill` (or `make install-hooks` on its own) merges `skills/mnemos-okf/hooks/settings.example.json` into your `~/.claude/settings.json` idempotently, keeping a `.bak`; pass `SKIP_HOOKS=1` to opt out, or merge the file by hand for a project-level `.claude/settings.json`. Two hooks are activated:
| Hook | Matcher | Effect | ||
|---|---|---|---|---|
| `SessionStart` | `startup\ | resume\ | compact` | Injects the working set at session start: `mnemos task list` plus recent decisions (`mnemos ls decisions`). The `compact` matcher re-injects it after context compaction. |
| `UserPromptSubmit` | recall cue phrases | When the prompt matches "as we decided", "what was", "remember when", and similar cues, injects the top 3 `mnemos search` hits. Requires `jq`. Silent no-op when no cue matches. |
PreCompact and Stop persistence (session summaries, capture flush) stays in the skill because those hook events cannot inject context into the model.
Capabilities
Claude reaches your memory through MCP tools (and you through the matching CLI
commands). Note the spelling: `mnemos.search` is the MCP tool Claude calls;
`mnemos search` is the CLI command you run.
Query (read-only, no gate)
- `mnemos.search`: ranked, filtered retrieval with citations.
- `mnemos.read`: read a precise chunk (by `chunk_id`) or a whole document (by `uri`). Pass `follow_links: true` to also attach the document's 1-hop link neighbors.
- `mnemos.context`: top-k results as LLM-ready context blocks (`uri:start-end` → content). Pass `follow_links: true` to 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 with `resolved: false`. Filter with `direction` (outbound/inbound/both) and `limit`.
- `mnemos.list`: walk the OKF tree on disk and annotate each file with index metadata (title, type, tags, collection) plus an `indexed` flag, so both stored and not-yet-indexed files are visible. Filter by `path`, `collection`, `type`, or indexed state.
Write (requires `allow_write = true`)
- `mnemos.remember`: write a note into memory. Pass an optional `path` (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 is secret-scanned before it is written and indexed.
- `mnemos.okfy`: convert an existing `.txt`/`.md` file in the tree into an OKF document (frontmatter + body) at `out` (defaults to the source path with a `.md` extension) and index it, leaving the source intact. The source body is secret-scanned first.
`mnemos edit ` is the human counterpart: a terminal editor for one document, gated by the same `allow_write` flag, with no MCP tool of its own. See Edit documents interactively.
Manage (requires `allow_delete = true`)
- `mnemos.forget`: remove a file from the OKF tree and de-index it; idempotent.
- `mnemos.move`: move a file or directory within 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).
Keep memory fresh
Run a watcher to reindex on change (incremental; removes deleted files):
mnemos watch . --collection myprojectEnable write-back in `.mnemos/mnemos.toml` so Claude can capture and manage notes:
[mcp]
allow_write = true # gates mnemos.remember and mnemos.okfy
allow_delete = true # gates mnemos.forget and mnemos.moveIf a watcher is running over the tree, `forget`/`move` operations 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 = true` when a watcher
covers `capture_dir` to avoid double indexation of remembered notes.
Edit documents interactively
`mnemos edit ` 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 OKF `type`. A
known enum (a task's `status` or `priority`) cycles with the arrow keys,
`tags` is retyped as a whole list, unknown fields fall back to free text,
and index-owned fields like `type` are read-only.
- CONTENT: the body, handed to `$EDITOR` for editing and reloaded on exit.
mnemos edit tasks/ship.mdKeys: `tab` focus, `↑↓` move, `enter` open/edit, `←→` cycle an enum, `e`
`$EDITOR`, `m` move/rename, `s` save, `b`/backspace back, `q` quit. 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.
`m` moves or renames the open document. It prompts with the current uri:
edit it freely, or press `tab` for a fuzzy-filtered picker of the directories
that already hold documents (`enter` relocates the filename under the picked
one, `esc` returns 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. Like `mnemos mv`,
it needs `[mcp].allow_delete = true` since the old index entries are deleted.
It requires a uri: bare `mnemos edit` errors, there is no tree-browsing picker
yet. It is gated the same way as `mnemos.remember`/`mnemos.okfy`:
[mcp]
allow_write = true # also gates mnemos editThere is no matching MCP tool: `mnemos edit` is CLI-only, for a human at the
keyboard.
Semantic search (optional)
The default binary is lexical only (FTS5 / bm25) and stays small and cgo-free.
Local semantic + hybrid retrieval is fully implemented but compiled behind the
`embed` build 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`--semantic` fuses 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; plain `mnemos search` always works.
How it works under the hood (model, pure-Go ONNX inference, RRF fusion):
OKF support
mnemos natively understands OKF
(Open Knowledge Format) bundles, and any Markdown vault with YAML frontmatter and
cross-links, with no special mode:
- frontmatter `tags`/`type` become fuzzy ranking signals in FTS,
- markdown links are captured as edges (stored, not yet traversed),
- `index.md` files are treated as structure only (kept out of FTS and the link graph).
OKF bundles double as the corpus for `mnemos eval`, which auto-derives held-out
query→source pairs and reports Hit@1 / Recall@12 / MRR@12 against a committed
baseline. See docs/architecture.md.
Reference
- **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.
Security
- 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].exclude` globs 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.
See SECURITY.md for the full policy.
Development
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 targetsArchitecture, design principles, and the retrieval-evaluation methodology live in
docs/architecture.md; design decisions are recorded as
ADRs. Contributions welcome; see CONTRIBUTING.md.
License
mnemos is licensed under the MIT License: this covers mnemos's own code
and content. The repository also vendors third-party material that is not
covered by the MIT License and remains under its own terms; see
THIRD-PARTY-NOTICES.md (notably the example OKF bundle in
`examples/onpage-seo/bundle/`).
Frequently asked questions
What is mnemos?
mnemos is Local-first MCP memory server for AI agents, with source citations and OKF/Markdown knowledge bases.
How do I install mnemos?
Open the GitHub repository and follow its README. Most MCP servers are added to your client's MCP config, then called by your agent.
Is mnemos open source?
Yes — it is hosted on GitHub at https://github.com/arhuman/mnemos and has 13 stars.
Related MCP tools
Give your AI agents persistent, collective memory — with deduplicating absorb, supersession lineage, semantic search, and a graph UI. Speaks MCP.
The go-to web for your AI coding agent — local-first search, fetch, crawl & research over MCP. No API keys, no cloud, $0/query. Public beta.
Cut AI token costs 95%+ on code exploration. The leading MCP server for precise, symbol-level GitHub code retrieval via tree-sitter AST. Works with Claude Code, Cursor & any MCP client. 313B+ tokens saved.
Open-source coding agent memory. Records issues, attempts, fixes and decisions, then warns your agent before it repeats an approach that already failed. Native MCP server for Claude Code, Cursor, Antigravity and Codex. 100% local, no cloud, no telemetry. MIT.
eBPF-powered network observability for Kubernetes. Indexes L4/L7 traffic with full K8s context, decrypts TLS without keys. Queryable by AI agents via MCP and humans via dashboard.
GOWA - WhatsApp REST API with support for UI, Multi Account, Webhooks, and MCP, and Chatwoot. Built with Golang for efficient memory use.
Run your own MCP server? See who uses it and what to fix.
Measure it with TrackMCP