metalmind
A metalmind for Claude. Store decisions in copper. Tap them when you need them. Persistent memory for Claude. Save decisions. Recall them when you need them.
Every claude invocation is a first meeting. Yesterday's architectural call,
the reason you rejected that library, the 40-minute debug you just finished — gone by
tomorrow. metalmind is the place Claude stores things, and the way Claude gets them back —
without burning context tokens on tool schemas to do it.
metalmind init. Today, metalmind only supports Claude Code. Cursor, Codex, Copilot, and Gemini CLI are on the roadmap.
What it adds
Seven things that survive your claude ending, start fresh, and an eighth that
lets you take it all back. One CLI, one verb per concern.
store copper "<insight>"save "<insight>"
deposits a decision into your local Obsidian vault. metalmind proposes the path,
wikilinks, and frontmatter; you approve; it writes. Tomorrow's session recalls it
as if yesterday never ended.
tap copper "<query>"recall "<query>"
is a Bash call, not an MCP tool — zero schema bloat per session. Most memory tools
silently inject a handful of tool schemas — often heavily over-specified — into
every Claude Code session before you've typed a prompt. Measured:
metalmind costs ~2.5× less than mem0 as shipped. We stamp the command into your CLAUDE.md so Claude reaches for
it naturally. --deep follows backlinks; --expand returns
hits plus the surrounding graph.
- hit@5 = 90% · hit@3 = 85% · hit@1 = 70%
- latency median 45 ms · p95 87 ms
burn bronze "<query>"graph "<query>"
queries a code graph of every repo in your
forgegroup.
HTTP-route-match edges connect caller → handler across services in three
tiers: OpenAPI specs on the metalmind shelf (never inside your repos), Java
RestTemplate/WebClient/Feign callers, and URL literals as an opt-in fallback. Every
inferred edge carries INFERRED_NAME / INFERRED_ROUTE /
INFERRED_URL_LITERAL provenance so Claude can trust-grade what it reads.
burn iron <symbol>symbol <symbol>
returns a symbol's neighbors — who calls it, what it calls, its module — in one pass.
burn steel <old> <new>rename <old> <new>
drives a coordinated rename through Serena's LSP backend. One verb per concern; no
LLM required for either.
burn zinc "<bug>"debug "<bug>"
hands a bug to the /team-debug skill with the code graph already primed.
The team agents start with relevant call-paths and files, not cold — so adversary,
skeptic, and archaeologist can each challenge a hypothesis that's grounded in your
actual code.
scribe <verb>note <verb>
is the CRUD interface agents use instead of raw Write — full
flow: create · update · patch · delete · archive · rename · list · show.
It stamps frontmatter, picks the right folder
(Plans/Learnings/Work/Daily/Inbox/MOCs/Archive), auto-links the project
MOC, and on rename rewrites [[wikilinks]] across the vault. Body on
stdin; every verb supports --dry-run.
metalmind uninstall stops containers, unloads the watcher service
(launchd on macOS, systemd on Linux), restores your prior output style, clears the
settings we changed, removes shell aliases. Never touches your notes.
Everything we did is undoable in one command — a design constraint, not an
afterthought.
Why it isn't an MCP server
Most memory tools register themselves as MCP servers. That design injects a handful of
tool schemas (search_memory, recall, store, …)
into every Claude session before you prompt anything. Those schemas eat
context tokens you could be using for the actual task.
metalmind takes the opposite bet: the recall surface is a CLI, Claude learns the command
once from your stamped CLAUDE.md, and every session starts with a clean
context. The watcher, indexer, and embedding stack still live locally — they just don't
live in Claude's tool registry.
Measured in bench/mcp-tax-v0/ — first-turn token tax on a cold session, before any user turn:
| System | Transport | Tools | First-turn tokens |
|---|---|---|---|
| metalmind (default) | loopback HTTP | 0 | ~519 (one-time CLAUDE.md block) |
Claude Code native /memory | CLAUDE.md text | 0 | ~1 |
| metalmind (stdio MCP fallback) | MCP stdio | 3 | ~157 |
mem0 (pinkpixel-dev/mem0-mcp) | MCP stdio | 3 | ~1,319 |
~2.5× lower than mem0 as shipped (loopback-HTTP vs stdio MCP) · ~8.4× lower on the apples-to-apples MCP comparison (metalmind's stdio fallback vs mem0 — same transport, different schema discipline).
The ~519 tokens metalmind spends up front are prose in ~/.claude/CLAUDE.md
that teaches Claude when to recall — work that mem0's schema-tax doesn't do.
Approximation via chars / 4; rerun with pnpm bench:mcp-tax
(add ANTHROPIC_API_KEY for exact counts). Shape is what matters: two
zero-schema transports, one modest, one bloat. Per-call result tokens are billed like
any tool output and are excluded here — this is standing cost before a single
call.
Who should NOT use metalmind
Honest anti-personas — install the wrong tool and you'll bounce in an hour:
- You don't use Claude Code. SessionStart hook, stamped
CLAUDE.md, MCP fallback — all target Claude Code specifically. Cursor/Codex/Copilot/Gemini are roadmap. - You don't use Obsidian. The vault is the storage layer. No other UI is planned.
- You don't want Docker running. Qdrant + Ollama embed-stack is local but containerized.
sqlite-vecbackend is on the roadmap. - You want a 2-minute install. The wizard takes ~15 minutes the first time — prereqs, embed-model download, first-index. Worth it for daily users; overkill for evaluation.
- You're a team of 5+ with shared memory needs. metalmind is single-dev by design. The forge supports many repos per dev; it does not sync vaults between devs.
Will this still be around?
Fair question for any solo-maintainer tool. The sustainability story:
- Your notes outlive metalmind. The vault is plain markdown in your own
~/Knowledge/directory. If this project goes unmaintained tomorrow, you keep everything — Obsidian still opens the files,grepstill searches them,gitstill versions them. metalmind is the layer that makes Claude use them well, not the layer that holds them hostage. - No cloud, no accounts, no phone-home. Embeddings, indexing, recall, code graphs — all local. There is no metalmind backend to shut down, no API quota to throttle, no subscription to lapse. The only network call is the one you were already making to Claude.
- Reversible in one command.
metalmind uninstallstops the watcher, removes Docker containers, strips the sentinel-bounded blocks from yourCLAUDE.mdfiles, and clears shell aliases. Your vault is never touched. Try it — then reinstall if you like it. - MIT licensed. Fork it, vendor it, swap the embedding backend. Architecture decisions are documented in
docs/,bench/, and CHANGELOG specifically so a contributor — or a future-you — can keep it running.
Commands
| Metal | Command | Description |
|---|---|---|
| Copper ↓ | $ metalmind store copper "..." $ metalmind save "..." | Deposit an insight to the vault. |
| Copper ↑ | $ metalmind tap copper "<q>" $ metalmind recall "<q>" | Retrieve semantically (--deep / --expand). |
| Bronze | $ metalmind burn bronze "<q>" $ metalmind graph "<q>" | Query the code graph (Seeker). |
| Iron | $ metalmind burn iron "<sym>" $ metalmind symbol "<sym>" | Pull a symbol and its neighbors. |
| Steel | $ metalmind burn steel <o> <n> $ metalmind rename <o> <n> | Coordinated rename via Serena. |
| Tin | $ metalmind burn tin $ metalmind verbose | Enhanced output — verbose toggle. |
| Pewter | $ metalmind burn pewter $ metalmind reindex | Force-rebuild the code graph. |
| Zinc | $ metalmind burn zinc "<bug>" $ metalmind debug "<bug>" | Rioter — dispatch a team-debug session. |
| Aluminum | $ metalmind burn aluminum $ metalmind wipe | Wipe install (reversible uninstall). |
| Brass | $ metalmind burn brass $ metalmind stamp | Soother — re-imprint metalmind managed files (upgrade in place). |
| Forge | $ metalmind forge create <g> $ metalmind group create <g> | Define a cross-repo group. |
| Forge | $ metalmind forge add <g> <r> $ metalmind group add <g> <r> | Add a repo to the group. |
| Forge | $ metalmind forge capture-spec <r> <url> $ metalmind group capture-spec <r> <url> | Seed the OpenAPI shelf for cross-repo route edges. |
| Forge | $ metalmind burn bronze "<q>" --forge <g> $ metalmind graph "<q>" --group <g> | Query across every repo in the group (--include-literals for URL-literal fallback). |
| Scribe | $ metalmind scribe <verb> $ metalmind note <verb> | Vault CRUD — create · update · patch · delete · archive · rename · list · show. |
| Release | $ metalmind release-check $ metalmind release-check | Preflight before tagging — working tree, branch, version sync, tests, build, stamped block. |
| Seeker | $ metalmind pulse $ metalmind doctor | Pulse-check the install — prereqs, config, MCP state. |
Both spellings always work at the CLI. Use the Scadrial / Classic toggle in the nav to re-spell the page.
Install flow
A single metalmind init drives the whole install — and every step is
reversible via metalmind uninstall, which never touches your notes.
Scroll the rail below to trace what happens.
-
Prereqs, detected
Claude Code, Docker, Python 3.11+, uv, git — each checked with a per-failure remediation. Failing prereqs halt the wizard with a concrete fix.
◆ Claude Code 2.1.114 ◆ Docker reachable ◆ Python 3.11+ via python3.12 ◆ uv 0.11.7 ◆ git 2.53.0 -
Vault scaffold
Picks or creates your Obsidian vault. Drops in Work / Personal / Learnings / Daily / Inbox / Archive / Memory, stamps a CLAUDE.md that teaches Claude to recall via CLI — not MCP tools.
◇ Setting up vault ◆ Vault at ~/Knowledge created: Work, Personal, Learnings, Daily, Inbox, Archive, Memory -
Engines installed
Three Python tools land on PATH via uv — Serena (LSP navigation), graphify (code graph), vault-rag (recall server + watcher + indexer + doctor). Mirror of how you install anything else.
◇ Installing Serena → uv tool install serena-agent ◇ Installing graphify → uv tool install graphifyy ◇ Installing vault-rag → uv tool install metalmind-vault-rag -
Local stack
Qdrant + Ollama start as Docker containers (metalmind-qdrant, metalmind-ollama). nomic-embed-text pulls once. All embeddings stay on your machine.
◇ Starting Docker stack (Qdrant + Ollama) ◆ stack at ~/Knowledge/.metalmind-stack nomic-embed-text pulled -
Services, hook & routing
Auto-reindex watcher runs as a background service — launchd on macOS, systemd --user on Linux. MCP registers Serena only; vault recall is a CLI call (no schema tokens). A SessionStart hook injects a memory-available reminder so fresh Claude sessions discover the vault without prompting. Optional: disable native auto-memory and route all memory to the vault.
◇ Installing watcher service ◆ wrote com.metalmind.vault-indexer.plist ◇ Installing SessionStart hook ◆ registered in settings.json ◇ Applying memory routing ◆ disabled native auto-memory -
Ready
metalmind pulse verifies the whole chain end-to-end. metalmind uninstall rolls everything back — watcher, containers, MCP entries, settings, aliases — without ever touching your notes.
$ metalmind pulse ◇ Prerequisites ◇ Config ● flavor: scadrial ● vaultPath: ~/Knowledge ● mcp: serena, graphify └ All systems nominal.
Under the metalmind Under the hood
One verb, one job. Each engine is swappable — so if a backend gets replaced later, your muscle memory doesn't move. Your notes, embeddings, and code graphs never leave your machine.
~/Knowledge/. Qdrant + Ollama (nomic-embed-text)
embed locally. Incremental watcher re-embeds only changed files — no empty-window
queries during reindex.
INFERRED_NAME / INFERRED_ROUTE provenance.