mem-local embeds things and does semantic search, so it would be easy to mistake it for a vector dump with extra polish. It isn’t one. Every record is a typed node with typed edges to other nodes, and retrieval walks that graph as well as ranking by similarity. That structure wasn’t the plan from the start — it came out of a requirement I added partway through the first design conversation, and it survived two fork bases that looked, on paper, like they’d already built it.

Where the requirement came from

The origin conversation started entirely from Claude’s side — what does the model lack. Partway through I added something of my own: I wanted to see connections across projects, track work that spans more than one, hold the kind of shared context no single conversation owns. Claude’s answer named the actual shift: that’s a different way of getting at the data entirely. A retrieval layer gets queried; a knowledge layer gets explored. And exploring connections is a graph question, not a similarity one — similarity finds things worded alike, and worded-alike isn’t the same as connected. Two projects can block each other without sharing a single word in common; no amount of embedding distance will ever surface that.

What made the requirement stick was that it wasn’t just mine. A graph beats a flat store for Claude’s purposes too. Query a flat store and you get whatever mentions a project. Query a graph and you get the project itself plus its decisions, its open questions, its rationale, and what it connects to — the neighbourhood, not just the one matching node. My reason for wanting a graph (exploring my own projects) and Claude’s reason (getting the right context, not just the closest-worded sentence) turned out to be the same reason. Nothing to trade off.

It settled something else too: which artefact the two of us could actually both work from. An embedding means something to the model and nothing to me — I can’t read a vector and tell you if it’s right. A graph with named nodes and typed edges, I can read, correct, and disagree with. That matters because I’m still the one who has to judge whether any of it is actually true.

Two fork bases, checked and rejected

Before any of this got built from scratch, two SQLite-native projects that looked, from the outside, like they’d already solved the hard part got checked against their actual source rather than trusted on their README.

memorygraphMCP was the frontrunner because it advertised bi-temporal memory — the exact piece I was most nervous about getting wrong myself. It fell apart on inspection: the temporal fields lived only on relationships, not on the memories themselves, and “supersession” turned out to just be an in-place UPDATE. Then the real disqualifier — no embeddings anywhere. Its README treated that as a feature: “graph traversal without embeddings,” stated outright as the design stance. A reasonable choice for them. Fatal for me, since hybrid retrieval is the whole point here — using it would have meant tearing out its retrieval model to bolt on the one thing it was built to avoid. The full write-up is archived at verification-pass-fork-base-fails.

Basic Memory failed for a completely different reason, and a less damning one. Its whole identity is live, two-way Markdown you edit straight in Obsidian, and that isn’t a gap in what it does — it’s just not what I wanted. I browse the store and edit it indirectly, through the approval gate, never by hand-editing a file. Forking it would have meant inheriting its entire file-sync machinery to use a fraction of it, plus a permanent tax translating a bi-temporal schema onto Markdown frontmatter forever. The twist: Basic Memory turned out to be the best worked example for the retrieval layer I ended up building anyway — SQLite plus a hybrid embedding search. So it’s simultaneously the thing I rejected as a foundation and the thing I copied the shape of. Rejected as a whole category, not beaten by a specific competitor.

An outside reviewer put the same point more bluntly, in an independent look at the finished design: “Plain markdown vault + grep/embeddings (Basic Memory, Obsidian-MCP, etc.) — simpler, genuinely portable, but no temporal model and no real entity graph. You correctly crib their retrieval layer without inheriting their flat-file limitations.”

What the graph actually buys

A decision in mem-local isn’t a paragraph with a similarity score attached. It’s a node — entity ID, scope, rationale, a window of when it was valid — with typed edges to the project it belongs to, the decision it replaced, the open question it settles. Ask about “the memory system project” and you don’t get back whichever sentence sounds most similar out of a wall of prose; you get the project node and everything one hop out from it — decisions, provenance, related work. The same shape I’d follow by hand, clicking through wikilinks. The vector-plus-keyword layer decides which nodes are relevant to a query in the first place; the edges decide what comes along with them once found. Take either one away and the other can’t do its job.

Where this sits against the field

The fuller comparison against other personal-memory patterns — including the third camp, heavyweight graph stacks like Neo4j and GraphRAG, which mem-local isn’t that either — has its own page: theme-comparison-home-lab-patterns.


Sources: Building contextual memory for AI conversations, 17 Jun 2026 (the graph-vs-flat turning point); earlier, unpublished notes verification-pass-fork-base-fails and memory-system-differentiation-and-historical-search-decision; Home lab proposal review and comparison, 19 Jun 2026; earlier, unpublished notes origins-of-the-local-memory-project.