Appreciate this — and you've basically described the mechanism OmniMemory already runs on, which is a good sign we converged on the same answer.
Every memory is stamped at capture with the short SHA of the commit it was born at (commit_range). Staleness is then exactly the bounded question you framed: git diff birth_sha..HEAD narrows to the changed files, and the tree-sitter code graph intersects those diff hunks with the specific symbol line-ranges the memory cites (propagated one hop through the call graph). So an unrelated edit to the same file doesn't flag it — only a change that actually touches the cited symbol does. No open-ended scan of the current tree.
The merge semantics you called out fall out of that same provenance: a branch-scoped memory promoted at merge is re-anchored onto the base but keeps its birth SHA, and a memory whose branch never reached main gets classified abandoned and aged out automatically.
One thing I'd add on top of birth→HEAD diffing: a diff range catches drift but can't catch a source that was deleted out from under a memory (nothing in a later diff mentions what's gone). So there's a second pass that enumerates the git tree and re-resolves each memory's recorded blob SHA — FRESH / DRIFTED / ORPHANED — which is the half that never self-heals.
Strong agree on local-plus-inspectable being the point, not a footnote — it's all local SQLite with a dashboard and a plain MEMORY.md, precisely so it doesn't become a second CLAUDE.md you can't read. Thanks for the thoughtful note, and I'll take a look at the Skillselion comparison.
Most memory projects stop at storage, and this sentence is why yours is more interesting: "Persistent memory is only useful if you can tell when it's no longer true." A suggestion that builds on your branch-provenance tracking: stamp every memory with the commit SHA it was born at. Staleness checking then becomes a bounded question, "did anything in the diff range between birth SHA and HEAD touch the symbols this memory cites," which tree-sitter answers precisely, instead of an open-ended scan of the current tree. It also gives merges a clean semantic: a branch-scoped memory promoted at merge keeps its provenance, and a memory whose birth commit never reached main can be aged out automatically. The local-plus-inspectable stance matters as much as the mechanism; a memory layer you cannot audit becomes a second CLAUDE.md you cannot read. I keep a comparison of the current persistent-memory approaches for Claude Code at skillselion.com/guides/claude-code-persistent-mem… (disclosure: I run Skillselion), and OmniMemory's git-awareness is a genuine differentiator in that field.