The Memory Layer Your AI Coding Agent Was Missing
Every AI coding session ends the same way. The context window fills, the session closes, and everything the model figured out evaporates: the port that service actually runs on, why you chose SQLite over Postgres, the exact flag that made the compiler stop complaining. Next session: same questions, same wrong first guesses, same wasted turns.
I got tired of it. memd is what I built instead.
What it actually does
memd runs as a background service and watches your AI coding sessions. When a session ends, or a timer fires, it collects the transcript, strips credentials, and hands it to a curator model that rewrites four markdown files under .memory/ in your project root:
- state.md — what’s true right now: ports, directory layout, running services, active workarounds
- decisions.md — what was decided, why, and what that rules out
- todo.md — open tasks and roadmap items
- mistakes.md — what went wrong before, and the rule that prevents a repeat
The next session starts with memd brief injected into context. The model already knows the project. No re-explaining. No re-discovering.
Why you can trust the output
The curator model is useful but not trusted. Every invariant that matters lives in Python, not in the LLM output:
mistakes.mdis append-only. The model can add entries, never delete them.- A distill that would remove more than 60% of a file is rejected outright.
- Files that exceed size budgets get archived to
.memory/archive/YYYY-MM.md, not deleted. - Every write goes through a frontmatter validator before it touches disk.
- Per-project file locking means concurrent agents, sweep timers, and hooks can’t corrupt each other.
The model curates. Python enforces. You read the output and it’s honest because the Python said so, not because you’re trusting a language model to follow its own rules.
The inbox protocol
The inbox is where the design earns its keep. Any agent, script, or human can drop a note into .memory/inbox/ and it gets folded into memory on the next sweep. The rules are strict: write atomically (stage outside the inbox, fsync, then rename), never modify a published note, use microsecond-resolution timestamp + PID for filenames to prevent collisions.
This is how the noctalia-claude-plugin integrates: when the MCP shim has something worth remembering, it drops it in the inbox. No direct writes to memory files. One curator, many writers, zero races.
Nix + home-manager integration
{ inputs, pkgs, ... }: {
imports = [ inputs.memd.homeManagerModules.default ];
services.memd = {
enable = true;
installClaudeHooks = true; # wires ~/.claude/settings.json
sweep = {
enable = true;
interval = "30min";
};
};
}
On my system, volnixos, the sweep runs every 30 minutes. On session end, the claude-code hook fires a memd sync immediately. Memory stays current without any manual intervention.
Decision capture, not memory
I built this for memory persistence. What I use it for is decision capture. Three months into a project, when you’ve made thirty small architectural calls and you’re staring at a bug that doesn’t make sense, decisions.md tells you exactly which call you made six weeks ago that explains it. The model didn’t write that reasoning down at the time. memd did.
Tip
Memd is available under PyPI and as a nix flake. Be sure to install under a venv if you are running an externally managed environment like Arch Linux (EndeavourOS, CachyOS). Install:
pipx install memdornix run github:lowcache/memd -- status
Written from the machine it describes. More field notes: the archive · RSS.
Working on something in this territory? I take on scoped engagements.