Documentation Hierarchy — Source of Truth Spec
Documentation Hierarchy — Source of Truth Spec
Created: 2026-05-16 after audit revealed 6 out-of-sync documents tracking overlapping state. Enforced by: Every session start must read HANDOVER + LEDGER before touching anything.
The Problem This Solves
Docs kept diverging because status information lived in 4+ places with no ownership rule. When a phase completed, we’d update the plan doc but not LEDGER, or update HANDOVER but not AGENTS.md. Two sessions later, a stale reference would surface and cause confusion.
Root cause: No rule about which file owns which information.
The Hierarchy
TIER 1 — Source of truth (each owns its information type, nothing else does)
| File | Owns | Does NOT own |
|---|---|---|
LEDGER.md | Project status. What phase are we on? What’s done? What’s blocked? | Not for ops state, not for step-by-step how-to |
HANDOVER.md | Operational state right now. Current branch, current goal, next action, active blockers. Auto-written by session hooks. | Not for project history, not for how-to |
AGENTS.md | Agent runtime context. MCP architecture, tool selection rules, session protocol, branch naming. | Not for project status, not for operational state |
docs/plans/*.md | Execution recipes. How to execute a project — step by step, with rollback. Written ONCE before execution starts. | Not for status tracking. Never updated once execution begins. |
docs/decisions/ADR-*.md | Architecture decisions. Context, options considered, decision, consequences. | Immutable after Accepted. |
.mcp.json | What MCP servers are configured for this repo. | AGENTS.md table is derived from this — .mcp.json wins on conflict. |
TIER 2 — Derived (read-only references to Tier 1, never the source)
| File | Derives from |
|---|---|
~/.claude/CLAUDE.md (global) | MCP server table derives from .mcp.json. Update .mcp.json first, then sync global CLAUDE.md. |
AGENTS.md MCP table | Derives from .mcp.json. AGENTS.md is updated when .mcp.json changes — not independently. |
| Plan doc status header | Derives from LEDGER. The header is a convenience pointer; LEDGER is the source. |
The ONE Rule That Prevents Stale Docs
Phase status lives in LEDGER only.
When a phase completes:
- Update LEDGER.md row status. That’s it.
- Do NOT also update the plan doc, HANDOVER, AGENTS.md, CLAUDE.md.
- Optionally update the plan doc’s status header line as a pointer:
> **Status:** ✅ Phase X complete — see LEDGER for current status
When an operation completes (not a project phase, but a one-off action):
- Update HANDOVER.md next-action and major-state sections.
- If it affects a project, also update LEDGER.md row.
When MCP config changes:
- Update
.mcp.jsonfirst (canonical). - Update
AGENTS.mdMCP table to match. - Update
~/.claude/CLAUDE.mdMCP table if it’s a global server. - Never add an MCP server to AGENTS.md or CLAUDE.md without first adding it to
.mcp.json.
Plan Docs Are Write-Once (Like ADRs)
Once a plan doc is written and execution starts, it becomes a reference document, not a status tracker.
Good plan doc update: Fixing a factual error in the execution steps (e.g., wrong API endpoint).
Bad plan doc update: Adding ✅ to completed steps, or updating “Status: In progress”.
Status goes in LEDGER. The plan doc is the recipe; LEDGER is the cook’s journal.
Exception: The status header line at the top of each plan doc can be updated to a one-line summary pointing to LEDGER (e.g., > **Status:** ✅ Complete — see LEDGER). This is a pointer, not the status itself.
Session Start Checklist (in order)
- Read
HANDOVER.md— what’s the current operational state? - Read
LEDGER.md— what projects are active, what’s blocked? - Read
AGENTS.md— what MCP tools are available, what are the session rules? - Read plan doc only if actively executing that plan.
- Do NOT read plan docs to determine status — LEDGER is the source.
What Gets Updated When (quick reference)
| Event | Update these files |
|---|---|
| Phase completes | LEDGER (project row status) |
| Operational state changes (cron disabled, worker deployed, connection added) | HANDOVER (next-action + major-state) |
| New MCP server added | .mcp.json → AGENTS.md → ~/.claude/CLAUDE.md |
| New project starts | LEDGER (new row) + new plan doc in docs/plans/ |
| Project completes | LEDGER (move to Completed) + plan doc status header update |
| Architecture decision made | New ADR in docs/decisions/ |
| V5 invariant changes | .claude/rules/v5-invariants.md + master plan (both in same commit) |
Archiving Plan Docs
When a project moves to “Completed” in LEDGER:
- Update the plan doc’s status header to
> **Status:** ✅ COMPLETE — closed YYYY-MM-DD - Do NOT move the file. Leave it in
docs/plans/as a historical reference. - If the doc has conflict markers or is genuinely broken: fix or move to
docs/archive/plans/.
Anti-Patterns (don’t do these)
- ❌ Updating a plan doc with
✅ Phase 3 done— use LEDGER - ❌ Updating HANDOVER.md with project phase progress — use LEDGER
- ❌ Adding an MCP server to AGENTS.md without updating .mcp.json
- ❌ Updating
~/.claude/CLAUDE.mdMCP table before .mcp.json - ❌ Using a plan doc to determine “what’s done” — use LEDGER
- ❌ Updating LEDGER without updating HANDOVER when the next-action changes
- ❌ Having a “sources of truth” in two places for the same information type