Skip to main content

/fix

Bugfix workflow with TDD. Investigates the bug, writes a failing test, fixes at the root cause, verifies end-to-end against the running program, finishes. No plan file, no approval mid-flow, no separate verify phase.

Use /fix for bugs. Use /spec for features and architectural changes — including bugfixes that warrant a full plan with approval and code review.

$ pilot
> /fix "annotation persistence drops fields between save and reload"
> /fix "off-by-one in pagination at boundary"
> /fix "wrong default for max_retries"

/fix is always quick. If investigation reveals the bug is multi-component, architectural, or otherwise larger than a quick fix, /fix stops cleanly and tells you to re-invoke with /spec. It does not silently switch lanes.

Workflow

Investigate  →  RED  →  Fix  →  Verify End-to-End  →  Quality Gate  →  Done

Investigate

Trace the bug to file:lineN — function() does X but should do Y with High or Medium confidence. For UI / async / race / timing bugs that don't surface from a static read, add temporary SPEC-DEBUG:-marked logs at component boundaries before tracing. Low confidence bails out.

RED — Write the Reproducing Test

Encode Currently → Expected via an existing public entry point. Run it; it must fail with an error matching the symptom. A test that passes against buggy code doesn't encode the bug.

Fix at the Root Cause

Minimal change at the root cause. Symptom patches (try/except hiding the bug, swallowed returns, silently normalised inputs) are forbidden. Re-run the reproducing test → must pass. Run the targeted test module(s).

A diff sanity check follows: root-cause file IS in the diff, no unplanned files, < 20 lines typically. A grep over the diff catches symptom-patching and leftover print / console.log / SPEC-DEBUG: markers — every match must be justified or reverted.

Verify End-to-End

The primary correctness signal. Run the actual program with the original input and observe the symptom is gone — a passing unit test alone is never accepted. This step is mandatory.

Bug surfaceToolEvidence
UI / web4-tier browser stack: Claude Code ChromeChrome DevTools MCPplaywright-cliagent-browserPage state, element values
CLIThe exact command the user ranStdout, exit code
HTTP APIcurl / HTTP client with the user's bodyStatus code, response field
Library / SDK / functionpython -c '…', node -e '…', REPL, scratch scriptReturned value
Background jobTrigger manually with the failing inputLogs

The completion report must include concrete evidence — bare assertions ("looks fixed", "tests pass") are insufficient. If the symptom persists, the unit test is at the wrong layer: move the assertion up to the user's actual entry point and re-run RED → Fix → Verify End-to-End.

Quality Gate

Lint + types + build (when applicable), then the full anti-regression suite, once. If a far-from-the-fix test breaks, the bug has unintended cross-coupling — bail out to /spec.

Finalise

Worktree mode: bundle test + fix into one fix: commit. Approval gate fires only if Plan Approval is enabled. The completion report includes a mandatory E2E line documenting what was actually run.

When to bail out — use /spec instead

/fix stops and tells you to re-invoke with /spec when:

  • Bug spans 3+ files or 2+ components.
  • Root cause is architectural, not a single line.
  • Fix needs defense-in-depth at multiple layers.
  • Confidence stays Low — root cause can't be pinned to file:line.
  • Two failed fix attempts.
  • Fix has non-trivial UI implications that warrant a recorded Verification Scenario.

The full lane (/spec) adds: Behavior Contract, three-task structure, plan file with approval gate, Console annotation cycle, cp+trap revert-test proof in verify, iteration cap at 3.

Common issues

SymptomWhat it meansWhat to do
Can't reproduceDescription too vague or environment-dependentAsk for exact steps, env, stack trace. Don't write a speculative fix.
Test passes without the fixTest doesn't encode the bugTighten the assertion or pick a more specific input.
Fix breaks far-away testsCross-coupling beyond the quick laneBail out. Re-invoke with /spec.
Reproducing test green but user still hits the bugTest sits below the user's layerMove the assertion up and re-run RED → Fix → Verify End-to-End.
Two failed fix attemptsArchitectural problem, not a fix problemBail out. The pattern needs reconsidering, not another patch.

Configurable Toggles

/fix honours the same Console Settings as /spec:

ToggleDefaultEffect when disabled
Ask QuestionsOnInvestigation skips clarifying questions and uses defaults.
Plan ApprovalOnThe end-of-flow approval gate is skipped.

When both are off, /fix runs end-to-end with no user interaction. Worktree isolation is not honoured — use /spec if you want a worktree.

When to use /spec vs /fix

Use /fixUse /spec
Something is brokenBuilding new functionality
You want a fix without ceremonyArchitecture or design decision matters
You want it done nowWork warrants a written plan + approval

/fix handles the full range — from typos to multi-step debugging. It bails out and points to /spec only when complexity is truly architectural (multiple components, defense-in-depth at multiple layers, repeated failed attempts).