All 176 files in the four accumulating directories now use a zero-padded 4-digit counter prefix that reflects creation order (`NNNN-slug.md`). The counter is assigned per directory in strict git-log creation order; ties broken alphabetically by original name. The old `YYYY-MM-DD-` prefix on docs/specs/ and docs/plans/ files is dropped — the date is recoverable from git log and the counter carries the ordering. A file's counter is stable for the life of the file: never reassigned, never reused, never compacted. Deleted files retire their counter; subsequent files do not fill the gap. This is the property that lets cross-references stay literal — refs use the full filename including the counter (`design/contracts/0007-honesty-rule.md`) so they grep cleanly and resolve directly without a glob step. 313 cross-references updated across .md/.rs/.toml/.c/.json files (test pins, include_str! paths, design-INDEX entries, baseline notes, runtime C comments, inter-contract markdown links incl. bare basename and `../models/foo.md` forms). CLAUDE.md gets a new "File-naming convention" section spelling out the rule and rationale. skills/brainstorm/SKILL.md and skills/planner/SKILL.md updated so new spec/plan creation produces counter-prefixed names from the start. The full test suite (cargo test --workspace) passes.
11 KiB
name, description
| name | description |
|---|---|
| planner | Use when a milestone spec exists in docs/specs/ and a new iteration is starting. Produces a placeholder-free, bite-sized implementation plan in docs/plans/ that the implement skill can execute task-by-task. Hard-gate before any implementation work. |
plan — spec → executable plan
Violating the letter of these rules is violating the spirit.
Overview
A plan is the contract between design (spec) and execution
(implement). It commits the file structure, names every file
that will be created or modified, and decomposes work into bites
small enough that a subagent can execute one in 2-5 minutes
without making judgement calls outside its remit.
Plans live at docs/plans/NNNN-<iteration>.md where NNNN is the
next-higher 4-digit counter in docs/plans/ (determine with
ls docs/plans/ | tail -1 and add 1; see CLAUDE.md "File-naming
convention"). The header references the parent spec. The plan decomposes work into tasks; each task is
the unit of review (spec-compliance and quality gates inside
implement), not the unit of commit. Commits are a Boss-only
decision taken at the end of the iter against the full working-tree
diff.
When to Use / Skipping
Triggers:
- A spec at
docs/specs/<milestone>.mdis approved. - A new iteration within an active milestone is starting.
May be skipped when:
- The work is a bug fix where the RED test from
debugIS the plan (handoff goes straight toimplementmini-mode). - The work is a trivial mechanical edit (one file, ≤30 LOC, no design judgement).
Never skipped for a standard iteration within an active milestone. "I know the milestone, plan from memory" is exactly the failure mode this skill prevents.
The Iron Law
NO PLACEHOLDERS — TBD, TODO, "implement later", "similar to Task N",
or "add appropriate error handling" are PLAN FAILURES.
EVERY STEP THAT CHANGES CODE INCLUDES THE CODE.
EVERY STEP THAT RUNS A COMMAND INCLUDES THE COMMAND AND EXPECTED OUTPUT.
Non-negotiable.
The Process
Step 1 — Read the parent spec
Read docs/specs/<milestone>.md in full. NOT from memory. Even if
the spec is recent and you wrote it yourself, re-read it before
planning.
The spec is the source of truth; the plan is the projection of one iteration's worth of work onto a task list.
Step 2 — Map file structure
Dispatch ailang-plan-recon with the spec path and iteration scope.
Read the returned file-map. Lift the relevant entries into the plan's
"Files this plan creates or modifies" section; the Boss may add or
amend entries that recon missed.
Dispatch carrier:
| Field | Content |
|---|---|
spec_path |
path to the parent spec |
iteration_scope |
which sections of the spec this iteration covers |
focus_hint |
optional — subsystem or symbol to prioritise |
Recon does NOT decide decomposition. Two recon dispatches per planner
run is unusual but legitimate (e.g. one for the main spec sections,
one with a sharper focus_hint for a tricky subsystem). Three or
more is a smell — re-read the spec; the iteration scope is probably
too broad.
The plan's "Files this plan creates or modifies" section keeps the same shape:
**Files this plan creates or modifies:**
- Create: `<exact path>` — <one-line responsibility>
- Modify: `<exact path>:<line range if known>`
- Test: `<exact path>` — <one-line case description>
Files that change together stay in the same task. Files that change independently get separate tasks.
Step 3 — Write tasks, bite-sized
Each task is a logical unit of change (one feature, one fix, one extension). Each task contains steps; each step is ONE action that takes 2-5 minutes:
### Task N: <Component Name>
**Files:**
- Create: `<exact path>`
- Modify: `<exact path>:<line range if known>`
- Test: `<exact path>`
- [ ] **Step 1: Write the failing test**
```rust
#[test]
fn test_<specific_behaviour>() {
let result = function(input);
assert_eq!(result, expected);
}
- Step 2: Run test to verify it fails
Run: cargo test --workspace -p <crate> test_<specific_behaviour>
Expected: FAIL with ""
- Step 3: Write minimal implementation
fn function(input: T) -> U {
// exact code
}
- Step 4: Run test to verify it passes
Run: cargo test --workspace -p <crate> test_<specific_behaviour>
Expected: PASS
No `git commit` step. Implement tasks leave their work in the
working tree; the Boss commits at the end of the iter.
### Step 4 — Plan header
Every plan starts with this header:
```markdown
# <Iteration Title> — Implementation Plan
> **Parent spec:** `docs/specs/<milestone>.md`
>
> **For agentic workers:** REQUIRED SUB-SKILL: use `skills/implement`
> to run this plan. Steps use `- [ ]` checkboxes for tracking.
**Goal:** <one sentence>
**Architecture:** <2-3 sentences>
**Tech Stack:** <key crates/libs touched>
---
Step 5 — Self-review
Before handing the plan off, run this checklist inline:
- Spec coverage: every spec section has a task that implements it. If a section has no task, add one.
- Placeholder scan: grep for "TBD", "TODO", "implement later", "similar to Task", "add appropriate error handling". Any hit is a plan failure to fix.
- Type consistency: function names, type names, file paths
referenced across tasks must match.
clearLayers()in Task 3 andclearFullLayers()in Task 7 is a bug. - Step granularity: every step is 2-5 minutes. If a step is "implement the parser", split it.
- No commit steps: task templates must not contain
git commitinstructions. Implement tasks leave work in the working tree. - Pin/replacement substring contiguity: when a task ships a
test asserting
contains("<substring>")(or a grep) AND another task's verbatim replacement body is what must contain that substring, the substring must appear contiguously in that replacement body — no soft-wrap splitting it across two lines. Two authoritative artefacts (exact pin vs. exact replacement) that cannot both be applied literally is a plan defect, not an implementer judgement call. This is the recurring grep/contains line-wrap family (iter-revert Concern 2; iter effect-doc-honesty Task 2) — scrub it here, every plan that pairs a presence-pin with a verbatim text edit. - Compile-gate vs. deferred-caller ordering: when a task
changes a function signature (or any change that makes the
whole crate fail to compile until N call sites are updated)
AND that task ends with a
cargo build/cargo test"0 errors" gate, every caller the signature change touches MUST be threaded inside that same task — not deferred to a later task. A "0-errors" gate is unsatisfiable while any caller is still unthreaded (harderror[E0061]), so a plan that defers a caller (e.g. "thecheck_fncall site is handled in Task 4") past an earlier task's compile gate is internally contradictory: the executor is forced to pull the deferred code forward to satisfy the gate, silently resequencing the plan. Either fold all caller-threading into the signature-change task, or make the gate a partial build of just the changed module with the crate-wide build deferred to the task that finishes threading. This is the recurring "compile-gate depends on a caller the plan defers past the gate" family (iter loop-recur.2 Concern 1) — scrub it here, every plan with a signature-change task. - Verification-command filter strings must resolve. Every
literal
cargo test … <filter>/grep <pat>/cargo test --test <name>in a Run step is itself a load-bearing artefact: if its filter substring matches no test (or its--testtarget file does not exist), the step silently asserts nothing — a green "0 passed; 0 filtered" reads as success while proving the opposite of the gate's intent. For every such command, either (a) the filter substring must be one verified to match ≥1 real named test/line in the current tree (name it, do not guess from the feature word — e.g. tail-app guards are*_tail_position_*/*musttail*, NOTtail), or (b) use the unfiltered suite plus an explicit result-count assertion (… | awk '{p+=$4} END{print p}', expected ≥ a stated baseline) so "nothing ran" cannot masquerade as "nothing regressed". This is the recurring "literal verification filter doesn't resolve to its evident target" family (iter loop-recur.3 Concern) — scrub every Run step whose assertion lives in a filter string.
Fix issues inline.
Step 6 — Hand off
The plan sits in the working tree as an unstaged file at
docs/plans/<iteration>.md. Hand off to implement with: path to
the plan file + optional task focus ("only Tasks 1-3 this run").
The Boss commits the plan when handing it forward (suggested
commit subject: plan: <iteration> <subject>). The planner skill
does not perform the commit itself.
Handoff Contract
| Direction | Carrier |
|---|---|
brainstorm → planner |
path to docs/specs/<milestone>.md + iteration scope ("this iteration covers spec section X+Y") |
planner → implement |
path to docs/plans/<iteration>.md + optional task-range focus |
planner → brainstorm (bounce) |
spec contains placeholders or contradictions: name the offending section, request revision |
Common Rationalisations
| Excuse | Reality |
|---|---|
| "TBD in step 4 lets me ship the plan tonight, fill in tomorrow" | Half-decided plans get re-litigated mid-iteration, costing more than the night's sleep saved. Make the decision tonight or close the laptop. |
| "Bundle Tasks 3 and 4, both small" | Tasks are the unit of review (spec-check + quality-check fire once per task). Bundling collapses two reviews into one and hides the smaller change inside the bigger one. If 3 and 4 are inseparable, they're one task — rewrite the decomposition. |
| "Spec is recent, I wrote it, plan from memory" | Memory diverges from disk. 15 minutes of re-reading is the cheapest insurance in the cycle. |
| "Step 5 'implement the parser' is fine, I'll detail it at execution time" | Then it's not a step, it's a wish. Steps are bite-sized OR the plan isn't done. |
| "Task 7 is similar to Task 4, just say so" | The executor may read tasks out of order. Repeat the code. |
| "The spec has a TBD too, I can pass it through" | Bounce back to brainstorm. Plans inherit spec gaps; spec gaps are not plan placeholders. |
Red Flags — STOP
- Any of: "TBD", "TODO", "fill in later", "similar to", "add appropriate " — fix or bounce.
- Steps that describe what to do without showing how
- Function/type/path names that don't match across tasks
- Step descriptions longer than the code they describe
- Header missing parent spec reference
- Self-review skipped because "the plan looks fine"
Cross-references
- Input source:
skills/brainstorm/SKILL.md— produces the spec this skill consumes. - Output target:
skills/implement/SKILL.md— runs the plan task-by-task. - Agents dispatched:
skills/planner/agents/ailang-plan-recon.md— Step 2, file-structure mapping (read-only). Mandatory; the Boss does NOT do recon in-context.