Auto-memory for LLM agents — it decides what mattered and keeps it, so you don't have to. A self-pruning, human-memory-modeled knowledge context graph.
🧠 Self-curating, navigable, context-budget-aware agent memory that judges your session for what's worth keeping — with no vector database, no embedding pipeline, and no server. Just Markdown in a git repo. Works as a Claude Code plugin.
Mnemex (from Mnemosyne, the personification of memory, + the engineering suffix -ex) is a specification and a Claude Code plugin for capturing the durable knowledge an agent produces — the what (domain facts) and the how (the patterns and review decisions that govern good work in a domain) — into a plain-Markdown graph that lives in a git repository, organizes itself into human-like memory tiers (🔥 hot / 🌤️ warm / ❄️ cold), and forgets what stops being useful while protecting what is structurally important.
It is designed to give agents long-term, navigable, context-budget-aware memory without a vector database, without an embedding pipeline, and without a server. Routing is structural (folder + index traversal), decay is lazy (computed, never swept), and every mutation is a reviewable git commit.
Everything starts at the OpenMnemex Console — a local web app that opens in your browser:
uvx openmnemex # runs it without installing anything…or install it properly, then run it — two steps, because pip only installs:
pip install openmnemex
openmnemexFrom the Console: create (or open) a graph, then go to Add agents — it detects the coding agents on your machine and connects each with one click. For Claude Code the Console recommends the plugin route instead (richer: auto-capture hooks, the full skill set) and shows you the two commands to run inside Claude Code:
/plugin marketplace add kritird/OpenMnemex # inside Claude Code
/plugin install mnemex@mnemex-marketplaceThen just work: the first read on the empty graph offers to seed it from a repo/docs — or skip
that and it fills episodically as you go. Prefer the terminal? Every step has a CLI equivalent
(openmnemex install --agent <agent> --init-graph --yes) — see Install below and
docs/agent-setup.md; docs/user-journey.md has
the day-to-day loop.
Agents are excellent at producing knowledge inside a session and terrible at keeping it. The two common fixes both have sharp costs:
| ❌ Common fix | 💸 The cost it carries |
|---|---|
| Stuff everything into context | Context bloat, cost, and attention dilution. |
| Embed everything into a vector store | Infrastructure, an embedding pipeline, an index to operate, and opaque retrieval you cannot read or diff. |
Mnemex takes a third path. Knowledge is files. Navigation is the filesystem plus small index files you read in chunks. Relevance is a number you compute on demand from a usage log, modeled on the Ebbinghaus forgetting curve and spaced repetition: things used often stay visible and cheap to reach; things unused drift down the tiers and, eventually, die — unless something still points at them. The result is a knowledge base that behaves like memory rather than a landfill.
flowchart LR
A([🤖 Agent builds<br/>something]) --> B{How to keep<br/>the knowledge?}
B -->|"Stuff context"| C[💸 Bloat + cost]
B -->|"Vector store"| D[🛠️ Infra + opacity]
B -->|"Mnemex"| E[📄 Markdown graph<br/>in git]
E --> F[🔥 Hot · 🌤️ Warm · ❄️ Cold<br/>self-tiering memory]
F --> G([🔮 Future agent<br/>navigates cheaply])
classDef good fill:#0e7a0d,stroke:#0a5,color:#fff;
classDef bad fill:#7a1f1f,stroke:#a33,color:#fff;
class C,D bad;
class E,F,G good;
The full reasoning behind each design choice is in
docs/rationale-and-concepts.md.
You don't consciously decide to memorize everything that happens in a conversation. Your mind quietly judges, in the background, what was significant and what was noise — and keeps the former without you ever asking it to. Mnemex is auto-memory in exactly that sense. You do the work; it watches the session and decides what is worth keeping.
When a session ends, Mnemex looks at what actually happened and asks the questions a person would:
- Is this relevant? — does it generalize beyond this one conversation, or was it throwaway scaffolding?
- Is this significant? — a durable domain fact or a hard-won review decision, versus an incidental detail?
- Is this novel? — something the graph doesn't already know, versus a restatement of what's there?
It captures the knowledge that passes and ignores the rest. Concretely, capture extracts
candidate atoms from the session and scores each one now / later / not-needed — the explicit
keep / defer / forget judgment. The author doesn't curate, tag, or decide what to file away; that
salience call is Mnemex's job, and what survives later rises or decays on its own through the
🔥 hot / 🌤️ warm / ❄️ cold tiers as it gets used or stops being used.
And just like your own memory, being frequently recalled is not the same as being still true. Mnemex
tracks that too, on a separate axis: every fact carries a verified clock, and when it hasn't been
re-confirmed within a horizon you set (freshness_ttl_days), it's flagged ⏳ stale the next time it's
read — even if it's hot — so the agent re-checks it against the source instead of confidently repeating
something outdated. Confirm it's unchanged and the clock resets for one cheap stamp; find it's wrong and
the correction flows back in through capture. (Full model:
docs/freshness-and-revalidation.md.)
The author doesn't worry about any of this. You build; Mnemex remembers what mattered — and flags what may have gone stale. 🧭
The judgment is reviewable, not a black box: capture stages locally and you can inspect or un-stage anything (
mnx-status,mnx-capture --drop) before a deliberatemnx-promotecommits it to the shared graph. Automatic, but never unaccountable.
A knowledge base is only worth having if reading it is cheap. The two usual approaches quietly tax every single query: stuffing prior knowledge into the prompt pays for the whole pile on every turn, and vector-RAG pastes the top-k retrieved chunks into context each time you ask. Both get more expensive as the corpus grows.
Mnemex is architected the other way: tier is literally read cost, so the tokens a read spends scale with the path you take, not the size of the graph. You navigate by reading tiny index heads and open only the handful of node bodies you actually commit to.
| 🎯 Mechanism | 🪙 Why it spends fewer tokens |
|---|---|
| 🧭 Route, don't retrieve | You read one-line index heads to pick a path (org → team → cluster). Nothing is pasted into context on spec. |
| 🔥 Hot = top-K, chunk 1 | The routing head is capacity-bounded — it stays small even in a huge graph, so the baseline read is bounded regardless of node count. |
| 📚 Chunked tier reads, stop early | Read Hot first; it's usually enough. Warm/Cold only on demand. You rarely load a whole index, never the whole graph. |
| 🏷️ Match on denormalized summaries | Each index row carries the node's summary+aliases, so you match without opening a single node body. |
| 🔎 Expand only on commit | Load only the bodies you'll actually use, within a per-hop token budget — beam search, not "load every neighbor". |
| 🗑️ Self-pruning | Decay + death keep the routing surface small over time — no landfill of dead knowledge to page through. |
| ⏳ Trust the fresh, re-check only the stale | A verified fact is used as-is; you don't re-derive known knowledge from scratch — only a stale atom triggers a re-check. |
💡 The payoff: a read is a few small index-head reads plus only the node bodies you commit to — not the corpus, not a wall of retrieved chunks. Retrieval stays cheap as the graph grows into the thousands of nodes, which is exactly where naive context-stuffing and RAG get most expensive.
your-knowledge-repo/ ← a normal git repo you point Mnemex at
index.md ← org router (which teams exist)
mnemex.config.md ← your tunable parameters (half-life, budgets, cadence …)
.mnemex/ ← protocol state (locks, high-water marks, version stamps)
team-payments/
index.md ← team router (which domains) + HOT / WARM / COLD sections
registry.md ← append-only usage log (the write buffer)
cross-links.md ← GENERATED: inter-cluster edges within this team
settlement/
index.md ← domain sub-index (chunked: routing head, then node table)
registry.md
iso8583-field124.md ← a NODE (pure knowledge; no bookkeeping inside)
ledger-routing.md
pat-settlement-recon.md ← a PATTERN node (a "how", with a trigger)
flowchart TD
subgraph TRUTH["🟢 TRUTH — authored by the LLM"]
N1[📄 Node<br/>iso8583-field124]
N2[📄 Node<br/>ledger-routing]
P1[🧭 Pattern<br/>pat-settlement-recon]
end
subgraph DERIVED["🔵 DERIVED — generated by code"]
IDX[(🗂️ index.md<br/>HOT / WARM / COLD)]
XL[(🔗 cross-links.md)]
end
subgraph TELEMETRY["🟠 TELEMETRY — append-only"]
REG[(📝 registry.md<br/>usage stamps)]
end
N1 -- routes-through --> N2
P1 -- governs --> N1
N1 & N2 & P1 -. regenerates .-> IDX
N1 & N2 & P1 -. boundary edges .-> XL
REG -. folded at gc .-> IDX
classDef truth fill:#0e7a0d,stroke:#0a5,color:#fff;
classDef derived fill:#14507a,stroke:#39c,color:#fff;
classDef tel fill:#7a4a0d,stroke:#d90,color:#fff;
class N1,N2,P1 truth;
class IDX,XL derived;
class REG tel;
Three kinds of file, three jobs (this separation is the core of the design):
| File | Holds | Mutated when |
|---|---|---|
📄 Node (*.md) |
Pure knowledge: summary, body, edges, provenance. | Only on author / re-author / supersede / death / revalidation (verified). |
🗂️ Index (index.md) |
Derived navigation + materialized memory state (strength, tier). | Only by the maintenance pass (and write-apply). |
📝 Registry (registry.md) |
Append-only usage stamps. | Appended on confirmed use; truncated only by checkpointed compaction. |
Four of Mnemex's skills are memory operations, each fronted by a slash command. They map to the verbs of
a memory system (two more skills, mnx-init and mnx-status, handle setup and status — see below).
Knowledge writing is split capture / promote — the git commit vs git push/PR of memory.
| 🎛️ Command | Skill | What it does | Mutates? |
|---|---|---|---|
🔍 /mnemex:mnx-read |
mnx-read |
Route → read tiered indexes in chunks → overlay local staged atoms → expand only needed nodes → flag stale atoms for revalidation → emit a usage manifest → append stamps for nodes actually used. | Registry append only (pure w.r.t. knowledge). |
✍️ /mnemex:mnx-capture |
mnx-capture |
Capture the current session (artifact + human review points) → extract atoms → score each now/later/not-needed → stage locally with self-sufficient provenance. Cheap, local, no lock. Also curates staging: --drop <id> / --discard-all un-stage (review via mnx-status) — the local un-stage and the hard-cap escape valve. |
No — writes only the local staging tier. |
🚀 /mnemex:mnx-promote |
mnx-promote |
The deliberate merge: flush stamps → reconcile + merge staged atoms (clean-context sub-agent, HITL on contradictions) → consolidate the post-merge graph (decay/re-tier/death/edge-hygiene/budget) → doctor → push → clear staging. If a push fails after commit, --retry-push lands the existing commit (never re-merges). |
Yes — gated, atomic, one commit. |
🩺 /mnemex:mnx-doctor |
mnx-doctor |
The validator: checks every invariant (edge targets exist, index matches nodes, denormalized copies are fresh, reverse map consistent, no dangling edges) and can self-heal derived files. | Repair mode only. |
The maintenance pass (mnx-consolidate) is internal — the back half of mnx-promote, with no
standalone slash command.
You don't start from an empty graph. Point Mnemex at a repo you already have and it builds the memory for you:
/mnemex:mnx-ingest github.com/acme/payments-service # or a local pathmnx-ingest reads an entire code or documentation repository — no live session needed — and turns years
of accumulated docs, ADRs, API contracts, and code comments into a live, connected knowledge graph. It does
not dump the repo into a vector store. It distills: an LLM mines each file for the durable facts
and decisions worth keeping, collapses the same fact stated five different ways into one well-sourced
node (entity resolution), and wires the [[wiki-links]] between them — so what lands is distilled
memory, not a RAG index over your source.
And it stays honest at scale:
- Two gates, not a thousand. Approve the scope + routing map once up front, then a single bulk summary at the end — never per-atom review. A monorepo is one decision, not ten thousand.
- Re-runnable and idempotent. Run it again after the repo changes and it imports only the diff; a deleted source file surfaces as an orphan candidate for you to judge — never silent auto-death.
- Safe by construction. Ingest only stages (promote stays the sole writer), never reads secrets, and never mutates the source.
- Higher recall for free. A shared gleaning pass ("what did I miss?") lifts extraction completeness — and it improves ordinary session capture too.
Everything downstream — reconcile, merge, the wiki mesh, consolidate, doctor, push — is the same pipeline
your daily captures already flow through. Full model: docs/corpus-ingestion.md.
flowchart LR
R[🔍 mnx-read<br/><i>recall</i>] -.->|append stamps| REG[(📝 registry)]
C[✍️ mnx-capture<br/><i>stage locally</i>] -->|atoms| STG[(📥 staging tier)]
STG -->|reconcile + merge| P[🚀 mnx-promote<br/><i>commit + push</i>]
REG -->|flush| P
P -->|consolidate + commit| G[(🗃️ shared graph)]
G -->|validate / heal| D[🩺 mnx-doctor]
D --> G
classDef op fill:#4b2e83,stroke:#a98ce0,color:#fff;
classDef store fill:#14507a,stroke:#39c,color:#fff;
class R,C,P,D op;
class REG,STG,G store;
The OpenMnemex Console is the human side of Mnemex: agents write the graph, the Console is
where you start, look, and manage. One command opens it; from there you create or open graphs
and hook up your agents (the Add agents screen) — and it draws every graph on your machine as
a living picture: node size and teal depth show how heavily each atom is used, amber/red
rings show what's due or overdue for a re-check, hollow purple dots are staged captures, dashed
ghosts are [[links]] nobody has written yet.
uvx openmnemex # or, if you'd rather install it: pip install openmnemexClick any node for its mesh and full rendered atom; search the graph; open the revalidation
queue (what needs re-checking, soonest first); toggle the health overlay (doctor findings
pinned on the canvas); or drag the time scrubber to watch how the graph would age over the
next months. Every number is computed by the same engine the agents use — and over knowledge it's
view-only forever: browsing never changes a file (the Console's only writes are creating a
new empty graph and, on your click, an agent's own connection config). Full tour:
docs/console.md.
Two further skills round out the surface. /mnemex:mnx-init is the setup/preflight: it binds a
project (or your user account) to a graph repo — creating and scaffolding a new graph, or pointing at an
existing one — and is what every other command resolves first. For a git-remote graph it runs a
read-only reachability/auth pre-flight before binding and, on failure, offers a no-auth local-folder
fallback. /mnemex:mnx-status is a read-only at-a-glance status: what graph is bound, its kind,
node/tier counts per team, pending usage stamps, last gc, and a health summary. See
docs/binding-and-graph-sync.md.
Phase-by-phase breakdowns are in
docs/skills-commands-hooks.md and
docs/maintenance-pass-algorithm.md.
Start with the Console — it guides everything else:
# 1. Open the OpenMnemex Console (needs Python 3.9+). Either run it without
# installing…
uvx openmnemex
# …or install it once, then run it (two steps — `pip` only installs):
pip install openmnemex
openmnemex
# 2. In the Console: create your first graph (or open an existing folder).
# 3. In the Console → "Add agents": one click connects each detected agent.
# For Claude Code it recommends the plugin (auto-capture hooks, skills) and
# shows these two commands to run inside Claude Code:
/plugin marketplace add kritird/OpenMnemex
/plugin install mnemex@mnemex-marketplaceTip
Requirements: Python 3.9+. pip install openmnemex brings everything the Console and engine
need (PyYAML plus FastAPI/uvicorn for the Console — the
engine itself runs on the standard library + PyYAML alone). If something is missing, the Mnemex
commands report it and tell you what to install rather than failing cryptically.
A complete walkthrough — from install to daily usage, with the hooks that fire automatically — is in
docs/user-journey.md. 🧭
Everything the Console's Add agents screen does is also one command — it drives the exact same
installer. Claude Code gets the full plugin experience above; every other MCP-capable agent gets
the same read/capture/promote loop over the stdio MCP server. For step-by-step, per-agent
instructions (install → what changed → how to verify → which tier to expect), see
docs/agent-setup.md.
# 60-second start: create a local-folder graph, bind it, and pin it into the entry — zero prompts.
uvx openmnemex install --agent <agent> --init-graph --yes
# …or wire up the server against a graph you already have:
uvx openmnemex install --agent <agent> [--project|--user] [--pin-graph]--init-graph is the no-decisions path: it proposes a plain local folder under your mnemex home
(no git remote, no credentials — it always succeeds), scaffolds it doctor-clean, binds it as your user
default, and pins that graph into the agent's MCP entry. Nothing to choose, no dead end on the first
read. --pin-graph without a graph now errors clearly instead of silently writing an unpinned
entry.
--agent |
Config written | Tier |
|---|---|---|
opencode |
opencode.json + AGENTS.md block + .opencode/plugin/mnemex.ts (auto-capture hook) |
Full |
gemini-cli |
.gemini/settings.json / ~/.gemini/settings.json + GEMINI.md block |
Assisted |
codex |
.codex/config.toml / ~/.codex/config.toml + AGENTS.md block |
Assisted |
copilot |
VS Code .vscode/mcp.json (project scope only — no static user-scope file) |
Assisted |
cursor |
.cursor/mcp.json + .cursor/rules/mnemex.mdc |
Assisted |
claude-code |
.mcp.json (project) or claude mcp add (user) — an alternative to the plugin above |
Full |
"Assisted" tier means the host has to be told the read/capture/promote judgment procedure via the
instruction file (AGENTS.md/GEMINI.md/rules block) rather than getting it as a Claude Code skill —
see LIMITATIONS.md for exactly what differs. --pin-graph bakes the current
directory's resolved graph path into the server config so the agent doesn't need to cd there first;
add --dry-run to preview the diff or --check to verify an existing install; --uninstall removes
exactly the Mnemex entry/block and leaves everything else in the file untouched.
Note
openmnemex is on PyPI — uvx openmnemex and
pip install openmnemex just work. To run the bleeding edge straight from this repo instead:
uvx --from git+https://github.com/kritird/OpenMnemex openmnemex.
JS-native users can skip uv/pip entirely once published: npx openmnemex install --agent <agent> ... and npx openmnemex-mcp are thin shims that exec the same PyPI package underneath
(integrations/npm/, the npm side is not yet published).
The documents in docs/ are written to be self-explanatory and read in order. Every acronym
is expanded on first use and collected in the appendix.
| Document | What it covers |
|---|---|
overview.md |
The thesis and the design goals, in brief. |
rationale-and-concepts.md |
Every core concept and why it is shaped that way. |
architecture.md |
The three-layer model, memory tiers, lazy-decay math, and budget = ranking = forgetting. |
data-model-and-schemas.md |
Exact file formats for node, index, registry, cross-links, config, and staged atom. |
skills-commands-hooks.md |
The skills, their command surfaces, and the hooks that do what skills cannot. |
maintenance-pass-algorithm.md |
The snapshot-then-apply algorithm in full, with ordering guarantees. |
script-contracts.md |
Deterministic helper contracts (signatures, I/O, invariants). |
configuration.md |
The config schema, derived half-life, and config-version re-normalization. |
invariants-and-failure-modes.md |
The validator invariant list and the failure-mode register with mitigations. |
appendix-glossary-acronyms.md |
Glossary, acronym expansions, parameter reference, FAQ, references. |
binding-and-graph-sync.md |
How an author in any repo binds to a separate knowledge-graph repo. |
staging-and-promotion.md |
The capture / promote split: staging tier, atom schema, budgets, read overlay, atomic promote. |
link-reconciliation.md |
🕸️ The wiki mesh (Step 2b): inline [[wiki-links]], phonebook resolution, red-links + backfill. |
corpus-ingestion.md |
🏗️ Bootstrapping the graph from an existing repo: mnx-ingest as a source adapter — walk → distill → wikify → bulk promote; gleaning + entity resolution. |
user-journey.md |
🧭 End-to-end journey: install → bind → daily read/capture/promote, with auto-hook touchpoints. |
multi-graph-and-team-routing.md |
🔗 Working across many graphs, teams & orgs: which-graph vs which-team, per-graph staging, worked example. |
freshness-and-revalidation.md |
⏳ The freshness axis: verified clock, stale_after, read-time refresh cue, volatility, timeless-never-dies. |
console.md |
🖥️ The OpenMnemex Console (uvx openmnemex): the starting point — add agents, canvas encoding, revalidation queue, health overlay, time scrubber. |
See also: FEATURES.md (feature showcase).
MIT. See LICENSE.
