Survey of concept-level and temporal agent-memory systems — the layer holding architecture decisions, gotchas and design rationale, and the question of how it stays fresh as code changes. One of four source surveys behind knowledge-graph-research-2026-09-07.

For Agents

Survey date: 2026-09-07. Star counts and push dates were pulled live from the GitHub API on that date and are point-in-time facts. Verdict carried into the synthesis: Basic Memory for the typed-edge index over the existing vault; trace-mcp worth trialling for its decision-verification layer, base tier only. Kuzu was archived on 2025-10-10 after the Apple acquisition. The maintained fork is LadybugDB. Graphiti consequently deprecated its embedded Kuzu backend. Do not adopt Kuzu on the strength of any older recommendation. mem0 removed graph memory from open source in v3 (April 2026). claude-mem is not in use here and has been disabled since 2026-03-15. It is a flat session log with per-session LLM compression, not a graph. The synthesis recommends removing it. Graphiti is the only true bi-temporal model surveyed (valid_at / invalid_at), but it needs FalkorDB or Neo4j plus several LLM calls per write. Kept verbatim from the source report apart from this header and the ## Related footer.

Date of research: 2026-09-07. All star counts and push dates pulled live from the GitHub API on that date.

Target use case: a solo developer who wants architecture decisions, gotchas, design rationale, project state and debugging learnings to (a) stay fresh as code and decisions change, (b) be traversable by Claude Code over MCP, (c) link to code-level entities, (d) remain human-readable/editable in an Obsidian markdown vault, (e) be shared across two Macs over Tailscale.

Existing stack: Obsidian vault, claude-mem plugin, AgentOps .agents/ learnings, self-hosted FastMCP telep-kb on a Tailscale server.


0. Headline findings (read this first)

