Files
Skills/specify/SKILL.md
T
Brummel 7a58a530b1 feat(pipeline): route to the lightest correct methodology; move execution loops onto the Workflow substrate
The selector forced every task through the heaviest methodology's
critical path: a behaviour-preserving, type-enumerable change paid the
same specify -> planner -> implement front-half as a novel feature,
because it was neither new behaviour (tdd) nor an observed bug (debug)
and so fell to specify by elimination. Two coupled defects — a selector
with no verification axis, and an all-or-nothing executor — kept the
existing lighter path unreachable and uneconomical. This fixes both.

Part A — verification-keyed selector (boss/SKILL.md):
- Replace the three-way "design line" with an ordered cascade that adds
  a verification/enumeration axis ahead of the settled-vs-fork question.
  Each lighter arm carries a positive trigger matched by signature, not
  reached by elimination.
- New `compiler-driven` arm: a type/signature edit at a definition site
  that propagates mechanically. Observe-then-bounce — make the edit,
  build, run the suite; clean build AND suite green unchanged commits;
  a hole bounces up (specify for a design choice, tdd for discovered
  test-specifiable new behaviour); a regression bounces to debug.
- The observed-bug RED-first gate is first in the cascade, so a
  mechanical-looking fix cannot bypass it.
- The straddle rule ("add an enum variant") is codified as a rule:
  mechanical/forwarding -> compiler-driven; encodes new behaviour ->
  tdd/spec; doubt routes up.
- The executor is the elevated inline carve-out plus a shipped workflow,
  not a heavy new skill ("the largest concrete win is small").

Part B — Workflow substrate (implement/workflows/):
- implement-loop.js: the per-task loop as a deterministic script. Each
  phase (implementer -> spec-compliance -> quality, + tester for E2E) is
  a separate top-level agent() call, so a single phase is independently
  invokable and inter-phase aggregation/re-loop is code. Retires the
  implement-orchestrator agent's inline-role-switch workaround (the four
  phase agents survive as the agent-types the script dispatches).
- compiler-driven-edit.js: the observe-then-bounce loop.
- install.sh / uninstall.sh symlink shipped workflows into
  ~/.claude/workflows/.
- specify and brainstorm stay prose + interactive (human-intent oracle);
  only the autonomous/mechanical loops moved. try-and-error is deferred.

Docs (pipeline taxonomy, design, agent-template, migration, README) and
all selector<->executor cross-references updated; the arm and its
executor are co-located so a future re-route through the full loop is a
visible regression.

Verified by an adversarial multi-agent pass: PASS on all six acceptance
criteria; two coherence concerns fixed. The shipped scripts are
syntax-validated but exercised only in a downstream target project (the
skills repo is not itself a pipeline target).

closes #7
2026-06-17 12:27:51 +02:00

567 lines
32 KiB
Markdown

