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.
+20
View File
@@ -0,0 +1,20 @@
CC0 1.0 Universal (CC0 1.0) — Public Domain Dedication
https://creativecommons.org/publicdomain/zero/1.0/legalcode
The person who associated a work with this deed has dedicated the work to the
public domain by waiving all of his or her rights to the work worldwide under
copyright law, including all related and neighboring rights, to the extent
allowed by law.
You can copy, modify, distribute and perform the work, even for commercial
purposes, all without asking permission.
In no way are the patent or trademark rights of any person affected by CC0, nor
are the rights that other persons may have in the work or in how the work is
used, such as publicity or privacy rights.
Unless expressly stated otherwise, the person who associated a work with this
deed makes no warranties about the work, and disclaims liability for all uses of
the work, to the fullest extent permitted by applicable law.
The full legal text of CC0 1.0 Universal is at the URL above.
+63
View File
@@ -0,0 +1,63 @@
# agent-memory-seed
Seed for an AI-legible project memory map: **fork it, don't sync it.**
Copy the files into a new repo, let the AI run the first-session interview, then delete the seed
scaffolding. Every project owns its own copy from then on; improvements that prove out somewhere
get brought back here deliberately, one at a time. Never try to keep the two in lockstep.
## Why it exists
Most "AI context" files die the same death: they grow. A rules file becomes a history file, a task
list becomes a second source of truth, and every session pays to skim it — which is how stale facts
survive. This seed is small because it separates four kinds of content that have four different
read frequencies:
| Kind | Home | Read |
|---|---|---|
| Rules + invariants | `AGENTS.md` | every session |
| Subsystem truth | `docs/ai/<topic>.md` | only the one matching the task |
| Lookups (hosts, paths, commands) | `docs/ai/environment.md` | grepped, never read |
| Retired decisions | `docs/ai/decisions.md` | only when re-opening one |
Caps are enforced by `scripts/verify.sh`, not promised: a commit that pads a capped file fails.
## What's here
```
AGENTS.md the seed: rules, file map, per-file contents, first-session order
scripts/verify.sh the one gate — doc budgets, clean build, tests, scope check
scripts/scope-check.sh fails if a commit touches files outside the declared list
templates/ fill-in skeletons the AI copies into the target project
```
## Use
```bash
git clone https://<host>/<owner>/agent-memory-seed.git <new-project>
cd <new-project>
rm -rf .git && git init -b main
```
Then, as the first prompt to the AI:
> Read AGENTS.md and follow it. Ask me the first-session questions one at a time, then build the
> memory map, then delete the seed scaffolding — `templates/` and the seed sections of README.
`templates/` is input, not output: copy each skeleton to its real path (`templates/handoff.md` →
`HANDOFF.md`) and fill it in. When the map is built, remove `templates/` and rewrite this README
for the actual project.
## The parts that matter most
1. **The caps + the gate.** Everything else degrades politely; a file without a failing check
bloats silently.
2. **`HANDOFF.md` is overwritten, never appended.** History belongs to `git log`.
3. **A budget cut means moving detail out, never deleting a fact** — out to a subsystem doc, a
lookup sheet, the decisions log, or git.
Anti-patterns and the full ruleset live in [`AGENTS.md`](AGENTS.md) §1 and §6.
## License
[CC0 1.0 Universal](LICENSE) — public domain. Copy it, rename it, sell it, no attribution needed.
+57
View File
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
# scope-check.sh — Validate that git diff only touches declared files.
# Usage: ./scripts/scope-check.sh "file1.cs" "file2.cs" ...
# Exit 0 if all changed files are in scope, 1 if any are outside.
#
# Checks staged, unstaged, and untracked changes against the allowed list.
# Supports glob patterns in the allowed list (e.g. "ytLive.Tests/*").
set -euo pipefail
if [ $# -eq 0 ]; then
echo "Usage: $0 \"file1.cs\" \"file2.cs\" ..."
echo " Pass the declared file list as arguments."
exit 1
fi
# Collect allowed patterns into an array
allowed=("$@")
# Gather all changed files: working tree vs HEAD (tracked) + staged + untracked
changed=$({
git diff --name-only HEAD 2>/dev/null || true
git diff --name-only --cached 2>/dev/null || true
git ls-files --others --exclude-standard 2>/dev/null || true
} | sort -u)
if [ -z "$changed" ]; then
echo "✓ No changes detected."
exit 0
fi
violations=()
while IFS= read -r file; do
matched=false
for pattern in "${allowed[@]}"; do
if [[ "$file" == $pattern ]]; then
matched=true
break
fi
done
if [ "$matched" = false ]; then
violations+=("$file")
fi
done <<< "$changed"
if [ ${#violations[@]} -eq 0 ]; then
echo "✓ Scope check passed — all changed files are in scope."
exit 0
fi
echo "✗ SCOPE VIOLATION — the following files are outside the declared scope:"
for f in "${violations[@]}"; do
echo " - $f"
done
echo ""
echo "Either justify the edit or revert the change."
exit 1
+81
View File
@@ -0,0 +1,81 @@
#!/usr/bin/env bash
# verify.sh — the one gate before committing: doc budgets + clean build + tests + scope check.
# Usage: ./scripts/verify.sh "path/changed1" "path/changed2" ...
#
# Why a CLEAN build? An incremental build skips recompiling, so a "0 warnings" report can be a lie
# — a nullable warning slipped past exactly that way once. Clean first, then build.
#
# CONFIGURE the three commands below for the project. Empty means "skip with a warning", so a
# docs-only repo works out of the box.
set -euo pipefail
CLEAN_CMD="" # e.g. 'dotnet clean App.csproj'
BUILD_CMD="" # e.g. 'dotnet build App.csproj'
TEST_CMD="" # e.g. 'dotnet test Tests/Tests.csproj'
WARN_PATTERN=": warning" # what a compiler warning looks like in BUILD_CMD output
KNOWN_FLAKY="" # regex of pre-existing flaky test names; anything else fails the gate
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
cd "$ROOT"
echo "══ 1/4 DOC BUDGETS ══"
# The map stays cheap to read. A commit that PADS a capped file instead of moving detail out
# fails here (see AGENTS.md -> Reading budget).
check_budget() {
local rel="$1" cap="$2" lines
[ -f "$ROOT/$rel" ] || { echo " ⚠ $rel not built yet — skipped"; return 0; }
lines=$(wc -l < "$ROOT/$rel")
if [ "$lines" -gt "$cap" ]; then
echo "✗ $rel is $lines lines (cap $cap)."
echo " Move the detail to docs/ai/<topic>.md, MyMistakes.md, decisions.md or git log."
return 1
fi
printf " ✓ %-12s %3s/%s lines\n" "$rel" "$lines" "$cap"
}
budget_failed=0
check_budget "AGENTS.md" 210 || budget_failed=1
check_budget "ai.md" 100 || budget_failed=1
check_budget "HANDOFF.md" 40 || budget_failed=1
check_budget "TASKS.md" 120 || budget_failed=1
[ "$budget_failed" -eq 0 ] || exit 1
echo "══ 2/4 CLEAN BUILD (expect 0 warnings) ══"
if [ -z "$BUILD_CMD" ]; then
echo "⚠ BUILD_CMD not configured — build step skipped."
else
[ -z "$CLEAN_CMD" ] || eval "$CLEAN_CMD" > /dev/null
OUT="$(eval "$BUILD_CMD" 2>&1)"
if echo "$OUT" | grep -qI "$WARN_PATTERN"; then
echo "✗ WARNINGS FOUND:"
echo "$OUT" | grep -i "$WARN_PATTERN" | sort -u
exit 1
fi
echo "$OUT" | tail -3
echo "✓ Build clean."
fi
echo "══ 3/4 TEST SUITE ══"
if [ -z "$TEST_CMD" ]; then
echo "⚠ TEST_CMD not configured — test step skipped."
else
set +e
RUN="$(eval "$TEST_CMD" 2>&1)"
EXIT=$?
set -e
echo "$RUN" | tail -5
if [ "$EXIT" -ne 0 ]; then
if [ -n "$KNOWN_FLAKY" ] && ! echo "$RUN" | grep -iE "fail" | grep -qvE "$KNOWN_FLAKY"; then
echo "⚠ Failures, but all match the known-flaky whitelist (OK)."
else
echo "✗ TEST FAILURES — investigate."
exit 1
fi
fi
fi
echo "══ 4/4 SCOPE CHECK ══"
"$ROOT/scripts/scope-check.sh" "$@"
echo ""
echo "✓ All gates passed — safe to commit."
+30
View File
@@ -0,0 +1,30 @@
# <Product> (repo `<name>`) — AI guide & router
> Read [`AGENTS.md`](AGENTS.md) first: the rules and the invariants. This file is the **map** —
> what the product is, how it is built, and where the truth lives. No narrative, no status.
## What it is
<Five lines max: what it does, for whom, the platform, the one thing that makes it different.>
## Build, run, test
<The commands actually used. Link to docs/ai/environment.md for the full runbook.>
## Architecture
| Path | Role |
|---|---|
| `<dir>/` | <one line> |
## Where the truth lives
| Subsystem | File | Read when |
|---|---|---|
| <subsystem> | [`docs/ai/<topic>.md`](docs/ai/<topic>.md) | <the trigger> |
Lookup, not reading: [`MyMistakes.md`](MyMistakes.md) · [`TASKS.md`](TASKS.md) · `<dir>/index.md`.
## Current state
[`HANDOFF.md`](HANDOFF.md) — do not restate it here.
+12
View File
@@ -0,0 +1,12 @@
# Decisions log — retired paths, kept so they are not re-litigated
One dated line per decision that **no longer governs**, with the reason it died. Read only when
about to re-open one.
## <Domain>
- **<YYYY-MM-DD>** <decision> — superseded by <what>, because <why>.
## Out of scope — permanently
- <thing> — <the reason it will not be built, not "later">.
+10
View File
@@ -0,0 +1,10 @@
# docs/ai — index
Subsystem truth, split out so a session pays only for what its task touches. `ai.md` routes here;
`AGENTS.md` carries the invariants that hold across every subsystem.
| File | Covers | Read when |
|---|---|---|
| [`environment.md`](environment.md) | Hosts, ports, paths, build/run/test commands, test map | building, running, adding a test |
| [`decisions.md`](decisions.md) | Retired paths with cause of death; the permanent out-of-scope list | about to re-open a settled decision |
| <topic>.md | <subsystem> | <trigger> |
+34
View File
@@ -0,0 +1,34 @@
# Environment — lookups
Facts you grep for, never read start to finish. Add a line the first time one costs a hunt.
## Hosts & access
| Host | Address | Role |
|---|---|---|
| <host> | <ip> | <role> |
SSH / credentials: <where they live, never in this repo>.
## Build, run, test
```bash
<clean command>
<build command>
<run command>
<test command>
```
<The traps: which toolchain, which host, why not the other one. Notes on warnings, restores, caches.>
## Paths
- App data / config: `<path>`
- Logs: `<path>` (rotation: <rule>)
- Build output / artifacts: `<path>`
## Test map
| Area | Test file | Notes |
|---|---|---|
| <area> | `<file>` | <known flaky? slow? needs env?> |
+18
View File
@@ -0,0 +1,18 @@
# HANDOFF — <YYYY-MM-DD> (<one-line state>)
## State
- Branch `<branch>`, worktree <clean / N files dirty>, **<pushed|unpushed>** (`<last sha>`).
- In flight: <the unit that is partially done, if any — file names and what is left>.
## Next action
<The single next unit, one sentence on why it is next. Nothing else.>
## Landmines (live, not historical)
- <path / port / flaky test / do-not-touch rule — one line each, only what would bite today.>
## Pending the user
- <decision, hands-on check, or measurement that is blocked on them>
+9
View File
@@ -0,0 +1,9 @@
# <dir> — index
One line on what this directory owns, then every file with its purpose. Details live in the files.
| File | Purpose |
|---|---|
| `<File>` | <what it does, one line> |
Related: [`../other/index.md`](../other/index.md)
+23
View File
@@ -0,0 +1,23 @@
# MyMistakes — failure log + recipes
## Recipes (grep here FIRST)
<How-tos and workarounds, with verbatim commands. A solution recorded once ends the loop;
an un-recorded one guarantees the same wall twice.>
### <Recipe name>
```bash
<exact commands>
```
Traps: <the two or three things that actually go wrong>.
## Failure log (newest first)
### <YYYY-MM-DD> — <symptom in six words>
- **Symptom:** <what was observed>
- **Wrong guess:** <what was tried, and why it looked right>
- **Actual cause:** <the mechanism>
- **Rule now:** <what prevents the repeat — and where it is written down>
+35
View File
@@ -0,0 +1,35 @@
# Memory map — conventions
## Why files, not a database
Grep-able, diffable, human-editable, portable; git gives versioning and history for free. Files
form a graph: each file is a node, each relative link an edge.
## Inventory
| File | Role | Entry point? |
|---|---|---|
| `AGENTS.md` | Rules + invariants | **always read** |
| `ai.md` | Router: product, build, architecture, where truth lives | yes |
| `HANDOFF.md` | Current state (≤40 lines, overwritten) | yes |
| `TASKS.md` | Active queue | when asking "what's next" |
| `docs/ai/*.md` | Subsystem truth, one file each | when the task touches it |
| `MyMistakes.md` | Failure log + recipes | grep first |
## Rules
1. **Semantic filenames.** No codes, no abbreviations.
2. **One `index.md` per code directory**, listing every file with a one-line purpose.
3. **Links over hierarchy.** Anything unreachable from `ai.md` may as well not exist.
4. **Stale facts get fixed, not appended.**
5. **Progressive disclosure.** Detail lives one level down, never crammed into the router.
## Reading order
1. `AGENTS.md` → 2. `HANDOFF.md` → 3. `ai.md` → 4. the one `docs/ai/<topic>.md` → 5. `<dir>/index.md`
→ 6. the source (always the authority over any memory file).
## Integration rule
Every change ships with the facts it **falsifies** corrected, in the same commit. Broader
restatement may be batched at a milestone.
+22
View File
@@ -0,0 +1,22 @@
# TASKS — the active queue
> One line per live item; detail lives elsewhere. Done work goes to [`TASKS/archive.md`](TASKS/archive.md).
> Markers: ☐ queued · 🔶 in progress · ⏳ blocked · ⏸ deferred · ❌ retired.
## Next up
**<Task>** — <five lines: what exists today, what is missing, the one unit, its test.>
## Queue
| Task | Status | Scope | Detail |
|---|---|---|---|
| <id> | ☐ | <one line> | <link> |
## Pending the user (not programming)
- <hands-on check / decision / take>
## Release gates (before the first shipped build)
- <gate — one line each>