I've been building NexusMem mostly alone, in long
stretches, for a few weeks. It's a local-first memory engine for AI coding agents: it indexes your
git history, shell commands (with exit codes), project docs, and optionally your assistant
transcripts into a SQLite database on disk, then serves back a ranked, token-budgeted slice of it
over MCP or a CLI. No account, no cloud, no telemetry.
The pitch, in one line: your agent can already read git log. It cannot read the four things you
tried last Tuesday that didn't work — and that's the part actually worth remembering.
This week two strangers showed up and started fixing things I didn't ask them to fix. That felt
like a good excuse to write about what it does and why.
The problem it's solving
Coding agents get context from two places: what you paste in, and what they can grep. Neither one
remembers process. Git tells an agent what shipped. It has nothing to say about the three
approaches you tried before the one that worked, or which shell commands exited non-zero while you
were debugging it. That information exists for maybe a day, in your terminal scrollback, and then
it's gone.
NexusMem's answer is boring on purpose: read what already exists on disk (git log, shell history,
markdown docs), normalize it into one node shape, index it, and rank it well enough that a query
returns the right five things instead of the right fifty.
The interesting part: ranking priors against each other
The retrieval side is BM25 over SQLite FTS5, plus a vector pass over sqlite-vec if an embedding
model is reachable, fused with Reciprocal Rank Fusion. RRF fuses on rank position only, never raw
scores — that's the whole point of using it, since a BM25 cost and a vector distance live on
unrelated scales and position is the only thing they agree on.
On top of the fused rank, two priors adjust the score: signal (a fix: commit outranks a
chore:; a shell command that exited non-zero outranks one that succeeded) and recency. Both are
real signal. Both also almost broke the whole thing.
Dogfooding the tool on its own repo, a query about a PowerShell hook returned two unrelated
same-day fix: commits at ranks 3 and 4, while the commit that actually answered the query sat at
rank 6. The priors were capped individually — each could overturn at most a 2× relevance gap — but
the score multiplies them together, so a fresh, high-signal commit (which describes most of an
active working day) could overturn 4×. The fix wasn't a bigger cap, it was a shared one: priors now
split one budget across both of them, derived so each is worth exactly √2, not asserted by feel.
I only found this because I kept running real queries against the tool's own commit history and
reading the output critically instead of trusting the ranking math on paper. That's most of what
building this has actually been: dogfood, find the case where it's confidently wrong, write a test
that fails before the fix and passes after.
Where it's honest about not working
The README has a "Where it breaks" section and I've tried to keep it truthful rather than
reassuring. A few examples:
- Shell history without an installed hook has no directory context, so it gets attributed to
whichever repo you happened to run
syncfrom. - Languages without whitespace word boundaries (Japanese, Chinese) get no useful BM25 recall — they depend entirely on the vector pass.
- Rebasing strands nodes for commits that no longer exist in the rewritten history.
There's also a number I was tempted to lead with and didn't: the original target was cutting API
token spend by more than 70% versus sending full context. Measured end-to-end on this repo, it's
closer to 40%. The >70% figure describes what the packing math shows against its own candidate set,
which is a real number but a different, rosier question than "how much less did the agent actually
read." The README says this outright instead of quietly reporting the friendlier number.
The part that made this week different
I built this solo, iterating in long sessions, for weeks. This week, for the first time, someone I
don't know opened an issue asking to add end-to-end stdio transport coverage for the MCP server —
the existing tests only exercised an in-memory transport, which can't prove protocol framing
survives a real process boundary. They described their approach in a comment first, then shipped a
PR that spawns the actual built CLI as a
child process and asserts every line written to stdout parses as JSON-RPC. CI caught a real
Windows-only bug in their first pass (a .cmd shim needs shell: true to spawn on Windows) — they
fixed it within the hour and it merged clean.
A second person forked the repo the same day and, without opening an issue first, found something I
hadn't: the PowerShell hook always inserted its block with \n line endings, but a profile written
by a Windows editor is CRLF by convention, so installing the hook silently turned a CRLF file into a
mixed-ending one — and removing it later left a stray bare newline behind. That's a subtle enough
bug that finding it means actually reading the code, not skimming it.
Neither of those things needed me. That's the part worth sitting with — the project became legible
enough, on its own, for someone else to extend it correctly on the first try.
Try it
npx nexusmem init
npx nexusmem sync
nexusmem query "windows spawn failure"
Requirements are just Node 22+ and git. Ollama is optional and only affects semantic search — BM25
works fully without it.
Repo's here if you want to poke at it, and there's
now a CONTRIBUTING.md
if you find something worth fixing.
Top comments (1)
The failed-attempts part is the valuable bit. Git history records settled facts, but the expensive context is usually the dead branch you tried for an hour and abandoned. I like the cap on recency and signal priors here, since those features can become a very confident way to retrieve the wrong thing.