Four things materially changed the landscape in the last 12 months and invalidate most older comparison articles:

  1. Kuzu is dead. The embedded graph database was archived 2025-10-10 after Kùzu Inc. was acquired by Apple. Any 2025-era advice to “parse markdown into Kuzu” is now advice to build on an abandoned dependency. Two forks exist: LadybugDB (active — 1,714★, pushed 2026-09-07, MIT, 20+ releases, 80+ contributors) and Bighorn by Kineviz (134★, effectively a rename — one README commit since October 2025).

  2. mem0 deleted graph memory from open source. The OSS v3 rewrite (PR #4805, merged ~2026-04-14) removed the enable_graph flag, the graph_store config block, and all external graph drivers (Neo4j, Memgraph, Kuzu, Apache AGE, Neptune) — roughly 4,000 lines. The migration doc says plainly: “It is not being replaced by an OSS equivalent.” The relations field is no longer returned. Graph memory is now a paid Mem0 Platform feature. Replacement in OSS is spaCy entity linking that boosts ranking but exposes no traversable typed edges.

  3. Graphiti deprecated its embedded option. Kuzu support “still ships but emits a DeprecationWarning” and will be removed. FalkorDB is now the default backend. There is a falkordblite embedded extra (Python 3.12+), but the zero-ops story is weaker than it was.

  4. A new category emerged: code+notes in one graph. trace-mcp (created 2026-04-03) indexes a codebase and an Obsidian/Logseq markdown vault into the same SQLite graph, with decision records carrying valid_from/valid_until and linked to stable symbol IDs. This is the closest thing to the exact architecture described in the brief. It is also young and single-maintainer.


1. Comparison table

Legend: Bi-temporal = facts carry validity windows AND ingestion timestamps, with invalidation rather than overwrite. Embedded = no server process to run.

SystemLast pushLicenseData modelUpdate handlingStorageMCP for Claude CodeMarkdown vaultCode entitiesMulti-machineLLM per write?
Graphiti (getzep)30,6572026-09-06Apache-2.0Episodes → typed entity nodes + typed edges; communities; true bi-temporal (valid_at, invalid_at, created_at, expired_at)LLM detects conflict, writes invalid_at on old edge, keeps it. Entity resolution via MinHash/LSH + LLM fallback. Provenance via get_episode_entitiesNeo4j 5.26, FalkorDB 1.1.2 (default), Neptune+OpenSearch; Kuzu deprecated; falkordblite embedded (py3.12+)Official server in-repo, HTTP :8000/mcp/. Tools: add_memory, add_triplet, search_nodes, search_memory_facts (filters on valid_at/invalid_at), build_communities, get_episode_entities, summarize_sagaNo built-in ingester. No obsidian string anywhere in repoOnly as generic entities; no stable code IDsYes — HTTP server over TailscaleYes, heavily. Multiple calls per episode (node extract → dedup → edge extract → per-edge temporal resolution). ~300–1500ms extraction; ~50 episodes/min at default SEMAPHORE_LIMIT=10
Zep (managed Graphiti)4,890 (examples repo)2026-09-03Apache-2.0 (client)Same as GraphitiSameProprietary “Konig” backendCloud APINoNoYes (SaaS)Yes, priced in
cognee30,5452026-09-07Apache-2.0add → cognify → memify pipeline; ontology-grounded entities/relations; auto-generated + RDF/OWL ontologies; coding-rule nodesmemify prunes stale nodes, reweights edges, consolidates entities. Incremental load + “better conflict resolution” claimed in 1.4/1.5 notes. No documented per-fact validity windowsGraph: Ladybug (embedded, replaced Kuzu), Neo4j, Neptune, Turso, Postgres (demo). Vector: LanceDB, pgvector, Turso. Fully local possibleOfficial cognee-mcp, ~14 tools: cognify, codify, search (GRAPH_COMPLETION/CODE/CYPHER/…), remember, recall, forget, prune, cognee_add_developer_rules. stdio/SSE/HTTP30+ connectors incl. generic docs; no first-class wikilink/frontmatter parserYes — codify builds a real code graph (functions, classes, deps) via AST chunkingEmbedded engine is file-locked, single-process. Docs: “not suitable for concurrent use from different agents or processes. For multi-agent scenarios, use Neo4j”Yes — LLM + embeddings on every cognify
mem0 (OSS v3)64,8212026-09-04Apache-2.0Flat memories + spaCy entity linking into {collection}_entities; hub-and-spoke, no typed edgesADD/UPDATE/DELETE decided by LLM; overwrite semantics, no historyQdrant/pgvector etc.OpenMemory MCP (SSE, needs Docker+Postgres+Qdrant); mem0-mcp archivedNoNoYes if self-hosted serverYes (single-pass since v2 SDK)
Basic Memory3,8782026-09-06AGPL-3.0Markdown file = Entity. ## Observations bullets with [category] tags; ## Relations bullets as - relation_type [[Target]]. Frontmatter: title, type, permalink, tagsOverwrite/edit semantics. No validity windows, no invalidation, no fact versioning. write_note guards accidental overwrite; basic-memory doctor checks file↔DB consistencyMarkdown on disk + local SQLite index. Postgres + optional Milvus also supportedOfficial, 17+ tools: write_note, read_note, edit_note, move_note, delete_note, search_notes, recent_activity, build_context (traverses memory://), schema_infer/validate/diff, project mgmtNative and bidirectional — this is its whole thesis. Human edits in Obsidian are picked up; agent writes land as notes a human readsNoLocal install has no built-in sync (docs suggest Git/Syncthing). Cloud is $15/mo, rclone-basedNo. Pure parse + index. Optional embeddings only
LightRAG39,4532026-09-07MITEntities + relations with accumulated descriptions; dual-level retrievalIncremental insert merges by exact entity name string match only. Descriptions accumulate/re-summarize rather than supersede. No temporal invalidation. Manual merge_entities API exists4 pluggable layers; defaults NetworkX + NanoVectorDB (files); prod: Postgres/Mongo/OpenSearch, Neo4j/Memgraph, Milvus/Qdrant/FaissNo official MCP serverNoNoServer-mode yesYes per insert
HippoRAG 23,9832026-09-03MITOpenIE triples + passage nodes, Personalized PageRank retrievalAppend-only corpus; no fact invalidationLocal files, igraphNo official MCPNoNoNoYes (indexing)
nano-graphrag3,9832026-01-27 (stale ~7mo)MITGraphRAG cloneSame as GraphRAGLocalNoNoNoNoYes
Microsoft GraphRAG35,8722026-09-07MITEntities, relationships, communities + community summariesgraphrag update / --method standard-update since v0.4. Append-only by design — the original issue explicitly scoped out removal and editing. No per-fact temporal validityParquet files + configurable vector storeNo official MCPNoNoFile-basedYes, expensive (community summarization)
Letta24,6392026-08-23Apache-2.0Memory blocks (core/recall/archival); agent self-edits via tools; sleep-time “dreaming” agentsAgent rewrites blocks — destructive, no history. Archival is append-only vector passagesPostgres + FastAPI serverLetta consumes MCP tools; it is a runtime, not a memory MCP serverNoNoYes (server)Yes — it is the agent
claude-mem93,372 ⚠️2026-09-07Apache-2.0Sessions → AI-compressed observations + summaries. Flat, not a graph. No entities, no edgesAppend-only log; no contradiction handling, no invalidationSQLite (FTS5) + Chroma vectors, ~/.claude-mem/Yes — thin MCP wrapper over local HTTP worker: search, timeline, get_observationsNoOnly as free text in observationsLocal files; no sync storyYes on every session — compression via Claude SDK/Gemini/OpenRouter
Anthropic reference memory server(in modelcontextprotocol/servers, 90,127★)2026-09-03MITEntities (name, type, observations[]) + directed relations. Untyped-ish, no timestamps at allAdd/delete only. No dedupe, no invalidation, no provenanceSingle JSONL fileYes, official. create_entities, create_relations, add_observations, delete_*, read_graph, search_nodes, open_nodesNoNoOne file — syncable via git/SyncthingNo
trace-mcp1692026-09-07MITCode symbols (path::Symbol#kind) + framework-aware typed edges; notes as note:<basename> symbols, headings as sections, [[wikilinks]]/![[embeds]] as edges, frontmatter/#tags as metadata. Decisions table with valid_from, valid_until, symbol_id, file_path, confidence, session_id, git_branch, sourceinvalidate_decision sets superseded, row stays for historical queries. as_of and include_invalidated queries. No automatic contradiction detection. Provenance via session_idSQLite WAL + FTS5, local ONNX embeddings. ~/.trace/decisions.dbYes, 181 tools. Relevant: query_decisions, add_decision, mine_sessions, get_decision_timeline, get_change_impact, plan_turn, get_wake_up, search_sessions, find_usagesYes — Obsidian/Logseq/plain MD as a peer domain in the same graphYes — this is its origin. 81 languages, 87 frameworks, optional LSP enrichmentDB in $HOME, not the repo. No documented sync/exportNo for mining (8 regex patterns, 0 LLM calls); embeddings local ONNX; LLM summaries optional
codebase-memory-mcp42,5162026-09-07MITTree-sitter graph: functions, classes, call chains, routes. ADRs via manage_adr as a flat markdown doc, not symbol-linkedADR section splicing preserves surrounding bytes. No temporal modelSingle static binary, embeddedYes, 14 typed toolsNoYes (158 languages claimed)LocalNo
Khoj37,1672026-08-02AGPL-3.0Documents + embeddings; not a concept graphRe-sync/reindexPostgres + vectorsObsidian plugin, not an MCP graphYes — syncs a vault (periodic + force sync)NoYes (server)Embeddings
txtai12,9312026-09-04Apache-2.0Embeddings DB unioned with a semantic graph (auto edges from vectors, manual/LLM edges since 7.0); openCypher-ish traversalYou own it — it is a library, not a memory policyLocal files, Neo4j optionalNo first-class memory MCPNoNoFilesOnly if you use LLM extraction
Honcho7,0452026-09-05AGPL-3.0Peers + sessions + derived “conclusions”; deriver + “dreaming” background reasoningBackground re-derivation updates representations. Not a fact-level temporal graphPostgres (FTS + pgvector/turbopuffer/lancedb) + RedisNot a Claude Code graph MCPNoNoYes (server)Yes, plus a per-query LLM bill (0.50/query by tier)
Supermemory29,2532026-09-02MIT”Memory graph” with decay, recency bias, forgetting; user profilesFacts update/decay; details not openCloud-first; self-host is enterprise/Cloudflare Workers; new local binary advertisedPlugins for Claude Code advertisedNoNoCloudServer-side
Memori (MemoriLabs)16,4672026-09-03NOASSERTION ⚠️Entities, facts, relationships in normalized SQL/MongoDBSchema + constraints + history claimed; no public temporal-edge specYour existing SQL/MongoSDK-first, wraps LLM clientNoNoYes (your DB)Yes (3-agent pipeline)
A-MEM1,1672025-12-12 (stale ~9mo)MITZettelkasten notes with keywords/tags; LLM-generated links; memory evolution updates neighborsNeighbor context/tags rewritten — destructive, no historyChromaDBNoNoNoNoYes — 2 LLM calls per memory event

⚠️ claude-mem star caveat: 93,372 stars against only 299 watchers and 8,200 forks. A star:watcher ratio of ~312:1 is far outside the normal range (~30:1) for repos of this size. Treat the star count as a weak signal of adoption. Functionally it is a flat session log, not a knowledge graph.

⚠️ Memori license: GitHub reports NOASSERTION, and the repo redirects GibsonAI/memoriMemoriLabs/Memori. Verify licensing before depending on it.


2. Detailed notes on the systems that matter for this use case

2.1 Graphiti — the only real bi-temporal implementation

Graphiti is the only surveyed system that implements the full bi-temporal model as a first-class, queryable feature rather than a marketing phrase.

Data model. Episodes (text/JSON/message) are the ingestion unit. An LLM extracts entity nodes and typed edges. Each edge carries four timestamps:

  • valid_at / invalid_at — when the fact was true in the world
  • created_at / expired_at — when the system learned and un-learned it

Update handling. On ingest, Graphiti runs semantic + keyword + graph search to find candidate conflicts. When new knowledge contradicts an existing edge, it writes invalid_at on the old edge rather than deleting it. search_memory_facts accepts valid_at/invalid_at date-range filters, so “what is true now” and “what was true in March” are both answerable. get_episode_entities traces which entities and facts a given episode produced — real provenance.

Known weakness (important, from the issue tracker). Issue #1489 documents that add_episode accepts reference_time and plumbs it correctly, but the LLM frequently ignores it and stamps extracted edges with today’s date. The root cause is contradictory instructions in graphiti_core/prompts/extract_edges.py. For a backfill of an existing Obsidian vault, this means the temporal data would be largely wrong unless the prompt is patched.

Cost. This is the expensive end of the spectrum. Every episode fires several LLM calls plus embeddings. Reported figures: 300–1500ms for extraction alone, ~50 episodes/min at default concurrency. Users have opened issues (#1193, #1299) asking for a way to ingest pre-extracted facts and use Graphiti purely as a temporal engine; add_triplet / add_fact_triple is the partial answer.

Storage reality check. Neo4j (JVM, heavy) or FalkorDB (Redis-based, lighter, now default) or Neptune (AWS). The falkordblite embedded extra needs Python 3.12+. Kuzu is deprecated. There is no truly zero-ops embedded path that is also on the supported roadmap.

Multi-machine. Good. The MCP server speaks HTTP at :8000/mcp/, so pointing both Macs at one Tailscale host works. Note the community warning: use "type": "http" in Claude Code config, not "url", which triggers a failing OAuth handshake. Also use group_id per project rather than the default "main".

Obsidian. Nothing built in. A code search for obsidian in the repo returns zero hits. You would write the ingester.

2.2 Basic Memory — the markdown-native option

The design is the inverse of Graphiti’s: markdown files are the source of truth, SQLite is a derived index, and the graph is expressed in the notes.

The grammar is deliberately tiny: every file is an Entity; ## Observations bullets carry [category] tags; ## Relations bullets are - relation_type [[Target]]. That means a human writing normal Obsidian notes with wikilinks is already writing the graph, and the agent writing via write_note produces files a human reads in Obsidian with no conversion step.

What it does not do: there is no temporal model. No valid_from, no invalidation, no fact versioning. An edit_note overwrites. “What is the current auth flow” is answered by whatever the note says now; the history lives in git, not the graph. build_context traverses memory:// links, so multi-hop is possible, but there is no notion of a superseded fact.

Multi-machine: the honest answer from the README is that the local install has no built-in sync and they suggest Git or Syncthing. Cloud is $15/mo. For two Macs with an existing Obsidian vault, git or the vault’s own sync already solves this.

Cost: zero LLM cost on write. This is the cheapest thing in the survey that still produces a traversable graph.

License is AGPL-3.0 — fine for personal use, worth noting if anything ever gets embedded in a distributed product.

2.3 trace-mcp — code and notes in one graph, decisions bound to symbols

Created 2026-04-03, 169★, MIT, single maintainer, pushed daily.

This is the only project found that does all three of: index a codebase into a graph, index an Obsidian vault into the same graph, and attach decision records to stable code symbols with temporal validity.

  • Stable identifiers: src/db/connection.ts::Pool#class for code, note:<basename> for vault notes.
  • Markdown handling: wikilinks and embeds become graph edges; headings become nested sections; frontmatter and #tags become symbol metadata. find_usages on a note gives backlinks; get_change_impact on a note tells you what breaks if you rename it.
  • Decision schema: title, content, type, project_root, service_name, symbol_id, file_path, tags, valid_from, valid_until, git_branch, source (manual/mined/auto), confidence (0–1), review_status, session_id.
  • Supersession: invalidate_decision sets valid_until; the row stays for historical queries. query_decisions supports as_of and include_invalidated.
  • Mining is free: mine_sessions scans Claude Code JSONL transcripts with 8 regex patterns and zero LLM calls, assigning intrinsic confidence 0.70–0.85, boosted 5% for context words like “because” or “alternative”. A review queue (approve_decision/reject_decision) gates what lands.
  • Storage: SQLite WAL + FTS5 with local ONNX embeddings. No API keys, no outbound calls by default. Index db per project; ~/.trace/decisions.db for decisions.
  • Hooks: trace init installs a PreToolUse guard hook that blocks Read/Grep/Glob on source files and redirects to trace-mcp tools.

Skepticism required. The README carries self-run benchmarks (70.5% fewer input tokens over 60 PRs) that are preregistered and documented but not independently replicated. 181 MCP tools is a very large surface for one maintainer. The “Max” install tier patches Claude Code’s system prompt via tweakcc, which is invasive — pick Base or Standard. There is no documented decision-DB sync or export, and the DB lives in $HOME rather than the repo, so the two-Mac story is unsolved out of the box. Automatic contradiction detection between decisions does not exist; you invalidate manually. Nothing re-verifies a decision against the current code when a symbol disappears.

2.4 cognee — the ontology and code-graph option

Strong on breadth: codify builds a genuine code graph (functions, classes, dependencies) with AST chunking, and cognify grounds extraction in an auto-generated or imported RDF/OWL ontology. memify is a post-processing pass that prunes stale nodes, reweights edges by usage, and consolidates entity descriptions. 14 MCP tools including remember/recall/forget.

The blocker for a two-Mac setup: cognee’s embedded engine (Ladybug, the Kuzu fork) uses file-based locking. Their own docs state it is “not suitable for concurrent use from different agents or processes. For multi-agent scenarios, use Neo4j.” So the zero-ops path is single-machine, and the multi-machine path is a Neo4j server.

No documented per-fact validity windows. Freshness is handled by re-running the pipeline and by memify pruning, which is coarser than Graphiti’s edge invalidation.

2.5 What claude-mem actually is

Worth stating plainly because it is already in the stack: claude-mem is not a knowledge graph. It is a session capture system — hooks (SessionStart, UserPromptSubmit, PostToolUse, Stop, SessionEnd) enqueue tool observations, an AI provider compresses them into observations and summaries, and they land in SQLite FTS5 + Chroma. Retrieval is progressive disclosure (search → review index → get_observations). There are no entities, no edges, no contradiction handling.

It answers “what did I do last Tuesday” well. It does not answer “what is the current auth flow, excluding superseded facts”. These are complementary, not competing.

Known costs: issue #618 documents users burning a 5-hour token budget in under 10 messages; issue #707 documents a Chroma process at ~35GB RAM prompting a request for a SQLite-only mode. <private> tags exclude content from storage.


3. Answers to the four questions

(1) Best “temporal truth” story

Graphiti, without close competition. It is the only system where “what is the current auth flow” is a querysearch_memory_facts with an invalid_at filter returns only non-invalidated edges, while the superseded edges remain with closed validity windows for history. Nothing else surveyed lets you ask “what did we believe on 2026-03-15?” and get a correct answer from the graph itself.

Runner-up: trace-mcp, which gives you valid_from/valid_until on decisions plus as_of queries. It is a decision-level rather than fact-level model, and supersession is manual, but it costs nothing to run and it links to code.

Everything else either overwrites (Basic Memory, Letta, mem0, A-MEM), accumulates without superseding (LightRAG, GraphRAG), or has no time dimension at all (the Anthropic reference server).

Caveat on Graphiti: issue #1489 means the extracted valid_at values are frequently wrong on backfill because the LLM ignores reference_time. The temporal machinery is excellent; the temporal data quality depends on a prompt you may have to patch.

(2) Cheapest thing to run on a Claude Code hook every session

Ranked by cost per session:

  1. trace-mcp mine_sessions — zero LLM calls. Regex over the JSONL transcripts Claude Code already writes. Effectively free, runs after the session, can gate results through a review queue. This is the only candidate genuinely cheap enough for an unconditional SessionEnd hook.
  2. Basic Memory write_note — zero LLM cost on the write path (the agent already composed the text as part of its turn). Parsing and indexing are local.
  3. Anthropic reference memory server — zero cost, but the data model is too thin to be worth the tool calls.
  4. claude-mem — one compression pass per session against a paid model. Already in the stack; the token complaints in issue #618 are the known failure mode.
  5. Graphiti add_memory — several LLM calls per episode, 300–1500ms each. Running this on every Stop event is the expensive option. Mitigations: add_episode_bulk for backfill, add_triplet to bypass extraction, a local model via OpenAIGenericClient, or batching to one episode per session rather than per tool call.

A practical hybrid: mine cheaply on every session, and promote only reviewed, high-value facts into an expensive temporal graph on demand.

(3) Markdown as source of truth, or graph as source of truth?

For a human who wants to keep reading and editing Obsidian: markdown as source of truth, with a derived graph index. The reasoning is durability and reversibility. A derived index can be deleted and rebuilt; a graph-of-record cannot be re-derived from notes it has already superseded. It also means the vault survives any of these projects being abandoned — which, given Kuzu in October 2025 and mem0’s graph deletion in April 2026, is not a hypothetical risk.

Projects doing markdown-as-truth (derived index):

  • Basic Memory — markdown on disk is canonical, SQLite is an index, basic-memory doctor reconciles them. Explicitly bidirectional.
  • trace-mcp — the vault is read and indexed; notes stay plain files.
  • AgriciDaniel/claude-obsidian (14,695★, MIT) — the Karpathy “LLM Wiki” pattern: inbox//wiki-ingest → linked markdown pages, /wiki-query read-only, plan-hash guardrails before vault writes.
  • The whole cluster of 2026 “second brain for Claude Code” projects follows this shape: a vault-root CLAUDE.md defines the frontmatter schema and link conventions, an /ingest command writes pages, a /lint command reports orphans, broken wikilinks, missing frontmatter and contradictions.

Projects doing graph-as-truth (markdown rendered out or not at all):

  • Graphiti / Zep — the graph is canonical; there is no markdown rendering at all. You would build the export.
  • cognee — graph is canonical; markdown is an input format.
  • Letta — memory blocks are canonical and agent-owned; humans do not edit them in a text editor.

The honest cost of markdown-as-truth: you give up cheap fact-level invalidation. Markdown has no natural place to record “this sentence stopped being true on 2026-06-01” except frontmatter or an explicit superseded_by link. That is a schema you have to design and a lint rule you have to enforce.

(4) The lightest-weight thing that actually works

Frontmatter-typed links parsed into SQLite — not Kuzu, and not Graphiti.

Three reasons Graphiti-with-an-LLM-extractor is the wrong first move here:

  • The corpus is one developer’s notes, not a conversation firehose. Volume is low; the value is in precision and human-editability, which LLM extraction degrades.
  • The extractor’s temporal output is known to be unreliable on backfill (issue #1489).
  • It requires a running Neo4j or FalkorDB and OpenAI-class structured output on every write.

And Kuzu is simply not an option any more — archived October 2025. If you want an embedded graph database specifically, the live choices are LadybugDB (the maintained Kuzu fork, MIT, 1,714★) or FalkorDB. But for a single developer’s vault, SQLite with a recursive CTE for traversal handles the query load fine, and SQLite is the one dependency that will still be maintained in ten years.

The concrete lightest path, in order of increasing effort:

  1. Adopt Basic Memory pointed at a subfolder of the existing vault. Zero code. It already implements exactly “frontmatter + typed wikilinks parsed into SQLite”, exposes 17 MCP tools including graph traversal, writes notes humans read, and costs nothing per write. Its gap is the temporal model.
  2. Add a frontmatter convention for supersessionstatus: active|superseded, valid_from:, superseded_by: [[note]] — and a lint command. This buys most of the “temporal truth” benefit for the cost of a convention and a script. It is the 80% answer to question (1) at 5% of the cost.
  3. Add trace-mcp for code linkage and free session mining, pointed at both the repo and the vault, so decisions bind to path::Symbol#kind identifiers and surface in impact analysis.
  4. Only then, if fact-level point-in-time queries turn out to be genuinely necessary, layer Graphiti on as a derived store fed from the vault, with the markdown remaining canonical.

4. What to rule out, and why

Ruled outReason
mem0 for graph memoryGraph deleted from OSS in v3 (April 2026), explicitly not replaced, now a paid Platform feature. mem0-mcp archived 2026-03-24.
Anything targeting KuzuArchived 2025-10-10 after the Apple acquisition. Use LadybugDB if an embedded graph is required.
nano-graphragLast push 2026-01-27, ~7 months stale.
A-MEMResearch artifact. Last push 2025-12-12. Memory evolution rewrites neighbor notes destructively — the opposite of what a decision log needs. Superseded in the literature by All-Mem, MAGMA, AdaMEM.
Microsoft GraphRAGAppend-only by explicit design; deletion and in-place edit are out of scope. Community summarization is expensive. Built for static corpora, not evolving decisions.
HippoRAG 2A retrieval benchmark method, not a memory service. No MCP, no update semantics, no persistence story for a personal vault.
LettaIt is a whole agent runtime, not a memory layer you add to Claude Code. Self-editing blocks are destructive with no history. Last release 2026-05-14.
KhojExcellent vault search, but a document/embedding system, not a concept graph. No typed relations to traverse.
Supermemory / Honcho / MemoriCloud-first or server-heavy, oriented to end-user personalization and production agent fleets rather than a developer’s decision log. Honcho charges per query by reasoning tier. Supermemory self-hosting is enterprise-only on Cloudflare Workers. Memori’s license reads NOASSERTION.
Anthropic reference memory serverUntimestamped, no dedupe, no provenance, single JSONL. Fine as a demo; not a system of record.
jacksteamdev/obsidian-mcp-toolsArchived. Use MarkusPfundstein/mcp-obsidian (4,376★) or cyanheads/obsidian-mcp-server (674★) if a plain vault MCP is wanted.
txtai / LightRAGLibraries, not memory systems. LightRAG dedupes by exact string match only and has no temporal model. txtai would require you to build the entire memory policy yourself.

5. Sources