Model or dataset
Growth-Kinetics/DiffMem avatar
Growth-Kinetics/DiffMem

DiffMem: Git Commits as Agent Memory, With an LLM That Runs grep

Git Based Memory Storage for Conversational AI Agent

902 stars60 forksPythonLicense varies

At a glance

What is it?
DiffMem stores conversational memory as Markdown files in per-user orphan branches and lets a retrieval agent explore them with shell commands instead of a vector index. The design is unusually legible and unusually dependent on one LLM loop behaving.
Who is it for?
Adopt DiffMem if you are self-hosting a conversational agent on a single Linux box with a mounted volume, you want memory that a human can read with cat, and you accept that OpenRouter credentials and a working LLM loop are part of the critical path. Do not adopt it if you need a managed service, a hosted API, or a retrieval path that keeps working when the model provider is down; the retrieval agent is the retrieval path.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 19 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem DiffMem picks: memory that stays readable after a year

Most agent memory stacks accumulate. A vector store grows a new embedding per turn, a graph grows a node per extracted entity, and after a year nobody can say which of those rows is still true. DiffMem's answer is to keep only the current view in files and push everything historical into Git's commit graph. The README describes this as separating the surface (current files) from the depth (git history), and it is the whole architecture in one sentence. The audience is narrow and identifiable: a team self-hosting a conversational agent on one small Linux box, with a mounted volume, that wants memory a human can open in an editor. The README states the project is I/O-bound rather than compute-bound and that an e2-small or 1 vCPU VPS is enough for thousands of conversations. That is a claim from the documentation, not a measured result, and it is the kind of claim you should re-derive against your own transcript volume before sizing a box.

Writer agent, retrieval agent, and a shell tool with no vector index

DiffMem ships as a small FastAPI service with two agents and an HTTP layer. The writer agent reads conversation transcripts, identifies or creates entities, and stages updates in Git's working tree; the README says commits are explicit and atomic. The retrieval agent is a multi-turn LLM loop with a single tool, run(command="..."), which explores the memory repository through sandboxed shell commands. It reads index.md, probes history with git log and git diff, and emits a structured retrieval plan of file sections, diffs and commit logs that the service then resolves into context. There is no embedding step and no BM25. That removes an entire class of infrastructure, and it also means retrieval quality is a function of the model's ability to form good grep and git commands. The index.md file is the entry point the agent reads first, so the shape of that file is effectively a retrieval configuration, even though nothing in the README calls it one.

Per-user orphan branches and the worktree trick

Isolation is handled at the Git level rather than the database level. Each user gets an orphan branch named user/{user_id} inside a single local storage repo, and that branch is checked out into a per-user worktree when the user is active. Orphan branches share no history with one another, so one user's commit graph cannot leak into another's through a merge base. The README frames this as strict isolation without per-user repositories. The trade-off is that the storage backend is not really pluggable in practice: the README states that local storage, a mounted disk, is a hard requirement of the retrieval agent because that agent shells out to grep and git log against a real directory. You can swap the backup backend, not the storage backend. Anyone planning to put memory on S3 or in a managed database should read that line twice, because it closes off the option.

Backup is a mirror you opt into, not a dependency

Two concerns are separated in the configuration: where the repo and worktrees live, and where they are mirrored. The backup backend defaults to none, which the README pairs with relying on volume snapshots. The alternative is github, which mirrors user branches to a private GitHub repository you own. Pushes run on a scheduler and are never in the request hot path. Pulls happen at worktree mount time, meaning the first request per user after a restart, which keeps the local volume in sync with edits made from other machines. The README says a self-hoster can run DiffMem with zero external dependencies and that enabling the mirror takes two environment variables. The pull-on-mount behaviour has a consequence worth naming: after a restart, the first request from each user pays for the pull, so a cold start is not uniform across users.

Running it: Coolify, one API key, and the port variable

