Test-Driven Development
Guide the user through Red-Green-Refactor cycles to implement a feature or fix a bug test-first. Each cycle: write a failing test (Red), write the minimum code to pass it (Green), clean up while tests stay green (Refactor). One behavior per cycle.
This skill is for new features and bug fixes — not refactoring. For restructuring existing code without changing behavior, use /optimus:refactor instead (existing tests verify behavior is preserved).
The Iron Law
No production code without a failing test first. If implementation code is written before its test, delete it entirely and begin the cycle fresh. Do not preserve it as reference, do not adapt it — write the implementation from scratch once the failing test exists. This is the non-negotiable foundation of every step that follows.
Coming from plan mode? TDD runs in normal mode, in a fresh conversation. If you were iterating on a plan-mode prompt generated by
/optimus:brainstormor/optimus:jira, toggle plan mode off without approving (see$CLAUDE_PLUGIN_ROOT/references/skill-handoff.mdfor client-specific controls), let Claude append the "Refined plan" section to the design or JIRA doc, then start a fresh conversation before invoking this skill — TDD will auto-detect the updated doc.
Step 1: Pre-flight
Read $CLAUDE_PLUGIN_ROOT/skills/init/references/multi-repo-detection.md for workspace detection. If a multi-repo workspace is detected, process each repo independently: run Steps 1–9 inside the repo the user is targeting. If ambiguous, ask which repo.
Verify prerequisites
Check that .claude/CLAUDE.md exists. If it doesn't, stop and recommend running /optimus:init first — coding guidelines and project context are essential for the Refactor step.
Load these documents (they affect quality at every step):
| Document | Role | Effect on skill |
|---|---|---|
.claude/CLAUDE.md | Project overview | Tech stack, test runner command |
coding-guidelines.md | Code quality reference | Applied during Refactor step |
testing.md | Testing conventions | Test file location, naming, framework, mocking patterns |
Monorepo path note: Read the "Monorepo Scoping Rule" section of $CLAUDE_PLUGIN_ROOT/skills/init/references/constraint-doc-loading.md for doc layout and scoping rules. When running TDD inside a subproject, load that subproject's testing.md, not another subproject's.
Verify test infrastructure
Locate the test runner command from testing.md, CLAUDE.md, or project manifests (package.json scripts, Makefile, Cargo.toml, etc.). Run it once to confirm it works.
- Tests pass — proceed to Step 2 (Suitability Analysis)
- Tests fail — stop and report. Existing failures must be resolved before TDD can begin (a failing suite makes Red/Green indistinguishable)
- No test runner found — stop and recommend running
/optimus:initfirst to set up test infrastructure (framework, runner, coverage tooling,testing.md)
Step 2: Suitability Analysis
Before starting TDD cycles, analyze whether the user's task is a good fit for test-driven development.
Gather the task
Context detection (runs at Step 2 entry — the cascade below is evaluated in order regardless of whether the user provided an inline task description; first match wins):
-
Explicit reference — if the user's input references a file path ending in
.mdinsidedocs/design/ordocs/jira/, read that file and use its Goal section as the task description. Proceed to distillation below if the goal is longer than 2-3 sentences. -
Design doc auto-discovery — if item 1 did not fire and
docs/design/exists with.mdfiles, check the most recent one (by filename date prefix). If its date is within the last 7 days, mention it: "Found design doc<path>— use it as the basis for TDD?" viaAskUserQuestion— header "Design doc", options "Use it" / "Ignore — describe a different task". If its date is older than 7 days, add a note: "(This design doc is [N] days old — you may want to re-run/optimus:brainstormfor a fresh design.)" Design docs contain full approach details from/optimus:brainstorm— use Goal, Components, and Interfaces sections as the task description. -
JIRA context auto-discovery — if no design doc found (or user ignored it) but
docs/jira/exists with.mdfiles, read each file's YAML frontmatter and select the one with the most recentdatefield. If its date is within the last 7 days, mention it: "Found JIRA context<path>— use it as the basis for TDD?" viaAskUserQuestion— header "JIRA context", options "Use it" / "Ignore — describe a different task". If its date is older than 7 days, add a note: "(This context is [N] days old — you may want to re-run/optimus:jirafor fresh data.)" JIRA context provides Goal and Acceptance Criteria as the task description. -
No context found — proceed with normal task gathering below.
Design docs take priority over JIRA files because they are more detailed (they incorporate JIRA context if brainstorm consumed it). Detected context feeds into the existing task-gathering cascade below — it does NOT bypass Step 3 decomposition. TDD still independently decomposes the goal into behaviors, except when a ## Scenarios section is present (see the scenario-driven shortcut in Step 3).
If context detection above resolved a task description (user accepted a design doc or JIRA context), use it — skip the inline/prompt gathering below. Otherwise, if the user provided a task description inline (e.g., /optimus:tdd "Add auth endpoint"), use it. Otherwise, use AskUserQuestion — header "TDD scope", question "What feature or bug fix do you want to implement with TDD?":
- New feature — "Implement a new capability (e.g., 'Add user authentication endpoint')"
- Bug fix — "Fix a bug by reproducing it with a test first (e.g., 'Login fails when email has uppercase')"
If the task description is longer than ~2-3 sentences (e.g., a pasted spec, JIRA ticket, or acceptance criteria list), distill it into a single-sentence goal and confirm with AskUserQuestion — header "Distilled goal", question "I've distilled your spec to: '[single-sentence summary]'. Is this accurate?":
- Looks good — "Proceed with this goal"
- Adjust — "Let me refine the focus"
Analyze suitability
Examine the task description against the codebase and classify it:
Suitable for TDD — proceed silently to Step 3:
- New features with testable behavior (API endpoints, business logic, data transformations, utilities)
- Bug fixes where the bug can be reproduced with a test
- Adding capabilities to existing modules
- Large features (frontend + backend, multi-component) — these are suitable but need careful decomposition in Step 3
Not suitable for TDD — stop and redirect:
- Refactoring (restructuring code without changing behavior) → recommend
/optimus:refactor - Documentation-only changes (README, comments, CLAUDE.md) → no testable code
- Pure styling/cosmetic changes (CSS colors, spacing, fonts with no logic) → no testable logic
- Configuration changes (environment variables, CI/CD, linter config) → no testable behavior
- Deleting code/features without replacement → tests should be removed, not added
- Generated code (protobuf, OpenAPI, ORM migrations) → generated output, not hand-written behavior
If not suitable, report to the user:
## Task Analysis
**Task:** [user's description]
**Suitability for TDD:** Not recommended
**Reason:** [specific explanation — e.g., "This is a refactoring task — it changes code structure
without adding new behavior. TDD is for building new behavior test-first."]
**Recommended approach:** [specific skill or approach — e.g., "/optimus:refactor restructures code
while using existing tests as a safety net."]
If ambiguous (the task has both testable and non-testable