Auto Spec
Overview
Produce the spec a strong engineer would write before touching code: grounded in what actually exists,
precise about behavior, testable in its criteria, honest about scope and risk — arrived at autonomously
through recon + draft + an adversarial completeness loop. The output is a spec downstream phases can plan
and test against without re-interviewing the user.
Phase 0: Intake — capture the request, detect blocking ambiguity
- Capture
$request verbatim as the source of scope. The request IS the scope; don't silently narrow or
widen it.
- In a pipeline run, require and read the pre-plan intake snapshot; copy its
selectedScope[]
ids/titles/sources verbatim into a Binding selected scope checklist and record the snapshot path/hash.
Do not accept the plan/spec's own copy as its authority. In a standalone run, if the caller supplies
selectedScope[], preserve it verbatim; if the user selected a named bundle, itemize it first. The
checklist is authoritative over the draft and must not be regenerated from what the spec includes.
- Judge whether it's answerable from the repo + reasonable inference, or whether a genuine product
decision blocks it (a fork where building the wrong branch is expensive). Only for the latter, ask a
FEW targeted questions (
AskUserQuestion) — never a long interview, never scope questions you could
answer by reading the repo.
- Open a
checkpoint-resume run.
Success criteria: the request is captured; at most a few genuinely-blocking questions asked; recon
can proceed.
Phase 1: Recon — ground the spec in reality
Before drafting, learn what exists (fan out with fan-out-work for a large repo):
- the relevant existing code, modules, data models, and interfaces the change touches;
- prior art / patterns in the repo to stay consistent with;
- constraints that are real: the stack, existing contracts, invariants in
CLAUDE.md/docs, data shapes,
auth/security boundaries;
- the domain facts the request assumes;
- prior-run lessons already in your loaded context —
auto-learn routes them into CLAUDE.md,
.claude/rules, and auto memory (which Claude Code loads automatically), so constraints and failure
patterns already paid for are in front of you: fold them into the spec's constraints/risks, don't
rediscover them.
Record what's grounded vs. what's an assumption — the draft will mark assumptions explicitly.
Success criteria: a grounded picture of the current state and constraints the spec must respect.
Phase 2: Draft the spec
Write .ulpi/spec/<name>.md covering (omit a section only when truly N/A, and say so):
- Objective — the problem and the outcome, in one or two sentences.
- Users & context — who this is for and when it's used.
- Behavior / user stories — what the system does, from the user's view; the happy path AND the error
and edge paths.
- Acceptance criteria — a checklist, each item TESTABLE (a condition you could assert). These become
the plan's per-task criteria and the tests' targets.
- Binding selected scope — every intake id, unchanged, with the behavior/criteria that implement it.
- Scope & non-goals — explicitly in and explicitly OUT. Non-goals may contain only things the intake
selection never included. Never put a selected id here.
- Constraints & interfaces — stack, contracts, data shapes, public interfaces affected, backward-compat.
- Assumptions & open questions — everything not grounded, named as such.
- Risks — security, data, irreversibility, performance — with the mitigation direction.
Success criteria: a complete first draft; every acceptance criterion is phrased testably; assumptions
are marked, not hidden as facts.
Phase 3: The completeness-critic loop (converge until stable)
Run converge-loop in until-dry mode with an adversarial critic as the finder — this is what makes the
spec strong:
- each round,
adversarial-verify-style critics attack the draft: missing behavior/edge/error case? an
acceptance criterion that isn't testable? an ungrounded requirement? contradictory or ambiguous
wording? a non-goal that should be stated? an unstated assumption? any selected-scope id missing,
weakened, deferred, or placed in non-goals?
- apply the smallest fix per finding (tighten a criterion, add the missing case, mark the assumption, cut
the invented requirement);
- re-critique; exit when a round finds no material gap (dry) OR it stalls. A stalled loop reports the
remaining open gaps — it does not claim completeness.
Use AskUserQuestion only if a surfaced gap is a real product decision; otherwise the critic resolves it
against the repo.
Success criteria: no material gap/ambiguity/untestable criterion remains, or the open ones are
explicitly listed as open questions.
Phase 4: Finalize
Write the stabilized spec to .ulpi/spec/<name>.md, close the checkpoint, and report where it lives + the
open questions (if any). This spec is the input to auto-plan.
Success criteria: the spec file is written and self-consistent; open questions (if any) are flagged
for the user.
Common Rationalizations
| Rationalization |
Reality |
| "The request is clear enough, skip the spec." |
Clear-to-you scatters into ten interpretations at build time. The spec is the shared contract that prevents that. |
| "I'll just assume the obvious behavior." |
An unmarked assumption is an invented requirement. Mark it as an assumption or ask — don't smuggle it in as fact. |
| "'Works well' is a fine acceptance criterion." |
Untestable criteria can't gate anything. If you can't write a test for it, it's a wish, not a criterion. |
| "I don't need non-goals, the scope is obvious." |
Unstated non-goals are the entry point for scope creep. Name what's out. |
| "The critic found nothing new, one round is enough." |
One round rarely exhausts the gaps. Loop until a round is genuinely dry, then stop. |
| "I'll reference a config/endpoint that probably exists." |
A phantom path in the spec becomes a phantom in the code. Ground it or mark it unknown. |
| "This selected feature cannot fit this pass, so I will call it a non-goal." |
That silently reduces the user's scope. Keep it selected and attempt it; unfinished work is BLOCKED. Only the user may drop its id. |
Red Flags
- Requirements, paths, or endpoints in the spec that don't exist in the repo and aren't marked assumptions.
- Acceptance criteria you couldn't write a test for.
- A spec with in-scope items but no non-goals.
- The critic loop ran exactly once.
- Long clarification interviews for things readable in the repo.
- A "complete" verdict with unresolved contradictions still in the text.
- A selected-scope id missing from the spec, weakened into a non-goal, or pre-emptively deferred.
Guardrails
- Never invent requirements/paths/constraints; ground them or mark them assumptions.
- Never emit an untestable acceptance criterion.
- Never omit explicit non-goals.
- Never put a selected-scope id in non-goals or deferred work. If it cannot be completed, keep it selected
and surface it as BLOCKED; record a drop only after an explicit user decision naming that id.
- Never resolve a real product decision silently — ask (briefly) or flag it open.
- Never report the spec complete while the critic still finds material gaps.
When To Load References
fan-out-work (skill) — parallel recon across a large codebase in Phase 1.
adversarial-verify (skill) — the completeness critics in Phase 3.
converge-loop (skill) — the until-stable critic loop (termination + anti-thrash).
checkpoint-resume (skill) — durable spec-run state.
Output Contract
Report:
- the spec file path (
.ulpi/spec/<name>.md), independent intake snapshot path/hash, and objective
- selected-scope coverage (
N of M) against that snapshot with every selected id, then the acceptance-criteria count and
explicit non-goals
- any per-id user-approved drops, assumptions made, and open questions surfaced for the user
- critic-loop outcome (rounds to stable, or the honest remaining gaps)
1---2name: auto-spec3description: Turn a raw feature request into a grounded, TESTABLE spec — autonomously. It recons the real repo and domain to ground every claim, drafts a spec (objectives, user-visible behavior, acceptance criteria, explicit non-goals, constraints, interfaces, risks), then runs a completeness-critic loop that adversarially hunts for gaps, ambiguity, and untestable criteria and fixes them until the spec is stable. Every acceptance criterion it emits is measurable (you could write a test for it); every requirement is grounded in the repo or flagged as an assumption — no invented requirements, no phantom paths. It writes `.ulpi/spec/<name>.md` and is the DEFINE phase that feeds auto-plan. Composes fan-out-work (recon), adversarial-verify (the critic), converge-loop (until-stable), and checkpoint-resume.4---56<EXTREMELY-IMPORTANT>7A spec is a contract; a vague or invented one poisons everything downstream. Non-negotiable:81. GROUND EVERY REQUIREMENT. Each requirement is tied to the actual repo/domain or explicitly marked an9 ASSUMPTION. Never invent requirements, file paths, endpoints, or constraints to fill a gap — a phantom10 in the spec becomes a phantom in the plan and the code.112. EVERY ACCEPTANCE CRITERION MUST BE TESTABLE. If you can't state how it would be verified (a test, a12 measurable threshold, an observable behavior), it isn't an acceptance criterion — sharpen it or cut it.133. SCOPE HAS EXPLICIT NON-GOALS. A spec that only says what's in-scope invites scope creep. State what is14 deliberately OUT.154. SURFACE, DON'T GUESS. Genuine ambiguity that changes what gets built is a STOP-and-ask (bounded16 questions), not a silent assumption dressed as a requirement.175. FAIL CLOSED ON COMPLETENESS. The critic loop exits only when no material gap/ambiguity/untestable18 criterion remains OR it stalls — and a stalled critic reports the open gaps, never a "looks complete"19 it didn't earn.206. SELECTED SCOPE OUTRANKS THE DRAFT. Preserve every intake `selectedScope[]` id in scope. Never move one21 to non-goals or deferred work; reducing selected scope is a per-id user decision, not a spec decision.22</EXTREMELY-IMPORTANT>2324# Auto Spec2526## Overview2728Produce the spec a strong engineer would write before touching code: grounded in what actually exists,29precise about behavior, testable in its criteria, honest about scope and risk — arrived at autonomously30through recon + draft + an adversarial completeness loop. The output is a spec downstream phases can plan31and test against without re-interviewing the user.3233## Phase 0: Intake — capture the request, detect blocking ambiguity3435- Capture `$request` verbatim as the source of scope. The request IS the scope; don't silently narrow or36 widen it.37- In a pipeline run, require and read the pre-plan intake snapshot; copy its `selectedScope[]`38 ids/titles/sources verbatim into a **Binding selected scope** checklist and record the snapshot path/hash.39 Do not accept the plan/spec's own copy as its authority. In a standalone run, if the caller supplies40 `selectedScope[]`, preserve it verbatim; if the user selected a named bundle, itemize it first. The41 checklist is authoritative over the draft and must not be regenerated from what the spec includes.42- Judge whether it's answerable from the repo + reasonable inference, or whether a genuine product43 decision blocks it (a fork where building the wrong branch is expensive). Only for the latter, ask a44 FEW targeted questions (`AskUserQuestion`) — never a long interview, never scope questions you could45 answer by reading the repo.46- Open a `checkpoint-resume` run.4748**Success criteria:** the request is captured; at most a few genuinely-blocking questions asked; recon49can proceed.5051## Phase 1: Recon — ground the spec in reality5253Before drafting, learn what exists (fan out with `fan-out-work` for a large repo):5455- the relevant existing code, modules, data models, and interfaces the change touches;56- prior art / patterns in the repo to stay consistent with;57- constraints that are real: the stack, existing contracts, invariants in `CLAUDE.md`/docs, data shapes,58 auth/security boundaries;59- the domain facts the request assumes;60- **prior-run lessons already in your loaded context** — `auto-learn` routes them into CLAUDE.md,61 `.claude/rules`, and auto memory (which Claude Code loads automatically), so constraints and failure62 patterns already paid for are in front of you: fold them into the spec's constraints/risks, don't63 rediscover them.6465Record what's grounded vs. what's an assumption — the draft will mark assumptions explicitly.6667**Success criteria:** a grounded picture of the current state and constraints the spec must respect.6869## Phase 2: Draft the spec7071Write `.ulpi/spec/<name>.md` covering (omit a section only when truly N/A, and say so):7273- **Objective** — the problem and the outcome, in one or two sentences.74- **Users & context** — who this is for and when it's used.75- **Behavior / user stories** — what the system does, from the user's view; the happy path AND the error76 and edge paths.77- **Acceptance criteria** — a checklist, each item TESTABLE (a condition you could assert). These become78 the plan's per-task criteria and the tests' targets.79- **Binding selected scope** — every intake id, unchanged, with the behavior/criteria that implement it.80- **Scope & non-goals** — explicitly in and explicitly OUT. Non-goals may contain only things the intake81 selection never included. Never put a selected id here.82- **Constraints & interfaces** — stack, contracts, data shapes, public interfaces affected, backward-compat.83- **Assumptions & open questions** — everything not grounded, named as such.84- **Risks** — security, data, irreversibility, performance — with the mitigation direction.8586**Success criteria:** a complete first draft; every acceptance criterion is phrased testably; assumptions87are marked, not hidden as facts.8889## Phase 3: The completeness-critic loop (converge until stable)9091Run `converge-loop` in until-dry mode with an adversarial critic as the finder — this is what makes the92spec strong:9394- each round, `adversarial-verify`-style critics attack the draft: missing behavior/edge/error case? an95 acceptance criterion that isn't testable? an ungrounded requirement? contradictory or ambiguous96 wording? a non-goal that should be stated? an unstated assumption? any selected-scope id missing,97 weakened, deferred, or placed in non-goals?98- apply the smallest fix per finding (tighten a criterion, add the missing case, mark the assumption, cut99 the invented requirement);100- re-critique; exit when a round finds no material gap (dry) OR it stalls. A stalled loop reports the101 remaining open gaps — it does not claim completeness.102103Use `AskUserQuestion` only if a surfaced gap is a real product decision; otherwise the critic resolves it104against the repo.105106**Success criteria:** no material gap/ambiguity/untestable criterion remains, or the open ones are107explicitly listed as open questions.108109## Phase 4: Finalize110111Write the stabilized spec to `.ulpi/spec/<name>.md`, close the checkpoint, and report where it lives + the112open questions (if any). This spec is the input to `auto-plan`.113114**Success criteria:** the spec file is written and self-consistent; open questions (if any) are flagged115for the user.116117## Common Rationalizations118119| Rationalization | Reality |120|---|---|121| "The request is clear enough, skip the spec." | Clear-to-you scatters into ten interpretations at build time. The spec is the shared contract that prevents that. |122| "I'll just assume the obvious behavior." | An unmarked assumption is an invented requirement. Mark it as an assumption or ask — don't smuggle it in as fact. |123| "'Works well' is a fine acceptance criterion." | Untestable criteria can't gate anything. If you can't write a test for it, it's a wish, not a criterion. |124| "I don't need non-goals, the scope is obvious." | Unstated non-goals are the entry point for scope creep. Name what's out. |125| "The critic found nothing new, one round is enough." | One round rarely exhausts the gaps. Loop until a round is genuinely dry, then stop. |126| "I'll reference a config/endpoint that probably exists." | A phantom path in the spec becomes a phantom in the code. Ground it or mark it unknown. |127| "This selected feature cannot fit this pass, so I will call it a non-goal." | That silently reduces the user's scope. Keep it selected and attempt it; unfinished work is BLOCKED. Only the user may drop its id. |128129## Red Flags130131- Requirements, paths, or endpoints in the spec that don't exist in the repo and aren't marked assumptions.132- Acceptance criteria you couldn't write a test for.133- A spec with in-scope items but no non-goals.134- The critic loop ran exactly once.135- Long clarification interviews for things readable in the repo.136- A "complete" verdict with unresolved contradictions still in the text.137- A selected-scope id missing from the spec, weakened into a non-goal, or pre-emptively deferred.138139## Guardrails140141- Never invent requirements/paths/constraints; ground them or mark them assumptions.142- Never emit an untestable acceptance criterion.143- Never omit explicit non-goals.144- Never put a selected-scope id in non-goals or deferred work. If it cannot be completed, keep it selected145 and surface it as BLOCKED; record a drop only after an explicit user decision naming that id.146- Never resolve a real product decision silently — ask (briefly) or flag it open.147- Never report the spec complete while the critic still finds material gaps.148149## When To Load References150151- `fan-out-work` (skill) — parallel recon across a large codebase in Phase 1.152- `adversarial-verify` (skill) — the completeness critics in Phase 3.153- `converge-loop` (skill) — the until-stable critic loop (termination + anti-thrash).154- `checkpoint-resume` (skill) — durable spec-run state.155156## Output Contract157158Report:1591601. the spec file path (`.ulpi/spec/<name>.md`), independent intake snapshot path/hash, and objective1612. selected-scope coverage (`N of M`) against that snapshot with every selected id, then the acceptance-criteria count and162 explicit non-goals1633. any per-id user-approved drops, assumptions made, and open questions surfaced for the user1644. critic-loop outcome (rounds to stable, or the honest remaining gaps)