# The Committed Project-Memory Spine — A Portable Implementation Guide > **What you're reading.** A self-contained, copy-paste-ready guide to a small system that gives an > AI coding agent **durable, version-controlled memory of a project** — memory that survives across > sessions, machines, *and* across different agents/tools, because it lives in the repository itself. > > This guide is **project-agnostic**. The pattern and all templates below work for any software project. > A real implementation (a Unity factory-automation game called *Yuletide Works*) is used throughout as a > **worked example**, always clearly boxed and labelled `EXAMPLE` — copy the *generic* templates, not the > example text. > > Hand this whole file to an agent in another project and say *"set this up for us."* --- ## 1. The core idea AI coding agents are stateless between sessions. Most agent tools offer some "memory," but it is almost always **machine-local and tool-specific**: it lives in a hidden directory on one developer's laptop, isn't shared with teammates, doesn't travel with the repo, and is invisible to a *different* agent or a human reading the project later. This system takes the opposite stance: > **Project memory is part of the project. It is committed to the repository, version-controlled, > reviewed in pull requests, and readable by any agent or human who clones the repo.** It does this with a handful of plain Markdown files plus two pieces of automation. Together they form a **read-at-start / write-at-end loop**: ``` ┌─────────────────────────────────────────────┐ │ Repo-committed memory spine (plain Markdown) │ │ • PROJECT_STATE.md (live one-page truth) │ │ • RUN_LOG.md (append-only history) │ │ • DECISIONS/*.md (ADRs — the "why") │ └───────────────┬───────────────────────────────┘ │ START of session │ END of session ┌────────────────────┐ │ ┌──────────────────────┐ │ session-start hook │ ── reads ┘ │ /checkpoint routine │ │ injects git state │ │ doc-drift sweep + │ │ + top of STATE │ ── writes ─────────▶│ updates STATE, │ └────────────────────┘ │ appends RUN_LOG, │ │ adds ADR if needed │ └──────────────────────┘ ``` **The contract that keeps it healthy:** the spine tracks *progress and decisions only*. It **points at** the authoritative docs (architecture, coding rules, scope) — it never **restates** them. That single discipline is what stops the spine from going stale and contradicting itself. (More on this in §4.) ### Why each piece exists | Piece | Answers the question | Lifecycle | |---|---|---| | `PROJECT_STATE.md` | *"Where are we **right now**?"* | **Living** — overwritten every session; kept to ~one page. | | `RUN_LOG.md` | *"What happened, and **when**?"* | **Append-only** — newest entry on top; never rewritten. | | `DECISIONS/` (ADRs) | *"**Why** did we choose this?"* | **Frozen** — written once; superseded by new ADRs, not edited. | | session-start hook | *Bootstraps the agent's context automatically.* | Automation (tool-specific). | | `/checkpoint` routine | *Persists memory consistently at session end.* | Automation (a skill / prompt / habit). | The three time-horizons — **now** (STATE), **history** (RUN_LOG), **rationale** (ADRs) — are deliberately separated so each file has exactly one job and one update rule. Don't merge them. --- ## 2. The five components (with copy-paste templates) Create a `docs/` directory (or your project's docs home) and a `docs/DECISIONS/` subdirectory. The five components below go in the places shown. Everything is plain Markdown except the hook (a shell script) and the settings file (JSON). > Throughout, `<…>` marks a placeholder to replace. Keep the structure; swap the content. --- ### 2.1 `docs/PROJECT_STATE.md` — the one-page live snapshot **Job:** the single "current truth" of where the build is. Read it *first* when resuming work. Keep it to roughly one screen — detail goes to `RUN_LOG.md`, rationale goes to `DECISIONS/`. **Overwrite it** each session; it is not a log. It has a stable skeleton: a header note, *Current position*, a **phase/milestone tracker**, an optional **scope-gate tracker**, *Next actions*, *Open questions*, an optional **scope ledger**, and *References*. Drop the trackers you don't need, but keep "Current position / Next actions / Open questions" — those are the minimum that makes a resume cheap. ````markdown # Project State — > **One-page living snapshot.** This is the committed, version-controlled "current truth" of > where the build is. Keep it to roughly one screen — push detail into [RUN_LOG.md](RUN_LOG.md) > and [DECISIONS/](DECISIONS/). Update it at the end of every working session. > > This file does **not** restate architecture, invariants, or scope rules — those live in > [the project guide / README] and the planning docs. This file tracks *progress and live decisions only*. _Last updated: ()_ --- ## Current position - **Stage:** - **Active gate:** - **Branch focus:** - **Verification:** --- ## Phase / milestone tracker Status legend: `[ ]` not started · `[~]` in progress · `[x]` done & verified · `[!]` blocked. Source of truth for each item's scope and acceptance criteria: . | # | Title | Status | Notes | |--:|-------|:------:|-------| | 0 | | `[ ]` | | | 1 | | `[ ]` | | | 2 | | `[ ]` | <…> | | … | … | `[ ]` | … | --- ## Scope-gate tracker *(optional — keep if the project has staged scope)* | Gate | Definition | Status | |------|------------|:------:| | **** | | `[ ]` not started | | **** | | `[ ]` not started | | **** | | `[ ]` not started | --- ## Next actions (explicit order) 1. 2. <…> --- ## Open questions / decisions pending These are flagged-but-unresolved. Resolve each via an ADR when decided, then mark it RESOLVED with a link. - **** — . → ADR when decided. - **** → **RESOLVED** ([ADR-NNNN](DECISIONS/ADR-NNNN-.md)): . --- ## Scope ledger *(optional — the documented defense against scope creep)* Anything deliberately deferred out of the current stage gets logged here so it is a **decision, not a leak**. | Item | Decision | Revisit at | |------|----------|------------| | | Deferred | | > When a task tempts you toward one of these before its gate, add a row here with the temptation and the > deferral rationale **rather than building it.** --- ## References - Decisions: [`DECISIONS/`](DECISIONS/) — . - Run history: [`RUN_LOG.md`](RUN_LOG.md). - Architecture, invariants, scope, build order: . - Planning docs: . ```` > **EXAMPLE (Yuletide Works).** The phase tracker has 16 rows (Phase 0 → MVP review gate); two are > `[x]` done with verification baked into the Notes cell (`EditMode 55/55, PlayMode 5/5, user visual > confirm passed`). The scope-gate tracker has four gates (`Prototype → MVP → Vertical slice → Version 1`). > The scope ledger has a standing table of 13 features explicitly deferred to "V1" (magical power, fluids, > recycling, multi-floor, …) plus per-phase deferral tables added as each phase makes a deferral decision. > The `_Last updated:_` line is a *paragraph* that summarises the latest merge and names what's next — so > the auto-injected head (see §2.4) tells the whole story without opening the file. --- ### 2.2 `docs/RUN_LOG.md` — append-only session history **Job:** the narrative of *what happened, when*. One entry per working session, **newest on top**. Keep entries short — anything still *current* belongs in `PROJECT_STATE.md`; rationale belongs in an ADR. This file is **append-only**: never rewrite past entries (they are point-in-time records). ````markdown # Run Log — > Append-only history of working sessions. Newest entry at the **top**. One entry per session. > Keep entries short — detail that's still *current* belongs in [PROJECT_STATE.md](PROJECT_STATE.md); > decisions belong in [DECISIONS/](DECISIONS/). This log is the *narrative of what happened, when*. --- ## Entry template (copy this) ``` ## YYYY-MM-DD — - **Goal:** - **Did:** - **Verified:** - **Open / blockers:** - **Memory updated:** STATE ☐ · RUN_LOG ☑ · ADR ☐ () ``` --- ## - **Goal:** <…> - **Did:** <…> - **Verified:** <…> - **Open / blockers:** <…> - **Memory updated:** STATE ☑ · RUN_LOG ☑ · ADR ☐ ```` > **EXAMPLE (Yuletide Works).** The very first entry recorded the spine being scaffolded > (`Verified: n/a — no game code yet`). Later entries cite real verification — > `Verified: compile 0 errors, EditMode 55/55, PlayMode 5/5` — and the `Memory updated:` checkboxes make > it auditable which artifacts each session touched. --- ### 2.3 `docs/DECISIONS/` — Architecture Decision Records (the "why") **Job:** capture *why* each non-trivial call was made — the context, the options weighed, the choice, the consequences — so a future contributor (or future you, or a future agent) doesn't have to reverse-engineer it. An ADR is written **once and then largely frozen**; later thinking lands in a *new* ADR that supersedes the old one, **never** as an edit to the original. This subdirectory holds three kinds of file: a **template**, an **index (`README.md`)**, and the numbered **ADRs** themselves. **When to add one (important):** add an ADR **only when a real decision with alternatives and lasting consequences was made** — a structural call, a tooling commitment, a guardrail, a deliberate deviation from the docs. Routine work — implementing a planned feature, fixing a bug, writing tests — does **not** earn an ADR. (The `/checkpoint` routine in §2.5 enforces this.) #### 2.3.1 `docs/DECISIONS/ADR-TEMPLATE.md` ````markdown # ADR-NNNN: - **Status:** Proposed | Accepted | Enacted | Superseded by ADR-XXXX | Deprecated - **Date:** YYYY-MM-DD - **Deciders:** - **Phase / stage:** ## Context What problem are we solving? What forces are at play (technical constraints, the governing architectural rules, scope stage, the project invariants)? Why does this need a decision now? ## Decision What we decided, stated plainly. One paragraph. ## Alternatives considered - **A —