---
name: specify
description: Use when the design is already settled — a long in-context design discussion, an exhaustive tracker issue, or a ratified design handed over by brainstorm — and a spec must be produced from those sources with review but without an interview. The spec-production core: applies the feature-acceptance criterion, writes the spec under docs/specs, runs the parse and grounding-check gates, takes user sign-off, hands off to planner. Bounces to brainstorm the moment the sources do not resolve a load-bearing design decision. Co-equal third entry path alongside brainstorm and tdd.
---
# specify — spec-production entry path
> **Violating the letter of these rules is violating the spirit.**
## Overview
`specify` is where a settled design becomes an approved spec. It
takes **given sources** — a long in-context design discussion, an
exhaustive tracker issue, settled design docs, or a ratified design
narrative handed over by `brainstorm` — and produces the spec the
planner consumes: with review, but **without an interview**.
It is the **sole home of the spec-production gates**: the
feature-acceptance criterion, the write-spec step, the
`grounding-check` hard-gate, and the user-review gate. Whichever way design work enters — fresh
through `brainstorm`'s discovery, or directly from sources that
already resolve the design — it passes through `specify` to become a
spec. `specify` carries the universal invariant **no plan without an
approved spec**.
`specify` is the *producing* half of a deliberate split. `brainstorm`
owns *deciding* — interview, approaches, ratification. `specify` owns
*producing* — rendering that decision into the canonical artefact and
clearing the gates. The split is the toolchain's deepest discipline
applied one level up: `tdd → implement` and `debug → implement` split
RED from GREEN across two dispatches so the spec stays honest;
`specify` splits deciding from producing so the producing phase reads
the decision as a *source* rather than making it inline.
`specify` is a core pipeline node: it is the gate before `planner` on
every design path that is not a bug fix or a test-specifiable feature.
Where `tdd` is one entry path among three (chosen when behaviour is
test-specifiable), `specify` sits on every prose-design path — it is
not bypassed for those.
## When to Use / Skipping
Triggers:
- The design is settled in the sources and a spec must be written:
an exhaustive issue body, a long in-context design discussion, or
a ratified design `brainstorm` just handed over.
- A cycle-scope spec is missing for settled work and one is needed.
**Use the named alternative instead for:**
- A genuine design fork — the sources do **not** resolve a
load-bearing decision. Use `brainstorm` (its discovery is what
resolves the fork). `specify` itself bounces here the moment it
detects this (see The Iron Law and Step 1.5).
- A test-specifiable feature — the RED executable-spec is the spec.
Use `tdd` directly.
- An observed bug — use `debug` directly (RED-first).
- A tidy iteration — use `audit` directly.
- A trivial mechanical edit — per the project's CLAUDE.md carve-out.
**Skipping a gate is never permitted.** The interview is `brainstorm`'s,
and its absence here is the whole point — but the *production gates*
(criterion, grounding-check, user-review) are
non-negotiable regardless of how the work entered. "The issue looks
exhaustive, skip the grounding-check" is the reactive-deference failure
this skill must not reintroduce.
## The Iron Law
```
THE SOURCES MUST RESOLVE EVERY LOAD-BEARING DESIGN DECISION BEFORE THE SPEC IS WRITTEN.
IF WRITING THE SPEC FORCES A CHOICE BETWEEN PLAUSIBLE DESIGNS THE SOURCES DO NOT RESOLVE,
STOP AND BOUNCE TO brainstorm. DO NOT SILENTLY PICK ONE.
THE PRODUCTION GATES — ACCEPTANCE CRITERION, GROUNDING-CHECK, USER-REVIEW —
ARE NON-NEGOTIABLE REGARDLESS OF ENTRY PATH.
NO PLAN, SCAFFOLDING, OR DOWNSTREAM SKILL UNTIL THE SPEC IS APPROVED — BY THE USER, OR
(ONLY UNDER /boss WITH spec_auto_sign ENABLED) BY THE AUTO-SIGN GATE: ALL OBJECTIVE GATES GREEN
AND A UNANIMOUS ADVERSARIAL spec-skeptic PANEL. MODEL SELF-CONFIDENCE ALONE IS NEVER APPROVAL.
```
Every clause is non-negotiable. The precondition gate is what makes
the no-interview path legitimate rather than merely convenient: it is
the honest fork-check that `tdd`'s "is this test-specifiable?" is for
test work.
## The Process
### Step 1 — Explore / re-ground context
Before producing anything, establish what the sources actually say:
- **Direct entry** (from sources): read the sources in full — the
tracker issue body, the in-context design discussion, any settled
design docs. This IS the design input. Then `git log -5
--format=full` for the current state of the project.
- **Chain entry** (from `brainstorm`): the ratified design narrative
is already in-context. Re-ground lightly — fresh `git log`, the
files the design touches — rather than re-deriving it.
- If the project has a design ledger (its CLAUDE.md project facts),
walk to the contracts the work touches. Note any `status:
aspirational` source: its code is a target, not verified fact.
### Step 1.5 — Precondition gate (bounce-back)
Enumerate the **load-bearing design decisions** the spec must encode
— the choices that, decided differently, would change what ships.
For each, ask the honest question:
> Do the sources **resolve** this, or am I about to **pick** it
> myself?
If every load-bearing decision is resolved by the sources, proceed to
Step 2. If even one is unresolved — the sources leave a genuine fork
between plausible designs with real trade-offs — **STOP and bounce to
`brainstorm`** (see Error handling / The Bounce-Back). Do not silently
pick one and bake it into the spec; a guessed design ratified into a
spec is harder to dislodge than an open question, and it is exactly
the reactive-deference failure the gate exists to prevent.
Genuine doubt about whether the sources resolve a decision *is itself*
the fork signal — it resolves to a bounce, not to a guess.
**Reconciliation comment (lagging-issue case).** A load-bearing fork can
be resolved by the in-context design discussion yet still be listed
*open* by the tracker issue that seeded the cycle — the issue lags the
conversation. When that holds (entry is in-context **and** a tracker
issue still carries a now-resolved fork as open), record the resolution
as an auditable issue comment **before** writing the spec, via the
project's issue-tracker comment command (`tea comment <idx>` for Gitea;
a heredoc body per the `issue` skill's conventions). One comment, this
exact shape:
```
## Design reconciliation (specify, in-context entry)
Spec: <spec-name>. The fork(s) below are still listed open on this
issue; they were resolved in the in-context design discussion.
- **Fork: <name>** → <decision>.
Provenance: <verbatim user statement, or explicit attribution + date>.
```
The comment must carry **provenance**, and the distinction is
load-bearing: it is the *record of a user decision* (legitimate — the
user settled the fork in discussion, you are minuting it), never a *new
orchestrator decision* dressed as settled (illegitimate). A bare
`decision: B` with no provenance is the latter. If you cannot point to a
real user statement, that is the signal that *you* picked the fork, not
the user — which is a Step-1.5 bounce, not a comment. The comment is
*persistent and auditable* (author + timestamp, in the forward queue) —
which is exactly why it, and not your ephemeral confidence, is what a
downstream `scope-fork` juror reads to confirm the fork is settled (see
Step 6). Recording it keeps the forward queue honest in either run mode;
under auto-sign it is *load-bearing* — without it the `scope-fork` juror
sees only the stale issue body and (correctly) blocks.
Provenance enforcement is not yours to self-certify: you *write* the
comment, the adversarial `scope-fork` juror *checks* it carries
provenance (Step 6). Writing a provenance-less comment does not buy a
pass — the re-dispatched juror blocks on it.
Gitea writes are pre-authorized (per `~/.claude/CLAUDE.md`); post the
comment without a confirmation prompt.
**Issue-less in-context entry.** If the cycle has *no* tracker issue —
the design was settled in pure chat — there is no existing artefact to
comment on, so *create one*: open a new tracker issue that records the
resolved fork(s) with provenance, under the same discipline as the
reconciliation comment above. The body takes this shape:
```
## Design record (specify, issue-less in-context entry)
This issue seeds <one-line identity of the work>. The design was settled
in an in-context discussion with no prior tracker issue; this records it.
Load-bearing fork(s) resolved:
- **Fork: <name>** → <decision>.
Provenance: <verbatim user statement, or explicit attribution + date>.
```
The body names the *work*, not the spec file — the spec does not exist
yet at Step 1.5 (its number is assigned only in Step 3). This new issue
is the cycle's seeding issue from here on: the `scope-fork` juror reads
it via the project's issue show command — its index handed to the juror
in the Step-6 carrier (the `seeding_issue` field, below) — exactly as it
reads any seeding issue. A *new issue* is the right artefact where a spec-note
is the wrong one — a provenance note *inside the spec* is
self-referential (the spec asserting its own sources settle it) and
stays banned, but a separate issue is independent (author + timestamp,
in the forward queue, juror-readable without opening the spec), as
auditable as a reconciliation comment. Creating it is what makes
auto-sign *reachable* here, instead of the old unconditional fall-back
to the human sign-off.
The provenance gate is unchanged and load-bearing: the new issue records
*user* decisions, never fresh orchestrator ones. No real user statement
for a fork means *you* picked it — a Step-1.5 bounce, not an issue to
manufacture. You *write* the issue; the adversarial `scope-fork` juror
*checks* the provenance, and a provenance-less body buys no pass.
Create it via the project's issue-create command (the `issue` skill's
mechanics — `tea issues create` for Gitea), title and label per the
project's vocabulary as in the Step-5 failure-mode procedure. Gitea
writes are pre-authorized, so create it without a confirmation prompt.
**Capture the new issue's index** the moment it is created and carry it
into the Step-6 panel as the `seeding_issue` field — it is the only way
the `scope-fork` juror knows which issue to read. An issue created but
never handed to the panel is invisible to the juror, which leaves the
fork looking picked and the creation pointless.
### Step 2 — Apply the project's feature-acceptance criterion
The project's `CLAUDE.md` declares the criterion a feature must
satisfy to ship. Apply it now, prospectively. The typical shape is
some combination of:
- the project's intended audience naturally reaches for the feature,
- the feature measurably improves correctness or removes redundancy,
- the feature reintroduces no class of failure the project's core
constraint exists to eliminate.
If the project declares no criterion, the default is "the feature
solves a real user-facing problem and does not contradict a stated
design commitment". The orchestrator applies the criterion; do not
delegate it to the user.
**The criterion is unjudgeable without concrete code.** For any cycle
with authoring or consumer surface, the spec MUST contain the actual
program / invocation / configuration a user would write — and that
example *is* the criterion's empirical evidence. A prose assertion
("a user naturally reaches for X") with no shown code is the
unfalsifiable hand-wave the criterion exists to prevent: write the
code the user would write, then judge whether it is what the criterion
demands. For an infrastructure cycle with **no** user surface there is
still concrete code: show the code the cycle *delivers* — frequently a
test fixture whose correct behaviour is rejection — plus a *minimal,
honest* slice of the north-star program the infrastructure serves. "No
surface so no code to show" is the rationalisation to refuse.
**Code lifted from an aspirational source is a hypothesis, not
evidence.** If the concrete code here is lifted from a design-models
file (or any `status: aspirational` source, per Step 1), it carries no
validation by default. Treat it as the spec's most suspect bytes: flag
it as a target, not verified fact.
### Step 3 — Write the spec
Path: under `docs/specs`, named per the fixed naming convention —
`NNNN-slug.md`, 4-digit per-directory counter (see
`docs/conventions.md`). Determine the next free number by scanning the
directory.
Structure:
```markdown
# <Title> — Design Spec
**Date:** YYYY-MM-DD
**Status:** Draft — awaiting user spec review
**Authors:** orchestrator + Claude
## Goal
## Architecture
## Concrete code shapes
## Components
## Data flow
## Error handling
## Testing strategy
## Acceptance criteria
```
`## Concrete code shapes` is mandatory and **leads with the
user-facing program**: the worked author example for a surface cycle
(= the Step-2 empirical evidence), or — for a no-surface infra cycle —
the code the cycle *delivers* (often a must-fail fixture) plus a
minimal honest north-star slice. The before → after implementation
shape (struct / signature / match-arm) for each load-bearing change
follows as an explicitly secondary subsection, never first. Prose may
*explain* code, never *replace* it. Exact bytes / line-numbers remain
the planner's job — the spec owns the *shape*, shown.
### Step 4 — Self-review
Inline checklist (not a subagent dispatch):
1. **Placeholder scan:** any "TBD", "TODO", incomplete sections,
vague requirements? Fix.
2. **Internal consistency:** sections must not contradict.
Architecture must match component descriptions.
3. **Scope check:** focused enough for one plan, or does it need
sub-cycle decomposition?
4. **Ambiguity check:** could any requirement be read two ways? Pick
one and make it explicit.
5. **Concrete-code check:** does `## Concrete code shapes` exist and
carry before → after code for every load-bearing change (plus the
worked user-facing example for a surface cycle)? A load-bearing
change described only in prose is a self-review failure to fix.
Fix issues inline.
### Step 5 — Grounding-check (hard-gate)
Dispatch the read-only `grounding-check` agent. The agent reads the
just-written spec with fresh context, extracts its load-bearing
assumptions about *current* behaviour of the codebase, and for each
searches the workspace for a currently-green test that ratifies it.
Dispatch carrier — the fields `spec_path` and `iteration_scope`,
defined authoritatively under **Carrier contract** in
`agents/grounding-check.md` (note `spec_path` is an *absolute* path).
That table is the single source for those fields; it is deliberately
not restated here, so the two files cannot drift.
The agent returns `PASS` / `BLOCK` / `INFRA_ERROR`. Interpretation:
| Agent status | Orchestrator action |
|--------------|---------------------|
| `PASS` | Proceed to Step 6. The report goes into the chat for the record. |
| `BLOCK` | Present the report to the user. User either: (a) accepts discard → execute the failure-mode procedure below; or (b) overrides in free chat ("Test `<path>::<name>` ratifies that") → log the override note and proceed to Step 6. |
| `INFRA_ERROR` | Abort. The spec stays as-is on disk; debug the workspace out-of-band and re-dispatch the agent. |
**Failure-mode procedure (no-override `BLOCK`):**
1. Delete the just-written spec file from the working tree
(`rm <spec_path>` — a shell delete, NOT `git rm`; never committed).
2. Open a backlog issue (via the project's issue-tracker create
command) pointing forward to a future re-design. Include:
- **Title:** one-line identity of the deferred work
- **Label:** matching the project's vocabulary (`feature` / `bug`
/ `idea`; promote to `BLOCKER` if the unratified mechanism is on
a core-functionality path)
- **Body:** short description plus two structured lines:
- `depends on: <name of the unratified mechanism>`
- `context: <why this is deferred>`
If the deferred work needs its own spec on resumption
(multi-iteration, cross-subsystem), file it as a **milestone
container** instead of a single issue.
3. Tell the user the spec was retired and which backlog entry was
filed. No commit is needed — the issue tracker is the live store.
After the failure-mode procedure runs, the session ENDS. There is no
Step 6, no Step 7. The idea is parked until the dependency ships.
**Re-dispatch on any post-PASS edit.** The PASS report is bound to the
exact bytes of the spec at dispatch time. Any subsequent edit — polish,
a user-requested change, a wording tighten — invalidates the PASS
report and requires a fresh dispatch of `grounding-check` before the
Step-6 sign-off and commit. Step 5 is the *last* step that touches the
spec file; nothing slips between it and the commit.
### Step 6 — User-review gate
The spec sits in the working tree as an unstaged file. Tell the user:
> Spec written to `<path>` (uncommitted). Please review it and let me
> know if you want changes before we start the implementation plan.
> The orchestrator will commit it once you approve.
Wait for the user's response. If they request changes, edit the file
in place (still uncommitted), **re-run Step 4 AND re-dispatch Step 5**
(the previous PASS report no longer covers the edited bytes), then
return here. Only proceed after approval AND a fresh Step 5 PASS.
The orchestrator commits the approved spec after sign-off (suggested
commit subject: `spec: <cycle> <topic>`). The skill does not perform
the commit itself.
**In `/boss` (autonomous):** `specify` is dispatched autonomously —
it is bounded (no interview). It runs the criterion, parse, and
grounding-check gates without a checkpoint. What happens at *this*
gate then depends on whether the project enables spec auto-sign (its
CLAUDE.md project facts):
- **Slot absent or `false` (default):** `specify` **pauses here** as a
problem-state notify ("spec X ready, please sign off") and waits for
the user. This is the final sign-off pause, not a pre-dispatch
checkpoint — the distinction from `brainstorm`, which `/boss` bounces
*before* dispatch. This is the conservative default; the user's
signature is mandatory.
- **Slot `true`:** the orchestrator MAY sign in the user's place, but
only through the **auto-sign gate** below. The gate exists because
the orchestrator that wrote the spec is the worst-placed party to
judge it — so the gate is built to *not* rely on the orchestrator's
own confidence. Run it in two stages:
1. **Objective gates (all must already hold — these are facts, not
judgements):**
- Step 1.5 precondition gate passed cleanly — no load-bearing
fork was silently picked (if one had been, `specify` would have
bounced, so reaching here is the evidence; do not re-decide it).
- Step 4 self-review clean, **including the placeholder scan** (no
`TBD` / `TODO` / incomplete section).
- Step 5 `grounding-check` returned **`PASS`** — *not* an
overridden `BLOCK`. An override needs a human; with no human in
the loop a `BLOCK` can never be overridden, so any non-`PASS`
grounding result denies auto-sign outright.
If any objective gate is not green, **do not run the panel**
fall straight to the human sign-off pause (the default-slot
behaviour above), carrying the failing gate in the notify.
2. **Adversarial panel (unanimous-or-nothing):** dispatch the
read-only `spec-skeptic` agent **five times in parallel**, once
per lens — `criterion`, `grounding`, `scope-fork`, `ambiguity`,
`plan-readiness`. Carrier per dispatch: `spec_path` (absolute),
`iteration_scope`, the single `lens`, and `seeding_issue` — the
index of the cycle's seeding issue (the lagging issue reconciled in
Step 1.5, the issue Step 1.5 created for an otherwise issue-less
cycle, or `none` if the cycle has neither) for the `scope-fork`
juror to read; the other four lenses ignore it. Each juror tries to
*refute* the spec along its lens and returns `SOUND` / `BLOCK` /
`INFRA_ERROR`. Auto-sign requires a **unanimous `SOUND`** — that
never changes. What the partition below adds is a bounded path to
*reach* that unanimity for defects the orchestrator can repair
without judging the spec.
The five lenses split by what a `BLOCK` actually means:
| Lens class | Lenses | A `BLOCK` means |
|------------|--------|-----------------|
| **Editorial** | `criterion`, `ambiguity`, `plan-readiness` | The spec is under-*articulated*: missing worked evidence, a requirement readable two ways, scope too broad for one plan. Repairable by editing the prose without settling any new design or fact. A `criterion` repair may only *supply or sharpen the worked evidence the criterion already demands* (paste the concrete before → after / user-facing code the spec implied) — it may **not** soften what the criterion requires or re-judge acceptance, and if the missing evidence cannot be shown without picking an un-settled design, that is a `scope-fork` in disguise: leave it, and the re-dispatched `scope-fork` juror escalates it. |
| **Design** | `scope-fork`, `grounding` | The *ground is not settled*: the sources do not resolve a load-bearing fork, or a load-bearing assumption is not ratified by a green test. The orchestrator may **never** settle these in the user's place. |
Resolve the panel against that split, in a bounded loop
(`round` starts at `0`):
| Panel outcome this round | Orchestrator action |
|--------------------------|---------------------|
| All five `SOUND` | **Auto-sign.** Commit the spec yourself (subject `spec: <cycle> <topic> (boss-signed)`), send the informational auto-sign notify (see `boss` § Notifications — names the capability in user terms and states the plan is proceeding and a reply vetoes), then proceed to Step 7. No pause. |
| Any `INFRA_ERROR` | **Escalate.** Fall back to the human sign-off pause; the notify carries the failing dispatch. |
| Any **design**-lens (`scope-fork` / `grounding`) `BLOCK` | **Escalate.** No self-correction — this is exactly the judgement the gate refuses to make for the user. Fall back to the human sign-off pause, carrying *all* lens findings this round. |
| Only **editorial**-lens `BLOCK`(s), and `round == 2` | **Escalate.** The self-correction budget is spent. Fall back to the human sign-off pause, carrying the findings *and* the per-round correction history. |
| Only **editorial**-lens `BLOCK`(s), and `round < 2` | **Self-correct.** Edit the spec in place to address each editorial finding (each names its `§section` / offending text / defect). Then **re-run Step 4 self-review and re-dispatch Step 5 `grounding-check`** — the edit invalidated the prior `PASS` (see "Re-dispatch on any post-PASS edit"); if `grounding-check` does not return `PASS`, escalate. Increment `round` and re-dispatch all five lenses from the top of this table. |
**Re-loop limit: ≤ 2 self-correction rounds. The 3rd unresolved
editorial `BLOCK` escalates** — same shape as the per-task re-loop
limit in the implement loop (`../implement/workflows/implement-loop.js`).
Three properties keep this loop honest, not a way to grind the panel
into submission:
- **The panel stays the sole arbiter.** The orchestrator never judges
the spec; it only edits in response to a juror's finding, and a
fresh panel re-adjudicates. "The spec looks good to me" still never
signs.
- **Re-dispatch is all five lenses, every round.** This is the
backstop. If an editorial repair silently *launders* an unsourced
design decision into the spec (resolving an ambiguity by picking an
un-settled fork), the re-run `scope-fork` / `grounding` jurors now
`BLOCK` on it — and a design `BLOCK` escalates. The only thing the
loop can converge to autonomously is a spec whose every lens is
`SOUND` *and* whose only repairs were editorial.
- **Escalation is the panel doing its job**, not a failure — it routes
the spec to the human who was going to review it anyway, the moment
a real design question surfaces or the budget runs out.
**Auto-sign commits on `main` are forward-only like every other
commit.** A later user veto is a forward correction (revert / revised
spec / `git checkout` of downstream working-tree work), never a
history rewind — same discipline as any other orchestrator call (see
`boss` § Direction freedom).
### Step 7 — Hand off to `planner`
The terminal state of `specify` is invoking `planner`. NO other skill
is invoked from `specify`. NO direct jump to `implement`.
Hand off carries:
- path to the spec under `docs/specs`
- iteration scope ("the first iteration covers section X+Y of the
spec")
## The Bounce-Back
`specify` returns to `brainstorm` whenever the precondition fails — the
sources do not resolve a load-bearing design decision (Step 1.5), or a
`grounding-check` `BLOCK` reveals an unratified mechanism the user does
not override (Step 5 failure-mode routes to a re-design). On a
precondition bounce:
1. Nothing was written yet (the gate fires *before* Step 3), so there
is no working-tree artefact to discard.
2. Invoke `brainstorm` with the unresolved design question as the
cycle request. From there the normal `brainstorm → specify →
planner` path runs.
The bounce-back is not a failure of this skill; it is the skill
correctly refusing to ratify an un-chosen design into a spec — the same
discipline `tdd` applies when behaviour is not test-specifiable.
## Handoff Contract
| Direction | Carrier |
|-----------|---------|
| user / issue (design settled) → `specify` | the sources: issue body, in-context design discussion, design docs |
| `brainstorm``specify` | ratified design narrative (approaches chosen, constraints, sections approved) — in-context; brainstorm writes no spec file |
| `specify``grounding-check` (Step 5) | `spec_path` (absolute) + `iteration_scope` |
| `specify``spec-skeptic` panel (Step 6, `/boss` + `spec_auto_sign` only) | `spec_path` (absolute) + `iteration_scope` + one `lens` per dispatch (five in parallel) + `seeding_issue` (index for the `scope-fork` juror to read, or `none`) |
| `specify``planner` (Step 7, on PASS or overridden BLOCK) | path to spec + iteration scope |
| `specify``brainstorm` (precondition bounce) | the unresolved design question as a cycle request; no spec written |
| `specify` → issue backlog (Step 5, no-override BLOCK) | new issue naming the unratified dependency; spec file deleted from the working tree |
## Common Rationalisations
| Excuse | Reality |
|--------|---------|
| "The issue looks exhaustive — skip the grounding-check / criterion too" | The interview is what `specify` skips, by design. The production gates are not the interview; they are what keeps the spec honest no matter how it entered. Skipping a gate because the sources look thorough is the exact reactive-deference failure this skill must not reintroduce. |
| "There's a small open fork but the sources mostly decide it — I'll pick the rest" | "Mostly decided" with one real fork left is an unresolved design, and a guessed design baked into a spec is harder to dislodge than an open question. That is the bounce-back trigger — stop and go to `brainstorm`. |
| "Genuine doubt whether the sources resolve this — but bouncing feels like overkill" | Doubt about whether the sources resolve a decision *is* the fork signal. It resolves to a bounce, not a guess. The bounce is cheap (nothing is written yet); a wrong guess in a ratified spec is not. |
| "The shape is clear from the prose, I don't need to paste the code" | If it's clear, pasting it is free; if pasting it is hard, it wasn't clear. The acceptance criterion is unjudgeable without the worked code. |
| "Just polishing a wording after PASS, no need to re-dispatch" | The grounding-check report attests to specific bytes. A polish edit changes the bytes; the attestation no longer covers them. Re-dispatch is cheap. |
| "It's in a model doc / the design ledger, so it's canonical" | A `models` / RFC / proposal doc holds aspirational code — a target, not verified fact. Flag code lifted from a `status: aspirational` source as such; it is not ratified contract. |
| "In `/boss` with auto-sign on, this spec looks solid — I'll sign and move on" | Your sense that it looks solid is the exact signal the auto-sign gate refuses to trust. Signing requires all objective gates green AND a unanimous `spec-skeptic` panel. If you find yourself wanting to sign on confidence, that is the cue to run the gate, not to skip it. |
| "One lens blocked on something minor — I'll sign anyway since the rest passed" | The panel is unanimous-or-nothing by design. You never *sign over* a `BLOCK`. An editorial `BLOCK` you may *repair* (within the ≤ 2-round budget, with a full re-panel after); a design `BLOCK` routes to the human. Neither is overruling a juror — that is the whole point of replacing your eye with five independent ones. |
## Red Flags — STOP
- An unresolved design fork silently picked instead of bounced (any flavour)
- "The sources are thorough, skip a gate" thoughts (any flavour)
- A load-bearing change described in prose with no before → after code
block; a surface cycle with no worked user-facing example
- Lifting code verbatim from a `status: aspirational` source without
flagging it as a target, not verified fact
- Editing the spec file after a Step 5 PASS without re-dispatching
- (auto-sign) About to sign a spec in the user's place on confidence —
without all objective gates green AND a unanimous `spec-skeptic`
panel; signing over any `BLOCK`; self-correcting a *design*-lens
(`scope-fork` / `grounding`) `BLOCK` instead of escalating; or
re-dispatching only the blocked lens rather than all five, or past
the 2-round self-correction budget
- (auto-sign) Running the panel before the objective gates are green,
or running it at all when `spec_auto_sign` is not enabled
- Jumping straight from spec to `implement` (must go via `planner`)
- Running an interview here (that is `brainstorm`'s job — if the work
needs one, bounce)
## Cross-references
- **Output target:** `../planner/SKILL.md` — only valid next skill.
- **Discovery front-end / bounce-back target:** `../brainstorm/SKILL.md`
— produces the ratified design `specify` consumes on the chain path,
and reclaims the work when the sources do not resolve a design fork.
- **Sibling fast path:** `../tdd/SKILL.md` — the same
bounce-to-`brainstorm`-on-fork discipline, for test-specifiable work;
its RED executable-spec is the spec, so it skips both `specify` and
`planner`.
- **Agent dispatched:** `agents/grounding-check.md` — dispatched in
Step 5 as a hard-gate. Reads the spec with fresh context and reports
PASS / BLOCK / INFRA_ERROR.
- **Agent dispatched (auto-sign only):** `agents/spec-skeptic.md`
dispatched in Step 6 five times in parallel (one per lens) ONLY under
a `/boss` session with spec auto-sign enabled (the project's CLAUDE.md
project facts). Each
juror tries to refute the spec along its lens; a unanimous `SOUND` is
what lets the orchestrator sign in the user's place. An editorial-lens
`BLOCK` (`criterion` / `ambiguity` / `plan-readiness`) is self-
corrected in a bounded loop (≤ 2 rounds, full re-panel each round); a
design-lens `BLOCK` (`scope-fork` / `grounding`), an `INFRA_ERROR`, or
an exhausted budget falls back to the human sign-off pause.
- **Ad-hoc dispatch.** The orchestrator MAY also ad-hoc dispatch
`../planner/agents/plan-recon.md` during Step 1 when the work enters
code territory not recently read; discretionary, not part of the
standard process.
- **Project feature-acceptance criterion:** declared in the project's
`CLAUDE.md`. Applied prospectively in Step 2.