# Project Setup

> Scaffolds the repo ecosystem every achilles skill assumes — a one-time bootstrap that creates the STATE.md board, the CONTEXT.md glossary, docs/adr/, docs/features/, docs/session-state.md (the five-field snapshot of where the work stands), docs/session-log.md (the separate append-only record of decisions a resuming session reads before re-opening a question), docs/progress.md (the run record — what each slice actually executed, appended to and never rewritten, scaffolded with the entry shape and no entries), and docs/lessons.md (the lessons record — what a root-caused defect turned out to be and the guard that would catch it coming back, appended to and never rewritten, scaffolded with the field template and no entries), and the `## Agent skills` block in one of CLAUDE.md / AGENTS.md plus a short pointer to it in the other — and, when the repo has neither and you opt to create CLAUDE.md, seeds it from a bundled behavioral template. Run this ONCE before the first feature, before interview-me or spec-grilling.

- Skill: `celestialdust/project-setup` (Agent Skill, multi-file: 3 files)
- Install (CLI): `npx skillmds@latest add celestialdust/project-setup`
- Raw SKILL.md: https://api.skillmd.com/api/skills/celestialdust/project-setup/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: celestialdust (https://skillmd.com/u/celestialdust)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/celestialdust/project-setup

---


## Purpose

Stage: **cross-cutting / setup** (one-time). Every downstream skill reads and writes a *shared substrate*:
the `STATE.md` board (what's in flight + who owns the next action), the per-feature artifact directories,
the repo-wide design substrate (`CONTEXT.md` glossary + `docs/adr/`), the session state
(`docs/session-state.md` — the snapshot of where the work stands; `docs/session-log.md` — the append-only log of decisions a resuming
session reads first), the run record
(`docs/progress.md` — what each slice actually executed, one entry per slice), the lessons record
(`docs/lessons.md` — what each root-caused defect turned out to be, and the guard that would catch it
coming back), and the rules file that carries the `## Agent skills` block, with a pointer to it in
whichever of `CLAUDE.md` / `AGENTS.md` does not hold it. If that substrate doesn't exist, each skill has to re-derive "where do issues live / where's
the glossary / where do ADRs go" — which is exactly the scattered-tracker problem this suite consolidates
away (one local board, not mp's several issue queues). `project-setup` makes the substrate exist **once**, so the rest of the suite consumes it cold.

This is a prompt-driven skill, not a deterministic script. Explore, present what you found, confirm with
the user, then write. It is **distinct from `preflight-readiness`**: `preflight-readiness` is a per-run environment gate that
re-fires every wave; `project-setup` is the one-time repo bootstrap that runs before any feature exists.

## When to use / when to skip

- **Use** once per repo, before the first feature — before `interview-me`, `idea-refine`, or `spec-grilling`.
- **Skip** if `STATE.md` already exists at the repo root and the substrate is intact; you don't need to
  re-run per feature (the board is appended to by `plan-breakdown`, not re-scaffolded).
- **Re-run to repair** when a substrate file has gone missing or stopped resolving — including a
  `CLAUDE.md` / `AGENTS.md` pointer naming a file that is no longer there. Nothing watches for that
  between runs, so the pointer check under "Verification" is what catches it, and it only runs here.
- **Escape hatch — adopt, don't overwrite:** if the repo already has a `CONTEXT.md`,
  `docs/session-state.md`, `docs/session-log.md`, `docs/progress.md`, `docs/lessons.md`, `docs/adr/`, or a
  `CLAUDE.md`/`AGENTS.md` with prior content, adopt them in place. Re-running `project-setup` repairs missing pieces;
  it never clobbers existing user content. The three append-only files matter most here: every entry in
  `docs/session-log.md`, in `docs/progress.md`, and in `docs/lessons.md` exists nowhere else, so
  re-scaffolding over any of them deletes reasoning and evidence nobody can recover.

## Inputs

Foundation only — this is the bootstrap; it has no upstream artifact and no refuse-to-run dependency. It
reads the repo as-is to decide what already exists:

- `git remote -v` / `.git/config` — is there a remote? (informational only; the tracker is local regardless.)
- root `CLAUDE.md` and `AGENTS.md` — does either exist? Is there already an `## Agent skills` section?
- root `CONTEXT.md` / `CONTEXT-MAP.md` — single- or multi-context already?
- `docs/adr/`, `docs/features/`, `docs/session-state.md`, `docs/session-log.md`, `docs/progress.md`, `docs/lessons.md`,
  `STATE.md` — does prior output already exist?
- `.gitignore` — does any pattern in it match `docs/session-state.md`, `docs/session-log.md`, `docs/progress.md`, or
  `docs/lessons.md`? All three have to be committed.

## Process

### 1. Explore

Look at the current repo to understand its starting state. Read whatever exists; don't assume:

- `git remote -v` and `.git/config` — is this a remote-backed repo? (Informational — does not change the tracker.)
- `CLAUDE.md` and `AGENTS.md` at the repo root — does either exist? Is there already an `## Agent skills` section?
- `CONTEXT.md` and `CONTEXT-MAP.md` at the repo root — is a single- or multi-context layout already implied?
- `docs/adr/` and any `src/*/docs/adr/` directories.
- `docs/features/`, `docs/session-state.md`, `docs/session-log.md`, `docs/progress.md`, `docs/lessons.md`, and `STATE.md`
  — does this skill's prior output already exist?
- `.gitignore` — is `docs/session-state.md`, `docs/session-log.md`, `docs/progress.md`, or `docs/lessons.md` matched by anything
  in it? All three exist to survive the session that wrote them, so an ignored copy dies on the next fresh
  clone.

### 2. Present findings and ask

Summarise what's present and what's missing. Then walk the user through the decisions **one at a time** —
present a section, get the answer, then move on. Don't dump everything at once.

Assume the user does not know what these terms mean. Each section starts with a short explainer (what it is,
why these skills need it, what changes if they pick differently), then the choices and the default.

**There is no issue-tracker question.** In this suite the tracker is **always** the local `STATE.md` board:
a two-level board (features → slices) with a `gate` column that absorbs mp's
`ready-for-agent`/`ready-for-human` triage roles. So the source's GitHub/GitLab/local choice and its
five-label vocabulary are **already decided** — you scaffold `STATE.md`, you do not ask where issues live.
Mention this once so the user knows their GitHub Issues (if any) are intentionally not the work surface here.

**Section A — Domain doc layout** (the one surviving choice).

> Explainer: Several skills (`spec-grilling`, `code-review`, `quality-verification`, `incremental-implementation`) read `CONTEXT.md` for the
> project's domain language and `docs/adr/` for past architectural decisions. They need to know whether the
> repo has one global context or several (e.g. a monorepo with separate frontend/backend contexts) so they
> look in the right place.

- **Single-context** — one `CONTEXT.md` + `docs/adr/` at the repo root. Most repos are this. **(Default.)**
- **Multi-context** — `CONTEXT-MAP.md` at the root pointing to per-context `CONTEXT.md` files (a monorepo).

If **neither** `CLAUDE.md` nor `AGENTS.md` exists, also ask **which one holds the rules** — don't pick for
them. Both filenames end up existing either way: the one they pick gets the `## Agent skills` wiring, and
the other gets a short pointer to it, so a contributor whose tool reads that other name is not left
with nothing. Note that a fresh `CLAUDE.md` is seeded with a small set of project-agnostic behavioral
guidelines (the bundled `assets/CLAUDE.template.md`) above the `## Agent skills` wiring; a fresh
`AGENTS.md` gets the wiring only.

### 3. Confirm and edit

Show the user a draft of everything before writing, and let them edit:

- The `STATE.md` skeleton (the empty board with the legend; see "STATE.md seed" below).
- The `CONTEXT.md` stub (glossary-only).
- The `docs/session-state.md` stub (empty fields; see "session-state.md seed" below) and the
  `docs/session-log.md` stub (the preamble and entry shape, no entries; see "session-log.md seed" below).
  Say what each is for and why they are two files: the five fields are a snapshot of where the work
  stands, rewritten each time and therefore always short; the log is an append-only record of decisions —
  the reason, what was ruled out, what is still open — that only ever grows. Kept together, the half that
  grows without limit sits under the half every session must read. Both are committed, so they survive the
  session that wrote them.
- The `docs/progress.md` stub (the entry shape, no entries; see "progress.md seed" below). Say what it is
  for while you show it: one entry per slice recording what that slice actually executed — the commands,
  their real output, the files that changed, and what was not run. A run's own summary is otherwise the
  only account of itself, and a summary is written by the party with the most reason to round up.
- The `docs/lessons.md` stub (the field template, no entries; see "lessons.md seed" below). Say what it is
  for while you show it: one entry per root-caused defect, and every entry names the guard that would catch
  that defect coming back. A slice reads the file before it writes its skeleton, which is the moment the
  knowledge is worth anything — read afterwards, a lesson is a post-mortem of work already done.
- The `## Agent skills` block to add to whichever of `CLAUDE.md` / `AGENTS.md` is being edited.
- The pointer that goes in the *other* filename (see "pointer seed" below) — it names the file that holds
  the rules, and says nothing else.
- If a fresh `CLAUDE.md` is being created, the bundled behavioral template (`assets/CLAUDE.template.md`) that
  seeds it — the user can edit it now or later (it's a starting point, not a fixed contract).

### 4. Write

**Pick the file that holds the rules (verbatim file-selection rules):**

- If `CLAUDE.md` exists, edit it.
- Else if `AGENTS.md` exists, edit it.
- If neither exists, create the one the user chose in Section A — never pick for them.
- **Never write the rules into both.** Exactly one file gets the `## Agent skills` block — the one already
  there, or the one the user chose. The other never gets a copy of it: two copies drift apart, and a reader
  has no way to tell which one is lying. If an `## Agent skills` block already exists, update it in place
  rather than appending a duplicate; don't overwrite the surrounding sections.
- **Then create the other filename as a pointer.** Once the `## Agent skills` block has landed, write the
  pointer (see "pointer seed" below) into whichever of `CLAUDE.md` / `AGENTS.md` does not hold it.
  The pointer names the file that does, and says nothing else. Without it, a contributor whose tool reads
  only that filename opens an empty file or none at all. If the file already exists with content of its own,
  do not overwrite it — show the user the pointer line, ask before adding it at the top, and either way say
  plainly which file holds the rules. If they decline it, say what that leaves: their tool opens a file
  that does not route anywhere, and finding the rules is now on whoever reads it. That is theirs to accept,
  and it is the one branch where the pointer does not exist.
- **Seeding a fresh `CLAUDE.md`:** only when neither file exists and the user chose `CLAUDE.md`, write the
  bundled behavioral template (`assets/CLAUDE.template.md`) first, then append the `## Agent skills` block
  below it (see "CLAUDE.md seed" below). A fresh `AGENTS.md` chosen as the rules file gets the
  `## Agent skills` block only — no behavioral template. Never seed over a `CLAUDE.md` that already exists;
  edit it in place.

Then create the substrate (skip anything that already exists; never clobber).

1. **`STATE.md`** at the repo root — the empty two-level board with the legend (see seed below).
2. **`CONTEXT.md`** at the repo root (or `CONTEXT-MAP.md` + per-context `CONTEXT.md` for multi-context) —
   the glossary stub with a `## Glossary` heading, devoid of implementation detail (see "CONTEXT.md
   seed" below). The `## Glossary` heading is mandatory — `spec-grilling` appends terms under it.
3. **`docs/adr/`** — repo-wide ADR home (seed a `.gitkeep`; ADRs are named `ADR-<NNN>-<slug>.md`).
4. **`docs/features/`** — per-feature artifact root (`docs/features/<slug>/` holds intent.md, prd.md,
   acceptance.md, environment.md, plan.md per feature; seed a `.gitkeep`).
5. The **`## Agent skills`** block in the chosen file (see below), pointing at `STATE.md`, `CONTEXT.md`,
   `docs/adr/`, `docs/session-state.md`, `docs/session-log.md`, `docs/progress.md`,
   and `docs/lessons.md`, and **naming** `docs/design.md` — which setup does not create; the first UI
   surface writes it. The domain-doc consumer rules carry over from `references/domain-docs.md`. Then the **pointer** in the other filename
   (see "pointer seed" below), naming the file that holds the block.
6. **`docs/session-state.md`** — where the work stands, seeded with **five empty fields** (see
   "session-state.md seed" below), and **`docs/session-log.md`** — why it stands there, seeded with its
   **preamble and no entries** (see "session-log.md seed" below). Skip either if it already exists — and
   for the log skipping is not a courtesy, it is the only safe move: it is append-only, so overwriting one
   destroys decisions that exist nowhere else. Seed no entries; entries are written by `handoff` as
   decisions get made.

   **Check `.gitignore` and make sure nothing matches either.** Both are committed on purpose. Their whole
   job is to outlive the session that wrote them, and an ignored copy dies on the next fresh clone — which
   is precisely the case they exist for. If a pattern does match one, say so and ask before changing
   `.gitignore`; that file is the user's.

7. **`docs/progress.md`** — the run record, seeded with the **entry shape and no entries** (see
   "progress.md seed" below). Skip it if it already exists, and here — as with the session log directly
   above — skipping is the only safe move rather than a courtesy: it is append-only, so overwriting one
   destroys the only account of what earlier runs actually did. Seed no entries; entries are written by
   the skill that runs a slice, one per slice, as slices run.

   **Check `.gitignore` here too.** A record nobody commits is a record nobody reads: the question it
   answers — what did the last run really do — is asked by someone who was not present, most often on a
   fresh clone. If a pattern matches it, say so and ask before changing `.gitignore`; that file is the
   user's.

   You are scaffolding this file in the repository itself, not in a worktree — `project-setup` runs once,
   before any feature exists, so there is no slice branch for a write to get stranded on.

8. **`docs/lessons.md`** — the lessons record, seeded with its `## Entry shape` heading, the fenced field
    template beneath it, and the prose that states the rules every writer of an entry reads there (see
    "lessons.md seed" below). Seed no entries: every `##` heading after `## Entry shape` is somebody
    else's, written by whoever root-causes a defect, by `code-review` for a `Critical:` finding it raised,
    and by the `orchestrator` carrying back an entry a slice handed it. Skip the file if it already
    exists, for the same reason as the two above and with the same force: it is
    append-only, so overwriting one destroys what earlier defects cost somebody to work out.

    **Check `.gitignore` here too.** A lesson is written for the next person to work in that area, who is
    usually not the person who wrote it and often arrives on a fresh clone. If a pattern matches it, say so
    and ask before changing `.gitignore`; that file is the user's.

The `## Agent skills` block:

```markdown
## Agent skills

This repo is configured for the achilles-skills pipeline (run once by `project-setup`).

### State board
Work-in-flight lives in `STATE.md` at the repo root — a local two-level board (features → slices) with a
`gate` column marking who owns the next action. This is the only work tracker; there is no GitHub/GitLab
issue queue. See `STATE.md`.

### Domain docs
Single-context: `CONTEXT.md` + `docs/adr/` at the root. (Multi-context: `CONTEXT-MAP.md` → per-context
`CONTEXT.md`.) Skills read these before exploring; consumer rules in the project-setup skill's
`references/domain-docs.md`.

### Per-feature artifacts
Each feature's intent.md / prd.md / acceptance.md / environment.md / architecture.md /
architecture.html / plan.md live under `docs/features/<slug>/`, with each slice's concrete
steps in `docs/features/<slug>/plan/<slice-id>.md`.

### Code comments and docstrings
Explain the code to the developer reading it. A docstring that points at a spec instead of
explaining — `Implements US-3`, `see prd.md`, `per plan.md step 2` — leaves the next reader
no better off, and those files move as the feature moves while the code stays. Say what it
does, why it is built this way where that is not obvious, and which invariants it assumes. A
`docs/adr/` record may be cited **after** the explanation as provenance, never in place of it;
ADRs are immutable once written, which is why a citation to one keeps being true.

### Decided look
`docs/design.md` holds this repo's look once it is decided: the palette, the type, the layout language,
the motion posture, and the signature vocabulary every interface here shares. The **first** user interface
built in this repo writes it; every later one starts from it and records only what differs. Nothing
scaffolds it — a repo with no user interface has none, and that is correct rather than missing.

### Session state and decision log
Two files, because they grow differently. `docs/session-state.md` is the snapshot — five fields saying
where the work stands, rewritten each time, so it stays short no matter how long the project runs.
`docs/session-log.md` is the record — an append-only account of decisions, the reason, what was ruled out,
what is still open — and it only ever grows. Kept in one file, the record buries the snapshot every
session must read; kept apart, the log can grow for the life of the project without taxing anyone.

**Read the snapshot before starting work**, at the top of every session, and **read the log before
re-opening any question**, so one it already answers is not argued twice. The log is append-only: earlier
entries are never edited, re-ordered, or deleted, a wrong entry is corrected by a new entry naming it, and
an attempt to change one is reported as a violation rather than quietly refused. Entries hold only what
the git history cannot show — never which files changed. It is the weakest source here: a decision record
under `docs/adr/` or a signed `acceptance.md` outranks it, and a decision that must bind future work is
promoted to `docs/adr/`.

### Run record
`docs/progress.md` records what each slice actually executed: one entry per slice, carrying the commands
in the form they were run, their real output, the files that changed, and what was **not** run and why.

**Read it when you resume work you were not present for**, alongside the two files above. The board says
where things stand, the log says why, and this says what was actually done — a claim that a check passed
either has the command's output under it or says the check was not run, and there is no third state.

It is append-only on the same terms as `docs/session-log.md`, and it is evidence rather than a status page: no entry
carries a stage, a state, or an owner. `STATE.md` answers who owns the next action, and a second answer
here would eventually disagree with it.

### Lessons
`docs/lessons.md` holds what a root-caused defect turned out to be: one entry per defect, seven fields
each, naming the guard that would catch it coming back.

**Read it before building a slice**, so a pit somebody has already fallen into is not fallen into twice.
It is append-only on the same terms as `docs/session-log.md`. The same defect recurring is a second entry, never an
edit to the first — the count is the signal that the first guard did not hold, and folding two entries
together destroys it.

### Keeping these files worth reading
Every file above is read by somebody who has none of your context, at the moment they decide what to do
next. That is what they are for, and it is also the whole constraint on them: **a line earns its place by
changing what a cold reader would do.** A line that records merely that work happened changes nothing —
git holds that already, exactly — and a second copy of a derivable fact is free to disagree with its
source, leaving a reader no way to tell which one is lying.

So the test, before writing any line into any of them: *would somebody who just arrived act differently
for having read this?* If not, it does not go in. What that means file by file:

- **`STATE.md`** — tokens and short phrases in cells, never sentences. It is a board: where each slice
  is, and who owns the next move. *Why* a slice is where it is belongs in `docs/progress.md`; what got
  decided belongs in the log. A cell holding a paragraph is a board nobody can read across.
- **`docs/session-state.md`, the five fields** — where the work stands **now**, in the fewest words that
  let a person resume without asking a question. They are overwritten every time, so nothing in them is
  history: last session's state is not context, it is noise with a timestamp.
- **`docs/session-log.md`** — one entry per **decision**, in the four lines the entry shape
  gives it, one sentence per line. Not one per session, not one per turn, not one per file touched. A
  session that decided nothing appends nothing, and that is a correct outcome rather than a missing entry.
- **`docs/progress.md`** — the commands as they ran, and the output that settles whether each passed.
  Quote what a reader needs in order to believe the claim, not the whole scroll, and say what was not run.
- **`docs/lessons.md`** — one entry per **root-caused** defect, seven fields, and a named guard. An
  observation with no guard behind it is a preference, and preferences are what fill a file like this
  until nobody reads it.
- **`CONTEXT.md`** — one definition per domain term, in the language of the domain, with no
  implementation detail. A term already defined is sharpened in place, never defined a second time.

**The cure is at the point of writing, never at the point of reading.** These records are append-only for
a reason: what grows with decisions grows with work, and trimming it deletes the evidence somebody will
need. A file that has become too long to skim was not written too much — it was *admitted* too much. The
fix is the next line you are about to add, not the hundred already there.
```

### 5. Done

Tell the user setup is complete and which skills now read from these files (`spec-grilling` appends
`CONTEXT.md` and writes `docs/adr/`; `interview-me`/`idea-refine` write `docs/features/<slug>/intent.md`;
`plan-breakdown` adds feature blocks + slice rows to `STATE.md`; the orchestrator drives `STATE.md`;
`handoff` writes `docs/session-state.md` and appends to `docs/session-log.md`; whichever skill runs a slice —
`incremental-implementation` on its own, or the `orchestrator` when a run drives it — appends that slice's
entry to `docs/progress.md`; `debugging-and-error-recovery` appends a `docs/lessons.md` entry whenever a
defect is root-caused, `code-review` appends one for a Critical finding and for nothing lesser, and the
`orchestrator` appends the entries slices hand back, from the checkout it holds rather than from theirs).
Say which of `CLAUDE.md` / `AGENTS.md` holds the rules and that the other is a pointer to it, so a
contributor on the other tool lands in the right place. A rule change goes in the rules file; the pointer
never gets a copy of it.
Say what the two session files are for too: `docs/session-state.md` is a snapshot and
`docs/session-log.md` is a record, and the log is append-only — nothing in it is ever edited or deleted,
so it can be trusted as evidence rather than read as a status page. They are separate files so the record
never buries the snapshot. Both are committed so they survive a fresh clone; leaving either out of version
control defeats it.
Say the same about `docs/progress.md`, and say what it is not: it records what each slice ran and what
came back, and it never says which stage a slice is at or who owns the next action — that is the board's
question, and one question with two answers is one answer too many. It is append-only and committed for
the same reasons.
Say what `docs/lessons.md` is for as well: one entry per root-caused defect, each naming the guard that
would catch it coming back, read before a slice is built rather than after. It is append-only and committed
on the same terms, and the same defect recurring is a second entry — the count is the signal that the first
guard did not hold, and folding the two together destroys it.
Mention that `STATE.md`, `CONTEXT.md`, the five fields of `docs/session-state.md`, and the per-feature
docs are theirs to hand-edit later — `docs/session-log.md`, `docs/progress.md`, and `docs/lessons.md` being the
exceptions, since correcting an entry in any of them means appending a new one rather than changing the
old one. Re-running `project-setup` is only needed to repair or re-scaffold a substrate file that has
gone missing.

## STATE.md seed

Write this empty board — the legend header is the stable section downstream consumers depend on; no feature
blocks yet (those are born from an already-sliced plan, added by `plan-breakdown`):

```markdown
# Pipeline State — <project>

> Single source of truth for what's in flight. The orchestrator drives slice rows; the human reads the
> `gate` column to know what needs them. No emojis; text tokens only.
>
> Cells hold tokens and short phrases, never sentences — this is a board, and it is read across rather
> than down. Why a slice is where it is goes in `docs/progress.md`; what got decided goes in
> `docs/session-log.md`. A row whose cell has grown into a paragraph has taken on another
> file's job, and the board stops being skimmable at exactly the moment there is enough work to need it.

feature state:  spec · plan · building · done          ← the PRD's stage
slice state:    impl · verify · review · ship · done · blocked · halted
gate:           you · agent · done                     ← who owns the next action

<!-- Feature blocks are added by plan-breakdown. Slice ids are PRD-namespaced. Example shape:

## PWR · Password reset                          feature: building
origin:  prd.md · acceptance.md · plan.md
| Slice  | Title              | Design ref                     | State   | Gate  | Blocked by | Artifacts |
|--------|--------------------|--------------------------------|---------|-------|-----------|-----------|
| PWR-1  | request reset link | `docs/features/pwr/design-contract.md` | impl | agent | —      | —         |
| PWR-2  | expire stale tokens| —                              | impl    | agent | PWR-1     | —         |
-->
```

`Design ref` holds the signed design contract + prototype the slice builds against, or `—` for a slice that
builds no UI. The orchestrator copies it into both the implement and the verify dispatch brief, so a `—` has
to be recorded rather than left blank — blank reads as "nobody looked".

## CONTEXT.md seed

Write this glossary stub — the `## Glossary` heading is the stable section `spec-grilling` appends terms
under (canonical heading; do not rename); no terms yet (those emerge as the ubiquitous language is
sharpened). The seed comment states the entry shape rather than inventing one: `spec-grilling`'s
`references/CONTEXT-FORMAT.md` is what the appender writes to, so a seed describing a different shape
opens a file whose first entries disagree with every entry appended after them.

```markdown
# <project>

## Glossary

<!-- Domain terms are appended here by spec-grilling as the ubiquitous language emerges.
One entry per term: the term in bold on its own line, its one-or-two-sentence definition
beneath it. No implementation detail. Group with ### subheadings once clusters emerge —
never with a second ## section, which splits the glossary in two. -->
```

For multi-context, seed `CONTEXT-MAP.md` at the root plus one per-context `CONTEXT.md`, each carrying its
own `## Glossary` heading.

## session-state.md seed

Write this stub at `docs/session-state.md` — five empty fields and the pointer to the log. The five field
headings are the stable sections consumers depend on (canonical headings; do not rename). The file holds
**no log entries and no `## Log` heading**; the record is `docs/session-log.md`, seeded separately below.

```markdown
# Session state

Where the work stands, right now. Every field below is a **snapshot** — overwritten each time this file
is written, so only the latest version is true and nothing here is history.

Why the work stands here, and which questions are already settled, is the record:
**`docs/session-log.md`** (append-only). Read this file before starting work, and read the log before
re-opening any question — one it already answers does not get argued from zero.

The two are separate files because they grow differently. This one is rewritten, so it stays short. The
log only ever grows, and underneath a snapshot it would bury the twelve lines every session came for.

## Current objective

## Current state

## Remaining issues

## Boundaries

## Next phase
```

Fill in none of the five fields — they are written by `handoff` when there is actually a session to
record.

`handoff` also adds `## Suggested skills` and `## Referenced artifacts` after `## Next phase` the first
time it writes the file. The seed leaves them out because there is nothing to point at yet.

## session-log.md seed

Write this stub at `docs/session-log.md` — the preamble and the entry shape, no entries. The explanation
is part of the seed: an append-only file is only append-only if the next person to open it can tell that
from the file.

```markdown
# Session log

Why the work stands where it does. One entry per **decision**, appended and never edited, so every entry
stays true about the moment it was written. Where the work stands *now* is the snapshot:
`docs/session-state.md`.

Append-only. A new entry goes after the last one. Earlier entries are never edited, re-worded, re-dated,
re-ordered, or removed. An entry that turned out to be wrong is corrected by a **new** entry naming the
old one — that the call was once made that way is the fact worth keeping. An attempt to change or remove
an earlier entry is **reported as a violation**, naming the entry and what would have changed; refusing
quietly is not enough, because a silent refusal reads as a silent success.

An entry holds only what the git history cannot show: the decision, the reason, what was ruled out, and
what is still open — **one sentence each, four lines, no fifth.** Never which files changed or what was
added; git holds that exactly, and a second copy of a derivable fact can disagree with its source,
leaving a reader no way to tell which one is lying.

An entry records a **decision**, not that work happened. The test is whether a later session, not knowing
it, would re-open the question. A slice landing, a test going green, a plan step taken — none of those
are decisions, and what a run executed belongs in `docs/progress.md`. Most sessions append zero or one
entry, and a session that decided nothing appends nothing.

This is the weakest source in the repo. It never overrides a decision record under `docs/adr/` or a
signed `acceptance.md`; where they disagree, the committed contract is right and the entry is stale. A
decision that has to bind future work is **promoted** to a decision record under `docs/adr/`; the
original entry is left as it is, and a new entry names both it and the record it became.

Entries are kept, not compacted. They grow with decisions, and decisions are work; compaction is for
what grows with elapsed time. And this file is committed, not ignored — its whole purpose is to outlive
the session that wrote it.

<!-- Entry shape. Append below, oldest first:

### <date> — <one line: what was decided>
Decided: <the call>
Because: <the reason>
Ruled out: <the alternative, and why not>
Still open: <what this did not settle, or "nothing">
-->
```

Seed no entries — they are written by `handoff` as decisions get made. A seeded entry is a decision
nobody made.

## progress.md seed

Write this stub at `docs/progress.md` — the entry shape and no entries. `## Entry shape` is the one
heading the seed ships (canonical heading; do not rename); every other `##` heading in the file is an
entry, and entries are appended after it, oldest first. The shape itself sits inside a fenced block,
which is what keeps it from reading as the first entry. The explanation is part of the seed, for the
same reason it is part of `docs/session-log.md`: an append-only file is only append-only if the next
person to open it can tell that from the file.

`````markdown
# Run record

What each slice actually executed. One entry per slice, appended when the slice starts and completed
when it returns.

This file exists because a run's own summary is otherwise the only account of itself, and a summary is
written by the party with the most reason to round up. An entry is evidence: the commands in the form
they were run, and what came back from them.

**It never says where the work stands.** No entry carries a stage, a state, or an owner — `STATE.md`
answers who owns the next action, and a second answer here would eventually disagree with it. Reading
this file will not tell you which slice is waiting on a person, and that is deliberate rather than
missing.

**Append-only.** A new entry goes after the last one. Earlier entries are never edited, re-worded,
re-dated, re-ordered, or removed — including an entry that recorded a failure the next attempt fixed.
The same failure twice is two entries; the second never replaces the first. An entry that turned out to
be wrong is corrected by a **new** entry naming the old one. An attempt to change or remove an earlier
one is a **STOP**: the work ends there, and the violation is reported, naming the entry and what would
have changed. Refusing quietly is not enough — a silent refusal reads as a silent success, and the text
already recorded stays readable in full either way.

**A heading with nothing under it is a slice that started and did not finish.** It is written the moment
the slice starts, before anything can go wrong with it, so a slice that dies mid-flight still leaves a
mark. That is not the same as a slice that was never started, which has no heading at all. Leave it as
it is; the missing fields are the record.

## Entry shape

Append below, oldest first:

```
## <date> — <SLICE-ID> — <title>
- Summary:
- Commands run:            (verbatim, one per line)
- Results:                 (the output lines that settle whether it passed — the counts, the failure
                            signature, the exit status — quoted exactly. Not the whole scroll: an
                            entry a reader scrolls past is evidence nobody checked)
- Files changed:
- Not run:                 (what was skipped, and why — never omit this line)
- Follow-ups:

Do not claim a command was run if it was not run. Write it under "Not run" and say why.
Withhold any credential that appears in output, and say that you withheld it.
```

Nothing checks those last two lines. They are written here, next to the shape, because this is what
the writer is looking at when the temptation arises.
`````

The last two lines of the shape are the whole point of the file and nothing mechanical enforces them, so
do not add a claim that something does. A "Not run" line that is present and honest is what separates a
check that passed from a check nobody performed; without it, the two read identically.

Seed no entries. An entry is a record of work somebody did, so a seeded one is fiction of exactly the
kind this file exists to prevent — the same reason `docs/session-log.md` ships with no entries.

## lessons.md seed

Write this stub at `docs/lessons.md` — the field template and no entries. `## Entry shape` is the one
heading the seed ships (canonical heading; do not rename); every other `##` heading in the file is an
entry, and entries are appended after it, oldest first. The template sits inside a fenced block, which is
what keeps it from reading as the first entry. The explanation is part of the seed for the same reason it
is part of the other two append-only files: the rules are only followed if the next person to open the
file can read them there.

`````markdown
# Lessons

What a defect turned out to be, so the same pit is not fallen into twice. One entry per root-caused
defect, appended once the cause is known and the fix is in.

**Read it before you build.** A slice reads this file before it writes its skeleton. That is the moment
the knowledge is worth anything: the skeleton is where the decisions these entries are about get made,
and a lesson read after the code is written is a post-mortem of work already done.

**Every entry names a guard.** `Automated guard` says what would catch this defect coming back — a lint
rule, a test, a helper that makes the mistake unavailable, a checklist item, or an architecture
invariant. It is filled in as the entry is written, by whoever root-caused the defect and is the only
person who knows what would have caught it. An entry naming none is **refused**: a lesson nobody can name
a guard for is a preference, and preferences are what fill a file like this until nobody reads it.

**Append-only.** A new entry goes after the last one. Earlier entries are never edited, re-worded,
re-dated, re-ordered, or removed. An entry that turned out to be wrong is corrected by a **new** entry
naming the old one. An attempt to change or remove an earlier entry is a **STOP**: the work ends there,
and the violation is reported, naming the entry and what would have changed. Refusing quietly is not
enough — a silent refusal reads as a silent success.

**The same lesson twice is two entries.** A defect whose category is already in the file is recorded
again rather than folded into the entry already there. The count is the signal: a category appearing a
second time says the first guard did not hold, which is the one thing a reader most needs to know.
Merging the two destroys the only evidence of it.

**Three parties write here, and they write different entries.** Whoever root-causes a defect writes one.
A review writes one only for its most serious class of finding — a `Critical:` finding, once root-caused.
A Required or lesser finding is refused here and stays in that review's findings list, where it is
already tracked; admitting those would make this file a second copy of every review.

**The third is a courier, not an author.** An entry written from inside a slice's own checkout lands on a
branch that may never merge, so a slice hands its finished entry back and the run that drove it appends
the entry here, from the checkout the run itself holds. The courier carries what it was handed and infers
nothing from silence: a slice that hands back nothing has nothing appended for it.

## Entry shape

Append below, oldest first:

```
## <date> — <one line: what the defect turned out to be>
- Tags:              (the area, so a later reader finds the others like it — and can count them)
- Symptom:           (what was observed, in the form it was observed)
- Root cause:        (why it happened — the cause, not the place it surfaced)
- Fix:               (what changed to close it)
- Prevention:        (what to do differently next time)
- Automated guard:   (what would catch a recurrence — a lint, a test, a helper, a checklist item, or
                      an architecture invariant. Never empty: an entry without one is refused)
- References:        (where to look — the commit, the run-record entry, the failing command)

Withhold any credential that appears in output, and say that you withheld it. `Symptom` and
`References` are the two fields one arrives in, and no entry here is ever edited — a value written
into one cannot be taken back out.
```

All seven fields get filled in. `Automated guard` is the one that gets left for later, and later is
where a lesson dies: by then whoever knew what would have caught the defect has moved on, and working it
out again costs what the defect cost the first time.
`````

Seed no entries, for the same reason as the other two: an entry is a record of a defect somebody
actually hit, so a seeded one is a claim about work that never happened. And do not soften the
guard-missing rule into a warning while you write the seed. A warning about a missing field is how the
field ends up optional, and an entry with no guard ca

…(truncated)