The documented path is Coolify, the self-hostable deployment tool. Create a new Docker Compose resource, point it at https://github.com/Growth-Kinetics/DiffMem, keep the compose file path at docker-compose.yml, and set OPENROUTER_API_KEY in the Environment Variables tab with a key from openrouter.ai/keys. Attaching a domain is optional and Coolify handles TLS through Let's Encrypt. Coolify builds the image, provisions a named volume at /data that persists across deployments, runs the healthcheck, and routes traffic through Traefik. The service listens on PORT, defaulting to 8000. The README also notes that DiffMem is importable as a Python library and exposes HTTP endpoints for onboarding users, processing sessions, and retrieving context, though it does not enumerate the routes. The Python badge says 3.11+. The supplied material stops mid-sentence while describing what Coolify asks for regarding the service port or proxy, so treat the port configuration as documented only up to that point and confirm the rest in the compose file itself.

Where DiffMem is the wrong tool

The failure modes are visible in the README's own roadmap. Indexing strategy from the proof of concept is listed as needing work and as too memory intensive without need. There is no parametrized method for context caps on retrieval yet, so you cannot bound the context the retrieval agent assembles through configuration. The roadmap also admits that an entity sometimes becomes a catch-all and the system insists on overloading it, which is a data-modelling failure that no retrieval improvement fixes. Retrieval history, needed for a linked-entities model to support wikification, does not exist yet. PDF export does not exist yet. The deeper structural limitation is that the retrieval agent is an LLM loop over shell commands, so every retrieval costs model calls, and a provider outage is a memory outage. A system that used embeddings would degrade differently: stale or wrong, but still answering. If your agent must answer when OpenRouter is unreachable, this is the wrong architecture. If your transcripts are short-lived and you never need to ask how a fact changed, the Git history is dead weight and a plain database is simpler.

What DiffMem is not: the case for a vector store or a graph

The obvious alternative is a vector database with an embedding pipeline, the pattern DiffMem explicitly rejects. The difference is not storage medium, it is what gets retrieved. A vector store retrieves passages by similarity to the query, which means the unit of recall is a chunk of text and relevance is approximate. DiffMem retrieves by file path and commit range, which means the unit of recall is a named entity's current state plus a diff, and relevance is exact but depends on the agent choosing the right path. That inverts the failure mode. Vector search fails by returning plausible but wrong context; DiffMem fails by returning nothing because the agent grepped the wrong term or the entity was filed under an unexpected name. A graph memory system sits between them, with explicit relations but the same extraction cost DiffMem avoids. Which one you want depends on whether your queries look like "what is similar to this" or "what changed about this person." DiffMem is built for the second question.

Licence, version, and what a year of maintenance looks like

The README displays an MIT licence badge and links to opensource.org, and the version badge says 0.5.0. The repository metadata supplied here does not name a licence, so the badge and the metadata disagree, and the licence file in the repository is the thing to read before you build on it. That is a factual check, not legal advice. On maintenance: the project has no releases retrieved, so there is no changelog to read and no versioned upgrade path beyond tracking the main branch. The last push recorded is 2026-08-28. The roadmap items are unchecked, which suggests active work rather than a frozen codebase, and also suggests that the indexing memory-intensity issue and the missing context caps are things you may have to work around rather than configure away. The operational cost is dominated by one thing: every retrieval is an LLM call, so your OpenRouter bill scales with retrieval frequency, not with stored memory size. That is the number to model before you deploy.

Editorial conclusion

Adopt DiffMem if you are self-hosting a conversational agent on a single Linux box with a mounted volume, you want memory that a human can read with cat, and you accept that OpenRouter credentials and a working LLM loop are part of the critical path. Do not adopt it if you need a managed service, a hosted API, or a retrieval path that keeps working when the model provider is down; the retrieval agent is the retrieval path. Before committing, verify three things in your own checkout: that the Python 3.11+ requirement matches your runtime, that the storage backend stays on local because the retrieval agent shells out to grep and git log against a real directory, and that the licence file in the repository matches the MIT badge the README displays, since the repository metadata does not name a licence.

Official sources

  1. Growth-Kinetics/DiffMem on GitHub
  2. Issues
  3. README
Community notes

Community notes