Seed an AI-legible project memory map that stays small

One file (AGENTS.md) that bootstraps the rest: rules, the file map to create,
what belongs in each file, the first-session interview order, and the list of
anti-patterns that killed the previous map (1,308-line guide, 63 task files,
narrative history inline, sessions skimming 56k tokens of context).

Separates four kinds of content by read frequency:
  rules/invariants  -> AGENTS.md          (every session)
  subsystem truth   -> docs/ai/<topic>.md (only the matching one)
  lookups           -> environment.md     (grepped, never read)
  retired decisions -> decisions.md       (only when re-opening one)

Caps are enforced, not promised: scripts/verify.sh checks doc budgets before
the build, so a commit that pads a capped file fails. Proven both ways — it
passes clean and exits 1 on an over-cap file.

scripts/scope-check.sh blocks edits outside the declared file list.
templates/ holds fill-in skeletons for the seven files a project must create.

CC0: copy it, rename it, sell it, no attribution needed.
This commit is contained in:
2026-10-30 06:51:19 -07:00
commit b5e3dbe614
14 changed files with 559 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
# AGENTS — bootstrap
You are starting this project's memory from nothing. This file is self-contained: it gives you
the rules, the file map you must create, what belongs in each file, and the order to do it in.
Two standing orders:
1. **This file is the only mandatory read at session start.** Everything else is read on demand.
2. **Finish work; do not manage it.** A session that produces task lists, re-prioritisation or
documentation of work instead of working has failed, even if the docs are good.
---
## 1. Rules — non-negotiable
**Delivery**
- One unit = one behaviour = **one test** = one commit. If a request needs several tests, pick the
one the user cares about and finish it before the next.
- No feature branches pre-1.0. Work lands on `main`, committed per unit.
- Commit every unit without asking. **Push only at checkpoints the user names.**
- Declare the exact file list before editing. No "while I'm here" edits, no drive-by refactors.
Anything spotted outside the list becomes a one-line follow-up in `HANDOFF.md`.
- One pre-commit gate for code: clean build at **0 warnings**, full tests, scope check, doc budgets
(`scripts/verify.sh "<files>"`). Docs-only units run the scope check alone.
**Reading**
- Session start, in this order, and stop: `HANDOFF.md` → `ai.md` → **the one** `docs/ai/<topic>.md`
that matches the task → `<dir>/index.md` for the code you will touch.
- `TASKS.md` is read when the question is "what's next" — never as a prerequisite to code.
- Never read the whole map "for context". If the map is a required read, the map is wrong.
**Memory**
- The map is corrected by the change that **falsifies** it — in the same commit. It is not a unit
of its own; no "docs backfill" commits unless asked.
- Three kinds of truth, three homes: rules/invariants → this file; subsystem detail →
`docs/ai/<topic>.md`; lookups (paths, ports, hosts, credential locations) → one cheat sheet.
History and abandoned decisions → a decisions log, never inline in the docs.
- `HANDOFF.md` is current state only, **overwritten not appended**, hard-capped.
- A fact recorded once ends the re-derivation loop: paths, traps and recipes go in the map the
first time they cost a hunt. **Grep the recipes file before re-deriving anything.**
**Behaviour**
- Do the work, then report what changed and what's next. No plans, pros/cons tables or "pitfalls"
sections unless asked.
- Nothing here is novel: scan externally before building anything new, cite the reference in the
commit. A **second** failed fix for the same symptom is a research trigger, not a persistence
trigger — stop and find the established answer.
- Follow the codebase's existing conventions; don't add comments the code doesn't need; don't
invent work items.
---
## 2. Files you must create
| File | Role | Cap | Written by |
|---|---|---|---|
| `AGENTS.md` | This file: rules + the project's invariants | 210 lines | you, rarely |
| `ai.md` | **Router**: what the product is, build commands, architecture table, where truth lives | 100 lines | you, rarely |
| `HANDOFF.md` | Current state: branch, in flight, next action, landmines | 40 lines | every session, overwritten |
| `TASKS.md` | The active queue, one line per live item | 120 lines | on status change |
| `TASKS/archive.md` | Everything done, as a dated snapshot | unbounded | at trim time |
| `docs/ai/<topic>.md` | Subsystem truth — one file per subsystem | unbounded | as that subsystem changes |
| `docs/ai/index.md` | Routing table: file ↔ what it covers ↔ when to read it | — | as files are added |
| `docs/ai/decisions.md` | Retired paths + cause of death, and the permanent out-of-scope list | — | when a decision dies |
| `docs/ai/environment.md` | Lookups: hosts, ports, paths, build/run/test commands, suite map | — | when a fact costs a hunt |
| `MyMistakes.md` | Failure log + **recipes registry** (grep-first) | — | when something is learned the hard way |
| `schema.md` | The conventions above, restated for this repo | — | once |
| `<dir>/index.md` | One per code directory: file list + one-line purpose + links out | — | when layout changes |
If a file is over cap: **move detail out, never pad** — the gate fails padding.
---
## 3. What goes in each file
**`HANDOFF.md`** (≤40)
```
# HANDOFF — <date> (<one-line state>)
## State branch, worktree, unpushed commits
## Next action the single next unit, and why it is next
## Landmines live traps only — paths, flaky tests, do-not-touch rules
## Pending what is blocked on the user (checks, decisions, takes)
```
**`ai.md`** (≤100) — `# <Product> — AI guide & router`, then:
- `## What it is` — five lines max.
- `## Build, run, test` — the actual commands, plus the pointer to `environment.md`.
- `## Architecture` — one table row per top-level directory: path → role.
- `## Where the truth lives` — table: subsystem → doc → "read when".
- `## Current state` → a one-line pointer to `HANDOFF.md`. Nothing else.
**`docs/ai/<topic>.md`** — open with one line of "read when". Then observed reality only:
how it works, the traps that cost time, the measurements that settled an argument, and the
guard test that protects each rule. Date contested facts. Never re-tell the product pitch.
**`TASKS.md`** — `## Next up` (the one unit, 5 lines) · `## Queue` (one table row per item:
id, status ☐🔶⏳⏸❌, one-line scope, detail link) · `## Pending the user` · `## Release gates`.
**`decisions.md`** — one dated line per decision that no longer governs, with the reason it died,
plus the permanent out-of-scope list. Read only when about to re-open one.
**`MyMistakes.md`** — `## Recipes` first (how-to, verbatim commands, traps). Then dated failure
entries: symptom → wrong guess → actual cause → the rule that prevents it.
---
## 4. Create the gate
`scripts/scope-check.sh` — fails if any changed file is outside the declared list.
`scripts/verify.sh "<files>"` — in this order:
1. **Doc budgets**: `wc -l` every capped file, fail with "move the detail out, do not pad".
2. **Clean build**: clean first, then build; any warning fails. (Incremental "0 warnings" lies.)
3. **Tests**: full suite; a whitelist of known-flaky names, everything else is a regression.
4. **Scope check** with the passed file list.
A budget that is not a failing gate gets eaten by the next append. This is the load-bearing part.
---
## 5. First session — do this, in order
1. Ask the user for: what the product is in one paragraph, the architecture's top-level
directories, the build/run/test commands, the deployment target, and anything that must never
be violated (legal, data-loss, output-corrupting). **One question at a time.**
2. Write `AGENTS.md` §1 rules as-is, then add **the invariants**: 10–20 lines, each stating a rule
and pointing at the doc that explains it. An invariant earns its line only if violating it
breaks output, destroys user data, or creates a legal/trust breach.
3. Write `ai.md` router, `HANDOFF.md`, `TASKS.md` (empty queue), `docs/ai/index.md`,
`docs/ai/environment.md`, `decisions.md` skeleton, `MyMistakes.md` with an empty Recipes
section, `schema.md`, and `<dir>/index.md` for each directory.
4. Write the two scripts and prove the gate fires (create an over-cap file, watch it fail).
5. Commit once: "docs: project memory map + gate". Then **stop mapping and start working**.
---
## 6. Anti-patterns that killed the last map
- Appending instead of replacing — the file only grows, and stale facts outlive the code.
- One task file per task, with paragraph-length status prose — a second, worse source of truth.
- Cross-references like "TASK 3 item 17" — numbers rot; cite a path or a feature name.
- Narrative history kept inline "for context" — it is 30% of the file and read by nobody.
- Splitting into more files without a router — discovery cost just moved.
- Docs commits as units of work — the cheapest thing to produce, so it replaces real progress.
- Reading the whole map every session — a tax that trains sessions to skim.