Skip to content

About

Repo-backed memory system that keeps AI coding agents continuous across hundreds of sessions

Resources

Stars

6 stars

Watchers

0 watching

Forks

Latest commit

 

History

4 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

long-running-project-memory

A maintained, repo-backed memory system that keeps AI coding agents continuous across hundreds of sessions — without relying on hidden model memory or chat-only notes.

The core idea: durable agent context lives in version-controlled files, split into separate layers, each with exactly one job. A small, dependency-free validator enforces the shape so the system stays small and usable instead of decaying into one giant NOTES.md that nobody trusts. It's strict about file shape precisely so your content, workflow, and runtime can stay loose — opinionated about structure, agnostic about everything else.

Per-project memory, not per-user memory. The repo is the boundary — an agent working in one project can't see another's context, because isolation here is the substrate, not a setting.

No API key, no VPS, no daemon, no vector database, no custom harness. It rides the Claude Code / Codex CLI you already run — cp a folder, chmod +x, run one stdlib Python script. Works with any agent that can read files in your repo. This is the current public, reusable distribution of a memory model proven across hundreds of sessions in a long-lived production project. It is maintained as the implementation, not as a placeholder for a newer private version.


Why

Agents forget everything between sessions. The usual fixes each fail in their own way:

  • One big notes file grows without bound, mixes current truth with stale history, and becomes too long and contradictory to trust.
  • Hidden / model memory isn't in the repo, can't be reviewed in a PR, and silently drifts from what the code actually does.
  • Memory daemons and vector vaults (auto-capture + embeddings + a SQLite store) add real infrastructure to chase the same goal — and optimize recall when the problem is truth. (Why not a vault.)

The differentiator here is enforcement. Most "agent memory" projects are a NOTES.md convention with nothing stopping the decay. This system makes memory layered, repo-backed, and self-limiting: each fact lives in the smallest file that owns it, current state is kept separate from history, and a dependency-free validator fails CI when the shape rots. The hard part everyone else skips is the forcing function — that's the part this ships.

The seven layers

No single file carries more than one of these:

# Layer File(s) Holds
1 Agent contract AGENTS.md (+ CLAUDE.md mirror) Small, stable behavior rules and the source-of-truth order
2 Runbooks docs/runbooks/*.md Repeatable task workflows and completion checklists
3 Live task state .git/agent-memory/tasks/ via tools/task_state.py Worktree-scoped objective, scope, next action, and blocker — never committed
4 Resume packets docs/resume/*.md Bounded future-only state for deliberate agent/machine transfers
5 Topic memory docs/memory/<topic>.md + topics.json Current durable facts and explicit domain ownership
6 Plans docs/plans/*.md Deferred or multi-phase future work with an exit condition
7 Structured history docs/repo_history/, indexed by CHANGELOG.md Immutable one-file-per-completion records, completed plans, and archived context

One file ties the layers together without being one of them: PROJECT_MEMORY.md is the router — a thin index into the topic memory (layer 5), kept small on purpose. It's injected at session start so the agent boots with a table of contents, not the whole encyclopedia, and the validator fails it the moment it stops being an index.

Three rules tie them together:

  • Live command output beats stored memory. Verify before claiming current state.
  • Current memory beats historical context. CHANGELOG.md and docs/repo_history/ are audit context, not authority.
  • External notes and model memory are leads, not authority. Check them against the repo.

Per-project, not per-user

Assistant-style agents that pool everything into one identity — projects, devices, calendars, chats — get cross-domain context bleed by default, and have to add isolation back with profiles or separate instances. This inverts that: the unit of memory is the project, not the user, and isolation is the substrate rather than a setting.

It's one rule — scope memory to the smallest unit that owns it — at two zoom levels:

  • Across projects: the repo is the wall. Another project's memory is files in a directory that were never injected, so an agent here can't be poisoned by them — there's no shared pool to leak from in the first place.
  • Within a project: the seven layers and the thin router keep even a large monorepo from drowning in its own context; only the topic files a task needs get pulled in.

The pooled-memory approach separates by configuration. This separates by construction.

Quickstart

From the root of the repo you want to add memory to:

# 1. Copy the scaffold in (replace the path with this clone's location)
cp -r /path/to/long-running-project-memory/template/. .

# 2. Make the hooks and tools executable, then enable the staged-scope gate
chmod +x .claude/hooks/session-start-context.sh hooks/pre-commit tools/*.py
git config core.hooksPath hooks

# 3. Confirm the shape is valid
python3 tools/check_memory_system.py
# -> memory-system check passed

Then customize (see Adopt it below) and commit.

Or just hand it to your agent

The heavyweight memory tools distribute as software — so you inherit their install surface, upgrade path, and breakage. This distributes as a spec your agent can satisfy. The installer is the agent you already have.

It works because of what the artifact is made of: the files are markdown (an agent reads and writes them natively) and the success condition is a stdlib validator (a hard pass/fail the agent can target). So "set this up for project X" isn't a vague ask — it's a well-formed, verifiable task. Point your agent at this repo and say:

Adapt this memory system to fit my project, then make python3 tools/check_memory_system.py pass.

None of the daemon/vault/embedding stacks can be installed that way — you can't hand an agent "run my SQLite vault and observer model" and have it be done and verifiable in one pass.

What's in this repo

README.md                                      You are here
LICENSE                                        MIT
.gitignore
.github/workflows/memory-system.yml            CI that validates the shipped template
template/                                       Drop-in scaffold — the whole system lives here
├── AGENTS.md                                  Agent contract (canonical)
├── CLAUDE.md                                  Byte-for-byte mirror of AGENTS.md
├── PROJECT_MEMORY.md                          Router / topic index
├── CHANGELOG.md                               Generated structured-history index
├── .github/workflows/memory-system.yml        Ready-to-copy CI (runs the validator)
├── .claude/
│   ├── settings.json                          Registers the SessionStart hook
│   ├── hooks/session-start-context.sh         Injects contract + router + live task state
│   └── skills/long-running-project-memory/    Claude skill (SKILL.md), bundled in-repo
├── .agents/
│   └── skills/long-running-project-memory/    Codex skill (SKILL.md + agents/ + references/)
├── docs/
│   ├── memory/README.md
│   ├── memory/topics.json                     Topic ownership and audit policy registry
│   ├── memory/workflow.md                     Starter topic for the memory system itself
│   ├── memory/_topic-template.md              Current-only topic shape
│   ├── plans/README.md
│   ├── resume/README.md                       Explicit transfer-packet boundary
│   ├── repo_history/                          Structured ledger + completed plans + archives
│   └── runbooks/                              triage, task-state, docs-change,
│                                              memory maintenance and review
├── hooks/pre-commit                           Staged scope + memory-system gate
└── tools/                                     Semantic knowledge routing/audit, validator,
                                               task state, scope, plans, and history

The runbooks shipped here are the memory-system ones. Add your own project runbooks (build, deploy, release, verification...) beside them and list them in AGENTS.md.

Adopt it into your project

After the Quickstart copy, do the project-specific part:

  1. Write your contract. The scaffold works zero-edit with generic defaults. Edit AGENTS.md only for durable cross-task behavior, universal safety, and runbook routes. Put stack setup, deployment details, domain rules, and volatile project facts in the relevant runbook or topic memory. Keep the contract small; it is the one file every session reads.
  2. Mirror it. cp AGENTS.md CLAUDE.md (they must stay byte-for-byte identical; the validator enforces this).
  3. Add real topics. The scaffold includes docs/memory/workflow.md for the memory system itself. Copy docs/memory/_topic-template.md to docs/memory/<topic>.md for each project domain (e.g. deployment.md, frontend.md). Prefer tools/project_knowledge.py create-topic so the topic file, topics.json ownership registry, router, and transaction receipt update together.
  4. Add project runbooks. Drop docs/runbooks/<workflow>.md files for your recurring tasks and reference them from AGENTS.md.
  5. Configure protected scope. Tailor PROTECTED_PATTERNS in tools/check_task_scope.py for runtime paths that should require explicit task authorization. Set a nonstandard primary branch with git config memory.primaryBranch <branch>.
  6. Validate, then let CI enforce it so routing, plans, history, transfer packets, and required files cannot silently drift. Run it locally:
    python3 tools/check_memory_system.py
    A ready-to-copy GitHub Actions workflow ships at .github/workflows/memory-system.yml — it runs the same check on every push and PR, no dependencies to install.

Not using Claude Code? Leave .claude/ inert — the file layout, runbooks, and tools stand on their own. The shipped validator checks the complete cross-agent scaffold; if you remove one assistant surface, tailor its required file list deliberately rather than leaving a half-installed integration.

Retrofitting an existing (messy) repo

Don't migrate everything at once — that just moves the big-ball-of-notes from one place to another. Convert lazily, in this order:

  • Drop in the contract. Add AGENTS.md, trim it to your real rules, cp AGENTS.md CLAUDE.md. This alone gives agents a stable starting point.
  • Sort your existing notes by layer, not by topic. Current facts → docs/memory/<topic>.md; deferred work → docs/plans/; finished work → structured entries under docs/repo_history/changelog/entries/; retired plans and old context → docs/repo_history/.
  • Create topic files only for domains you actually touch. Leave the rest until a task needs them — an empty topic is better than a stale one.
  • Retire static handoff files. Use the project-native transient state mechanism for live coordination and create a docs/resume/ packet only for deliberate pause or transfer. Preserve useful old handoff content in history instead of keeping the old file in startup context.
  • Add a runbook the first time you repeat a workflow, not before.
  • Turn on CI and let check_memory_system.py tell you what's still out of shape. Fix what it flags; ignore the rest until it matters.

How agents use it

  • At session start, the Claude Code SessionStart hook injects AGENTS.md, PROJECT_MEMORY.md, Git-local task-state output, and any explicit resume routes, so the agent boots with the contract, live state, and an index — not the whole encyclopedia.
  • The skill — methodology for designing, auditing, and repairing the system — is bundled in the repo, never installed globally, so it only loads where the system is actually used. Claude Code auto-loads it from .claude/skills/; Codex auto-discovers repo-scoped skills from .agents/skills/ when launched inside the repository. Nothing is copied into ~ — per-project, by construction, exactly like the memory it manages.
  • During work, the agent routes through PROJECT_MEMORY.md to the one or two topic files it needs, follows a runbook, and keeps risky or multi-session work scoped in Git-local state.

The validator

tools/check_memory_system.py is pure Python stdlib (no install) and enforces the invariants that keep the system honest:

  • all required contract / runbook / skill / archive files exist;
  • CLAUDE.md is a byte-for-byte mirror of AGENTS.md;
  • static handoff files are absent from current startup and workflow surfaces;
  • the agent contract remains below its enforced size ceiling and declares the boundary that routes project setup and history elsewhere;
  • explicit resume packets are bounded and schema-valid;
  • every docs/memory/*.md topic file has the four current-only sections and is routed bidirectionally through PROJECT_MEMORY.md;
  • PROJECT_MEMORY.md stays a thin router and includes docs/plans/ plus docs/repo_history/;
  • docs/plans/ contains indexed future-only plans with exactly one status, next action, and exit condition;
  • structured history and completed-plan lifecycle checks pass;
  • the topic registry, Markdown semantics, source-prose references, bundled skills, and optional domain coverage pass project_knowledge.py;
  • the SessionStart hook is registered, executable, and injects task state;
  • the memory-review runbook keeps its anti-churn language.

Watch it catch drift

Say an agent turns a future plan into a progress diary — exactly the rot a NOTES.md would swallow silently:

  # Opening explorer migration
  Status: `Incomplete`.
  Next action: Finish the bounded rebuild.
  Exit condition: The acceptance gate passes.

+ - [x] Deployed commit abcdef123456 and live-verified it.

CI goes red:

$ python3 tools/check_memory_system.py
memory-system check failed: docs/plans/opening-explorer.md contains checked work
$ echo $?
1

The plan is forced to remain future-only; that result belongs in one structured history entry. The same gate catches a CLAUDE.md that drifts from AGENTS.md:

$ python3 tools/check_memory_system.py
memory-system check failed: CLAUDE.md must be an exact byte-for-byte mirror of AGENTS.md

Run it locally, through the shipped pre-commit hook, and in CI — the scaffold ships a GitHub Actions workflow at .github/workflows/memory-system.yml that runs it on every push and PR with no dependencies to install.

Semantic knowledge routing and audit

tools/project_knowledge.py is the portable sorting layer. It has no agent_control.py, model, database, or network dependency. It can:

  • create and route a topic atomically with create-topic;
  • add, update, or move current facts and workflow steps with Git-local receipts;
  • reject active task state from durable Markdown;
  • audit every tracked Markdown file for stale references, mixed current/history sections, oversized contracts, and unintended duplicates;
  • inspect source comments and docstrings for stale documentation references;
  • validate skill resource links and size; and
  • report unexplained code/config domains from docs/memory/topics.json.

Start with advisory domain coverage so the scaffold can be adopted incrementally:

python3 tools/project_knowledge.py check
python3 tools/project_knowledge.py audit

After the topic registry covers the repository, change coverage to strict. Transaction receipts are also optional by default; enable require_transaction_receipts only when the team wants all durable-memory edits to go through the transaction commands or an explicit maintenance receipt.

Why not a vault

The vector-vault approach (auto-capture + embeddings + a SQLite store, shared across runtimes) is the popular answer, and it's solving the wrong problem.

  • A vault optimizes recall, not truth — and rot is a truth problem. Auto-capture ingests indiscriminately, so every stale, superseded, and contradictory fact goes in too. Retrieval is by similarity, and similarity is blind to currency: a deprecated fact is still relevant, so the vault happily surfaces it with a high score and presents it as current. There is no way to encode "this used to be true." This system's current topic memory beats repository history rule is an explicit authority hierarchy a vector store structurally cannot represent.
  • Rot stays visible. Rot in a markdown file shows up as a line in a PR diff a human catches. Rot in a vault shows up as a subtly wrong retrieval six sessions downstream that you can't trace back to a cause — invisible and unauditable, which is strictly worse than the NOTES.md it replaced.
  • What actually kills rot isn't storage or retrieval — it's legibility (you can read it), separation (current split from historical), and a forcing function (CI that fails when the shape rots). This repo is built entirely from those three.

Honest tradeoffs

Stated up front, because they're the real shape of the deal — not "set and forget," but "cheap to adopt, honest by construction":

  • The validator checks shape, not substance. It guarantees structure, not truth — an agent can produce structurally valid files that are semantically hollow. The session-start hook, the runbooks, and a human in the PR loop are what keep the content honest.
  • Capture and retrieval are manual. The agent has to write to the right file; there's no background extraction. That's a feature for people who distrust automatic memory and a dealbreaker for people who don't want to think about it.
  • It caps volume in exchange for legibility. Grep-plus-router over markdown has a ceiling; the topic split, thin router, and preserve-don't-delete rules push it far out, but they don't remove it. For one long-lived codebase that's the right trade every time. "Remember everything across my whole org/life" is a different product — don't reach for this there.
  • CLAUDE.md is a strict mirror by design. The byte-for-byte rule buys zero drift between the contract and what Claude reads, at the cost of putting assistant-specific shims in that file. They don't go there: per-assistant behavior belongs in agent config (.claude/ settings, skills) or a section of AGENTS.md that applies to everyone — not a diverging CLAUDE.md.
  • Agent-specific glue differs. Claude has the SessionStart hook under .claude/; Codex uses repo-scoped skills under .agents/skills/ plus the shared AGENTS.md contract. Both stay inside the project.

Design rules worth keeping

  • One concern per file. Behavior, workflow, live state, transfer state, durable fact, plan, and history never mix.
  • Live state is local. Worktree-aware task records do not merge or compete across branches; tracked resume packets exist only for deliberate transfer.
  • The router stays thin. PROJECT_MEMORY.md indexes; it is not the encyclopedia.
  • Reviews are self-limiting. When the automated check and the fixed rubric pass, the system is healthy — don't reopen the whole design every session.
  • Preserve, don't delete. Move stale facts and completed evidence to docs/repo_history/ instead of leaving them in current memory or dropping them.

Maintenance and freshness

This repository is the canonical public distribution of the reusable system. It is not a compatibility snapshot or an announcement for a separate, newer implementation. Changes to the seven-layer model, its bundled skills, or its enforcement belong here in the same maintenance cycle as the production lesson that motivated them.

The root CI validates the complete shipped template—including both agent skill surfaces, current Markdown hygiene, task-state self-tests, plan lifecycle, structured history, and scope enforcement—on every push and pull request. A clean clone of main is therefore the supported current version; consumers can compare or recopy the template without guessing which private revision is newer.

License

MIT — see LICENSE.

About

Repo-backed memory system that keeps AI coding agents continuous across hundreds of sessions

Resources

Stars

6 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages