Implement the feature described in a spec file. $ARGUMENTS should be the spec filename (without path or extension), e.g. export-zip. If no argument is given, use the most recently modified file in .claude/specs/.
-
Read the spec from .claude/specs/<name>.md
-
Read CLAUDE.md — note the project's test command, lint command, build command, and typecheck command if listed
-
Read all files in .claude/context/ if the directory exists — long-lived project references (schemas, API docs, glossaries)
-
Read all files listed under "Affected files", "New files", and "Patterns to mirror" in the spec — the "Patterns to mirror" files are the primary convention references; follow their structure, naming, and style
4b. Context budget check: count the total files from steps 3 and 4. If the total exceeds 15, read "Patterns to mirror" files in full and only read the relevant sections of remaining files. Note which files were fully read vs. partially read.
-
Decomposition gate: count the total files listed under "Affected files" + "New files". If the total exceeds complexity_gate_max_files from CLAUDE.md (default: 10), or if the spec has a ⚠ Complexity flag, pause and ask the user whether to proceed as a single session or break the spec into smaller sub-specs first. Continue only after confirmation.
-
Create a safety checkpoint: if the project uses git and checkpoint/<spec-name> does not already exist (e.g., already created by /ship), run git checkout -b checkpoint/<spec-name> from the current branch, then immediately switch back with git checkout -. This creates a named rollback point that survives crashes and avoids stash collisions. Skip if the checkpoint branch already exists or the working tree is already clean (no staged or unstaged changes).
-
Enter plan mode: propose a step-by-step implementation plan and wait for approval before writing any code
-
Phase management — check whether this is a phased implementation:
a. If .claude/specs/<name>-phases.md already exists (resuming a later phase): read it, find the next pending phase, set its status to in-progress, and implement only that phase's scope. If all phases are done, report completion and stop.
b. If no phase manifest exists but the approved plan proposes splitting into multiple phases: write .claude/specs/<name>-phases.md using the format below. Mark Phase 1 as in-progress, others as pending. Implement only Phase 1.
c. If no phases are needed, skip the phase manifest and proceed normally.
Phase manifest format (.claude/specs/<name>-phases.md):
# Phases for <name>
## Phase 1 — <title>
Status: in-progress
Scope:
- <spec requirement covered in this phase>
Validation criteria:
- <criterion from spec that applies to this phase>
## Phase 2 — <title>
Status: pending
Scope:
- <spec requirement covered in this phase>
Validation criteria:
- <criterion from spec that applies to this phase>
## Artifact coverage
Every file from the spec's "Affected files" + "New files" must appear in exactly one phase above.
Unassigned:
- (none)
Phase reconciliation (mandatory when creating or resuming a phase manifest):
Before proceeding, cross-reference the spec's "Affected files" + "New files" lists against all phases in the manifest. Every spec artifact must be assigned to exactly one phase. If any artifact is missing from all phases, add it to the appropriate phase or create an additional phase for it. The "Unassigned" block in the manifest must be empty — if it is not, stop and resolve before continuing. This prevents silent scope loss where entire subsystems (e.g. frontend) are dropped during decomposition.
When in phased mode, all subsequent steps (9-18) apply only to the current phase's scope and validation criteria — do not flag later-phase items as missing.
-
After approval, implement each step in order, marking todos as you go. For each logical unit of code added, apply the TDD loop: (a) write the test cases from the spec's "Test cases" section, (b) run the tests to confirm they fail (red) — if the test runner cannot find the test file at all, that counts as red; do not skip this step, (c) implement the code, (d) run tests again to confirm they pass (green). Do not defer tests to the end. Do not proceed to the next unit until the current unit is green.
9b. Impact check — before modifying a shared function's signature (adding/removing/renaming params, changing return type), run an impact analysis first:
- Grep for all call sites of the function across the codebase
- Grep for all test mocks that patch it (
patch("...function_name"), vi.mock)
- List every site that needs updating alongside the signature change
- Update ALL call sites and mocks in the same step — do not leave stale call sites for a later step
- If the blast radius is large (>10 call sites), pause and flag to the user before proceeding
- This prevents the recurring pattern: "changed helper, forgot 6 call sites, broke unrelated tests"
-
Follow existing code patterns — match the style, naming conventions, and architecture of surrounding code
-
Do not add comments, docstrings, or extra error handling beyond what the spec requires
-
After all changes are made, run the project's verify commands in this order (read them from CLAUDE.md, skip any not listed):
a. Typecheck (e.g. tsc --noEmit or equivalent)
b. Lint
c. Tests
d. Build (if a build command is listed)
-
Fix any failures — if a verify step still fails after two fix attempts, stop and report the blocker to the user. Do not loop indefinitely.
13b. Write the blocker to .claude/blockers/<spec-name>.md with: which verify step failed, the exact error message, what was already attempted, and suggested next action for the user.
-
Validation criteria gate: read the spec's "Validation criteria" section. For each criterion, confirm it can be observed in the current implementation. If any criterion cannot be confirmed, treat it as a failure and fix it before proceeding.
14b. Artifact inventory check — extract every file path from the spec's "Affected files" + "New files" sections. If in phased mode, filter to only the files assigned to the current phase. Run git diff --name-only (against the branch point or checkpoint) and compare:
If running as a subagent (no direct user interaction), skip the question and return the structured summary instead.
Do not summarize and stop. Always end with a direct question to the user.