Coding agents (Claude Code, Codex, and friends) are stateless across sessions: every conversation re-derives who you are, what you're working on, and what was already decided. That produces amnesia, context cost, and drift. The naive fix — one giant MEMORY.md — fixes the amnesia but makes the other two worse. This separates what the agent loads every turn from what it queries on demand, and makes the two layers provably consistent.
This page describes a system running daily on my own hardware. The repository is a sanitized architectural write-up — the design and the invariant, with invented example data — not the live store.
origin/main, it wasn't savedTwo layers — a portable lean layer loaded into context every session, and a canonical deep layer queried on demand — tied together by the deep ⊇ lean invariant, kept in sync by git hooks and a nightly job, and recoverable through a local semantic search layer for when manual routing fails.
MEMORY.md as an executive index + routing table, domains/*.md with per-domain summaries, and .semantic/ with the local vector index. Optimized for low context-window cost and fast routing. It's derived from the canon; lives on the laptop + GitHub.
Full history, rationale, and nuance. Optimized for completeness and auditability. Written first: every decision lands here before anywhere else. Lives on the home server + GitHub + _lean-mirror/ inside the deep store itself. Read on demand.
deep ⊇ lean. Everything in the lightweight summary also exists in the canon. A nightly job re-mirrors the lean repo into deep/_lean-mirror/, so the canon can never silently fall behind its own summary.origin/main, it isn't saved.Chat output is ephemeral. A decision that lives only in a conversation is lost when the window closes. That's why the mandatory last step of every useful session is writing the decision/correction/TODO to the canonical domain file, committing, and pushing. Conflicts resolve by the newest dated correction wins — every entry carries a date (YYYY-MM-DD, always absolute, never "yesterday").
Manual routing (a table of "if the topic is X, open file Y") is fast but brittle: it fails on queries that don't map cleanly to a known domain. That's why the lean repo carries a local semantic index.
Ollama running nomic-embed-text — local, no data leaves the machine. The corpus is personal by definition; sending it to a hosted embeddings API would leak exactly what this system protects. Local-first isn't a preference, it's the threat model.
LanceDB — embedded, no server to stand up. A single search queries the lean index and the deep one and merges by score, so you get the best hit no matter which layer it lives in.
Via a post-commit hook; manual re-index available for full rebuilds. Commit a markdown file and the index updates itself.
For a specific question where the routing table isn't obvious, run semantic search before answering from memory. For broad "where are things" questions, fall back to the executive index.
The whole system falls apart if keeping the layers in sync is manual work. It isn't:
# deep auto-push (post-commit hook) commit to deep ──▶ push to GitHub # you can't forget to back up # lean → deep mirror (nightly cron on the server) git fetch + reset --hard origin/main # read-only clone of lean rsync --delete ──▶ deep/_lean-mirror/ # enforces deep ⊇ lean commit + push of deep # escape hatch: same script, on-demand force-sync # when you don't want to wait for the cron
The mirror enforces the deep ⊇ lean invariant instead of trusting a human to maintain it. And the deep store is published as a Docsify wiki served 24/7 from a Docker/nginx container (--restart unless-stopped, vendored assets to run offline): commit a markdown file and the readable wiki updates with no build step.
| Decision | Why | Trade-off accepted |
|---|---|---|
| Two layers instead of one file | Context cost and completeness are in tension; separating them lets each side be optimized independently. | More moving parts; needs the deep ⊇ lean invariant to stay honest. |
| Canonical deep, derived lean | A single source of truth avoids the "which copy is the good one?" problem. | The lean layer can lag intra-day until the next mirror; acceptable for a summary. |
| Markdown + git, not a database | Readable, diffable, grep-able, zero infra to read; survives tooling changes. | No rich queries unless you bolt on the semantic layer. |
| Local embeddings (Ollama) | The corpus is private by definition. | Requires a machine running Ollama; slower than a hosted API. |
| The newest dated correction wins | Deterministic conflict resolution an agent can apply mechanically. | Demands discipline: every entry must be dated. |
| The write-back is the last step, mandatory | Knowledge that stays in the chat is lost. | Adds a step to every session; enforced by protocol, not tooling. |
| Docsify over a site generator | Reads markdown live, no build; offline via vendored assets. | Less polished than a full SSG. |
Running in production as the personal memory backbone of a multi-agent workflow since 2026. The repo is a sanitized architecture write-up: everything under examples/ uses made-up data for a fictional person. The real store is private.