Specify
Turn approved intent into a lintable, testable SpecScore Feature.
Hard Gate
This applies to every Feature, regardless of perceived simplicity. The only skills invoked after specstudio:specify are writing-plans (Plan) or specstudio:implement (Implement), as chosen by the user at the transition menu.
When to Use
- A SpecScore Idea is
Approvedand ready to become a Feature. - User has a clear, high-conviction buildable intent (may skip
specstudio:ideate). - Behavior of an existing Feature needs to change — revise in place (see path-conventions.md).
Anti-Pattern: "This Is Too Simple To Need A Spec"
Every Feature goes through this. A toggle, a one-line config, a single utility — all of them. Simple Features are where unexamined assumptions cost the most. The spec can be short (a few sentences for truly simple Features), but it must be written and approved.
Pre-Flight
- Inputs check. If triggered from an approved Idea, load it and list the Idea's assumptions that this Feature must validate. If no Idea exists, ask: "Is this ready to specify, or should we ideate first?" — don't force
specstudio:ideateon high-conviction users. - Scope decomposition. If the intent spans multiple independent subsystems, stop and help the user decompose into multiple Features before continuing.
- Revision vs new. If a Feature with this slug already exists, decide: revise in place (default) or create a successor and set
**Supersedes:** <old-slug>in the new Feature's body metadata (only when scope change invalidates existing ACs). See path-conventions.md.
Checklist
Create a task for each and complete in order:
- Explore project context — existing Features, recent commits, related specs.
- Scope decomposition check.
- Offer visual companion (if visual questions are ahead) — own message, no other content. See visual-companion.md (still TBD — see the analysis doc §11.1).
- Ask clarifying questions — one at a time, multiple-choice preferred. See question-cadence.md.
- Propose 2–3 approaches with trade-offs; lead with your recommendation. Use
specstudio:ideatelenses (inversion, constraint removal, simplification) where useful. - Present spec sections one at a time, get approval after each.
- Create the Feature artifact — run
specscore feature new <slug>(the required-CLI creation path; see## Artifact Creation), then FILL the scaffolded sections (REQs, ACs, etc.) viaEdit. Topics group under### <Topic>headings inside## Behavior, each containing one or more#### REQ: <slug>requirements. - Rehearse stub decision — per-AC heuristic. See rehearse-heuristic.md.
- Lint —
specscore spec lint. - Inline self-review — placeholders, consistency, scope, ambiguity.
- Run the reviewer gate — load and dispatch
gates.specify.reviewersfromspecscore.yamlper the Reviewer Gates Feature. See the## Reviewer Gatesection below. - Publication + events — maintain a checkpoint manifest for the Feature README, optional
_tests/, assets, indexes, and CLI-reported touched paths. Apply publication-policy.md forfeature.specifiedafter lint passes and before reviewer-gate dispatch, then emitfeature.specifiedwithpublication_result. After the reviewer gate releases, apply policy forfeature.approved, then emitfeature.approved(carrying the releasedgradeandpublication_result) and write the**Grade:**body-metadata line per Step 4. See events.md. - Transition — present the transition menu (see
## Transition). - Throughout — watch for sidekick ideas per sidekick-capture.md. When an out-of-scope improvement surfaces, invoke
specstudio:sidekickwith a one-liner, acknowledge in one line, and return to the current checklist step immediately. Do not derail to discuss the sideline idea.
Spec Sections (scale to complexity)
- Purpose & user job — from the Idea's HMW if applicable, or restated here.
- Requirements — numbered, each with ≥1 acceptance criterion.
- Architecture & components — isolation, interfaces, dependencies. Each unit: what does it do, how is it used, what does it depend on?
- Data flow.
- Error handling & failure modes.
- Testing strategy — references Rehearse stubs (or explains why none).
- Not Doing / Out of Scope — inherited from Idea + spec-level cuts.
- Assumption carryover — which Idea assumptions survive; which are now invalidated or answered.
Artifact Layout
A Feature is a single README.md (plus optional _tests/ and assets/):
spec/features/<slug>/
├── README.md # The Feature artifact (single file)
├── _tests/ # Optional — Rehearse scenarios (see shared/rehearse-heuristic.md)
│ ├── <scenario-1>.md
│ └── …
└── assets/ # Optional — diagrams, mockups
The skill carries no embedded schema — specscore feature new is the single source of truth for the Feature's structure (title prefix, body metadata, ## Behavior / #### REQ: / ## Acceptance Criteria sections). For a read-only spec reference, see https://specscore.md/feature-specification — never fetch it to write the file; the CLI scaffold produces the canonical structure.
Artifact Creation
Creation is required-CLI. specscore feature new <slug> is the ONLY way to create the Feature artifact — it produces a lint-clean skeleton by construction and updates the features index for you. There is no direct-write fallback: the CLI scaffold is the single source of truth for the Feature's structure. This follows the Required-CLI Artifact Creation policy — see the Creation-class row in ../shared/cli-detection.md.
Step 1 — Run the creation call and branch on exit status
Do not run a standalone command -v probe. Invoke specscore feature new <slug> (passing the fields you already have) and branch on its exit status per the Creation-class row in ../shared/cli-detection.md (which carries the per-outcome rationale): 0 → scaffold written, continue to Step 2; 127 → install message (/specscore:install), then install-then-retry; exit 8 → upgrade-then-retry, naming the missing feature new subcommand; any other non-zero → surface verbatim, never a direct-write fallback.
Step 2 — Fill the scaffolded sections
With the lint-clean skeleton in place, FILL its sections via Edit: the ## Summary, ## Problem, ## Behavior topics with their #### REQ: <slug> rules, and the ## Acceptance Criteria in Given / When / Then form. Preserve the scaffold's lint-clean structure — never replace it with a hand-authored layout.
Acceptance Criterion Format
Every AC uses Given / When / Then. This is enforced by lint rule F-004.
Scenario: <short name>
Given <precondition that sets state>
When <action the system or user takes>
Then <observable outcome that can be checked>
If you can't phrase an outcome as Then <observable>, the AC is too abstract — sharpen it.
Rehearse Stub Decision
After drafting ACs, for each one apply the heuristic in rehearse-heuristic.md:
- Testable (has CLI/HTTP/pure-fn/data/UI-selector/fs/event surface): scaffold
spec/features/<slug>/_tests/<req-slug>-<ac-slug>.mdwith**Status:** pendingbody metadata. - Not testable (subjective, abstract, undefined observer, doc-only Feature): skip; record reason in the Feature's
README.mdunder## Rehearse Integration.
The user can always override the heuristic.
Inline Self-Review
Check:
- Placeholder scan —
TBD,TODO, incomplete sections, vague requirements. - Internal consistency — architecture matches feature descriptions; requirements align with ACs.
- Scope check — focused enough for one implementation plan? If not, decompose.
- Ambiguity check — could any requirement be interpreted two ways? Pick one; make it explicit.
Fix inline. Don't re-review; move on.
Reviewer Gate
The reviewer gate — including the user's own approval — is consumed from the typed-per-stage Reviewer Gates contract. The skill carries NO hardcoded baseline reviewer and runs NO separate downstream user-approval step. The reviewer list comes exclusively from gates.specify.reviewers in specscore.yaml; the user's approval is collected through a type: human entry in that list like any other reviewer.
Step 1 — Update status to In Review
Before dispatching the gate, update the Feature's **Status:** body-metadata line from Draft to In Review. Re-run lint to confirm the transition is clean.
Step 2 — Load and validate the gate config
Follow the protocol in shared/reviewer-gates/loader.md with <skill> = specify. The loader reads gates.specify.reviewers from specscore.yaml, validates every entry's shape (per the Reviewer Gates Feature's reviewer-entry-required-fields, mvp-type-set, ai-entry-shape, human-entry-shape, no-untyped-entry REQs), and returns an ordered list of validated entries.
If the loader refuses (missing gates: key, missing gates.specify, empty reviewers: [], any per-entry validation failure), surface its error verbatim and halt. Do NOT dispatch any reviewer, do NOT fall back to a built-in baseline, do NOT run a separate user-approval step, and do NOT emit any approval event.
Step 3 — Run the gate
Follow the protocol in shared/reviewer-gates/runner.md, passing the validated reviewer list returned by the loader. The runner:
- Dispatches every entry serially in declared list order. For
type: ai, the Agent tool is invoked with the entry'spromptfile as the system prompt and the FeatureREADME.mdas the user-facing message. Fortype: human, the user is presented with the Feature and the approval-phrase recognizer described in## Approval-Phrase Recognitionbelow collects the verdict. - AND-composes the verdicts: the gate releases only when every entry returns
Approved. On the firstIssues Foundverdict in a pass, the runner halts — subsequent entries in that pass are NOT dispatched. - On rerun (after the user addresses findings), re-dispatches per the runner's
rerun-policy: every previously-Issues Foundreviewer always, every previously-Approvedreviewer when the fix touched a structural section (## Behavior,## Architecture, or## Acceptance Criteria).
The skill MUST dispatch exactly the entries in gates.specify.reviewers — no more, no less. It MUST NOT additionally dispatch any reviewer hardcoded inside this skill's own logic, and MUST NOT silently inject a built-in baseline. The runner's verdict map is the sole gating signal.
Step 4 — On Approved
When the runner returns Approved (the released grade satisfies grade ≥ threshold):
- Update
**Status:** In Review → Approvedin the body metadata. - Record the grade (per
reviewer-gates#req:grade-recording): write the runner's released grade as a**Grade:** <letter>body-metadata line immediately after**Supersedes:**— add it if absent, update it in place if already present. - Re-run lint to confirm the transition + grade line are clean.
- Apply publication policy for
feature.approvedusing a manifest that includes the Feature README, generated companion files, and any CLI-reported touched paths. This runs only after the gate releases; policy MUST NOT bypass reviewer or human approval. - Emit
feature.approvedwithgrade: <letter>andpublication_resultin the payload (see Checklist step 12 and events.md). - Proceed to
## Transition.
Step 5 — On Issues Found
When the runner returns Issues Found, surface the failing reviewer's name and every Blocker-severity finding verbatim. Advisory findings SHOULD also be surfaced (clearly labeled). Address every Blocker inline (edits to the Feature README.md), re-run lint, then re-invoke the runner per its rerun-policy. Do NOT emit feature.approved while any reviewer's last verdict is Issues Found.
Post-Approval Iteration
When revising an already-approved Feature in place, keep the existing status (Approved, Implementing, or Stable) unless a separate lifecycle rule requires a transition. After every successful lint pass following the edit, apply publication policy for feature.updated using the changed paths manifest, then emit feature.updated with publication_result. Do NOT re-emit feature.approved.
Approval-Phrase Recognition
When the runner dispatches a type: human entry, it presents the Feature to the user with a prompt such as:
"Feature written and lint-clean at
spec/features/<slug>/. The reviewer gate is waiting on your approval. Please review and let me know if you approve or want changes before we choose the next step."
The recognizer maps the user's response per the same explicit-approval phrase set used by specstudio:ideate:
- Explicit approval phrase — English
approve,approved,accept,accepted,lgtm, plus direct semantic equivalents in any language the user is communicating in (e.g.,aprobar,承認,одобрено,批准). The criterion is semantic: the phrase must function as a verb form meaning "I give explicit approval" in the source language. On detection of any qualifying phrase as a standalone or dominant response → verdictApproved. - Explicit change request — the user names a concrete change they want before approving → verdict
Issues Foundwith the user's change-request text captured as a singleBlockerfinding under the human entry'sname:. - Vague positive signal (e.g.,
looks good,yeah,nice,ship it,+1,🚀,yes,ok,sí,oui,да,はい) — not yet a verdict. Ask one explicit confirmation question (e.g., "Treat that as approval?") and wait. Silent transition on a vague signal is a contract violation.
Transition
After the reviewer gate releases and feature.approved is emitted, present the user with a structured choice via AskUserQuestion:
Step 1 — Count ACs and check config
- Count the number of
### AC:entries in the Feature's## Acceptance Criteriasection. - Read
specscore.yamland checklifecycle.suggest_skips(default:truewhen the key is absent).
Step 2 — Present the menu
Present exactly two options. Plan is always listed first as the default.
When lifecycle.suggest_skips is true (or absent) AND the Feature has ≤2 ACs:
"Feature approved. Choose your next step:"
- Plan — ordered task list with AC mapping (default)
- Implement (skip plan) — code directly from the Feature (suggested for small scope)
When lifecycle.suggest_skips is false, OR the Feature has >2 ACs:
"Feature approved. Choose your next step:"
- Plan — ordered task list with AC mapping (default)
- Implement (skip plan) — code directly from the Feature
The "(suggested for small scope)" label appears ONLY when both conditions are met: the Feature has ≤2 ACs AND lifecycle.suggest_skips is not false. The suggestion MUST NOT auto-select — the user MUST explicitly choose.
Step 3 — Route
If the user chooses Plan (default):
- Do NOT emit
lifecycle.phase-skipped. - Invoke
writing-planswith the Feature slug.
If the user chooses Implement:
- Emit
lifecycle.phase-skippedwith:from_phase: specify skipped_phases: [plan] to_phase: implement reason: user-requested # or scope-suggested if the heuristic label was shown and the user confirmed source_artifact: type: feature path: spec/features/<slug>/README.md slug: <slug> - Then invoke
specstudio:implementwith the Feature slug as the source artifact.
Visual Companion (Optional)
Status: decision pending — see spec/research/ideate-vs-brainstorming-skills-analysis.md §11.1.
Until the visual-companion strategy is decided, prefer these lightweight visual aids in text:
- Mermaid diagrams embedded in
README.md(most IDEs and GitHub render these natively). - ASCII diagrams for simple flows.
- Static SVGs committed to
spec/features/<slug>/assets/for complex visuals.
If the user has obra/superpowers installed, we may reuse its browser-based visual companion — pending a formal integration decision.
Verification
-
spec/features/<slug>/README.mdexists -
## Behaviorcontains at least one#### REQ: <slug>requirement (scoped under a###topic heading) - Every requirement has ≥1 acceptance criterion
- Every AC is
Given / When / Then -
specscore spec lintpasses - Reviewer gate released — every entry in
gates.specify.reviewers(including thetype: humanentry) returnedApproved -
**Status:** Approvedin body metadata - Rehearse decision recorded (stubs scaffolded OR skip-reason noted)
- Source Idea (if any) linked via the
**Source Ideas:**body-metadata line — lifecycle tooling handles the reverse link - Publication policy applied at
feature.specifiedandfeature.approvedcheckpoints with manifest disclosure -
feature.specified+feature.approvedevents emitted withpublication_result
Red Flags
- Proceeding to
writing-plansorspecstudio:implementbefore the reviewer gate releases - Dispatching a hardcoded baseline reviewer not present in
gates.specify.reviewers - Running a separate downstream user-approval step outside the
type: humanreviewer entry - Silently downgrading a
Blockerfinding toAdvisory, or skipping a registered reviewer - Requirements without ACs
- ACs not in
Given / When / Then - "Too simple to spec" rationalization
- Scope spanning multiple subsystems
- Assumptions from the source Idea silently dropped
- Writing to
docs/superpowers/specs/instead ofspec/features/<slug>/ - Silently routing to
writing-planswithout presenting the transition menu - Invoking any skill other than
writing-plansorspecstudio:implementon transition - Hard-coding stage-only handoff behavior instead of resolving publication policy for
feature.specifiedorfeature.approved - Letting publication policy bypass the reviewer gate or the
type: humanapproval entry
Autonomous Mode (decide-and-record)
When a run-scoped autonomy signal is active (an autonomous run driven by specstudio:autopilot — see autonomy-autopilot.md), the clarifying/approach/section questions are not asked via AskUserQuestion. Instead, take the documented default and record it:
- Scope check: proceed-not-decompose when the intent is single-scope (only a genuine multi-subsystem scope still stops, as an anomaly rather than a question).
- Approach proposal: pick the recommended approach from the 2–3 proposal without prompting.
- Section review: accept each spec section as drafted.
- Record the trail: every auto-made choice is written as one bullet in a
## Autonomous Decisionssection on the Feature (H2 near the end; what — alternatives — why the default). Omit the section entirely when no decision was auto-made; keep the Feature lint-clean. - The reviewer gate still runs. Under autonomy the
type: humanentry ongates.feature.approvedis masked by the reviewer-gates runner (Step 1.6), but thetype: aireviewer still dispatches and still blocks onIssues Found. Autonomy releases approval, never quality.
Non-autonomous runs are unchanged — this branch only applies while the signal is active.
References
- Reviewer Gates Feature — canonical typed-per-stage
gates:schema, reviewer entry shape, AND-composition, and rerun policy. - shared/reviewer-gates/loader.md — load-and-validate protocol for
gates.specify.reviewers. - shared/reviewer-gates/runner.md — dispatch and verdict-aggregation protocol.
- references/reviewer-prompt.md — baseline reviewer prompt; opt-in via a
type: aientry ingates.specify.reviewers. - visual-companion.md — visual companion strategy (decision pending).
- philosophy.md — shared tenets.
- path-conventions.md —
spec/vsdocs/rules. - publication-policy.md — checkpoint resolution, manifest safety, first-run preference prompt, and publication disclosure.
- specscore-lint-rules.md — lint contract this skill assumes.
- events.md — event payloads emitted by this skill.
- question-cadence.md — when to batch vs single-question.
- rehearse-heuristic.md — per-AC testability decision.