Help us improve
Share bugs, ideas, or general feedback.
From optimus
Guides Red-Green-Refactor cycles for test-first feature implementation and bug fixes. Requires /optimus:init and working test infrastructure.
npx claudepluginhub oprogramadorreal/optimus-claude --plugin optimusHow this skill is triggered — by the user, by Claude, or both
Slash command
/optimus:tddThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
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.
Enforces strict test-driven development: write a failing test first, then minimal code to pass, then refactor. Activates when TDD is explicitly requested or chosen for an atomic task.
Enforces test-driven development for features, bug fixes, and refactoring. Requires failing tests before any production code, with guidance on test types and spec-to-test mapping.
Share bugs, ideas, or general feedback.
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).
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 spec or JIRA doc, then start a fresh conversation before invoking this skill — TDD will auto-detect the updated doc.
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.
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 |
docs/product/tech-stack.md (if present) | SDD steering — target stack | Low-priority context for Step 3 decomposition and Refactor |
docs/product/mvp-prd.md (if present) | SDD steering — MVP scope | Low-priority context that informs decomposition |
The two docs/ rows are the optional spec-driven-development steering cascade (scaffolded by /optimus:spec-init). Load them only if they exist; they inform decomposition and the Refactor step but never replace the task source or the behavior decomposition. See $CLAUDE_PLUGIN_ROOT/references/sdd-mapping.md for the precedence contract.
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.
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.
/optimus:init first to set up test infrastructure (framework, runner, coverage tooling, testing.md). For a project with no code or detectable stack yet, tell the user to pick Scaffold new project when init asks — init builds a starter stack, then sets up the runner on it (so this is not a dead-end).Before starting TDD cycles, analyze whether the user's task is a good fit for test-driven development.
Resolve the task description with the shared cascade in $CLAUDE_PLUGIN_ROOT/skills/tdd/references/spec-context-detection.md (explicit docs/specs//docs/jira/ reference → build-spec auto-discovery → JIRA auto-discovery → none, plus long-spec distillation to a single-sentence goal).
If that cascade resolved a task description (the user accepted a spec or JIRA context), use it — skip the 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?":
Whatever the source — a spec or JIRA context the cascade resolved, an inline argument, or the answer above — apply the shared reference's Distillation step to the final task description: if it runs longer than ~2-3 sentences, distill it to a single-sentence goal and confirm via AskUserQuestion before proceeding.
Detected context feeds into this task-gathering — it does NOT bypass Step 3 decomposition. TDD still independently decomposes the goal into behaviors, except when the build spec has a ## Scenarios section in Given/When/Then form (see the scenario-driven shortcut in Step 3).
Prefer a self-orchestrated parallel build instead of supervised cycles?
/optimus:workflowimplements the same spec by having Claude design and run a Claude Code dynamic workflow (test-first as a quality bar, no mid-run checkpoints, more tokens). Use TDD when you want supervised, interactive test-first discipline; use/optimus:workflowfor a large or parallelizable spec where one linear pass is slow.
Examine the task description against the codebase and classify it:
Suitable for TDD — proceed silently to Step 3:
Not suitable for TDD — stop and redirect:
/optimus:refactorIf 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 aspects, or it's unclear whether behavior changes), use AskUserQuestion — header "TDD fit", question "[specific concern about the task]. Proceed with TDD or use a different approach?":
Always create a new branch from the current branch for TDD work. This keeps the user's original branch clean — all changes happen on the new branch.
git rev-parse --abbrev-ref HEAD$CLAUDE_PLUGIN_ROOT/skills/commit/references/branch-naming.md for the naming convention. The <type> is feat for new features or fix for bug fixes (from the task classification in Step 2). The <description> is the slugified task description.git checkout -b <branch-name>## Branch
Created branch `<branch-name>` from `<original-branch>`.
All TDD work will be committed to this branch.
Read $CLAUDE_PLUGIN_ROOT/skills/tdd/references/tdd-worktree-orchestration.md and follow the Setup section, using <branch-name> and <original-branch> from above.
Break the user's description into small, individually testable behaviors. Each behavior should be:
Scenario-driven shortcut: if the input build spec contains a ## Scenarios section with ### Scenario: headings in Given/When/Then form, use those scenarios directly as the behavior list in the order they appear — each scenario maps to one Red-Green-Refactor cycle. The scenarios are the stakeholder-approved acceptance criteria; do not re-derive a parallel behavior list. If a scenario implies multiple sub-behaviors (e.g., a Then with two unrelated outcomes joined by "and"), apply the decomposition strategies below to split that single scenario into the minimum number of cycles needed. For scenario-driven bug fixes, verify Scenario 1 is a reproduce-the-bug case; if it isn't, prepend one before applying the rest.
Otherwise, use these decomposition strategies by task type:
If the decomposition produces more than 10 behaviors, split into milestones. Present the first milestone (~5-8 behaviors that deliver a coherent slice of functionality) as the current scope, and list remaining behaviors as "Future milestones" with brief descriptions. After completing the last behavior of the current milestone, use AskUserQuestion — header "Milestone complete", question "Milestone [N] is done ([N] behaviors). Continue to the next milestone?":
If the user chooses to continue, present the next milestone's behaviors for approval (return to the "Behaviors" confirmation above), then resume Step 4. This prevents overwhelming behavior lists and gives natural stopping points.
Present the decomposition as a numbered list:
## Behaviors to Implement
1. [Behavior description] — [what the test will verify]
2. [Behavior description] — [what the test will verify]
3. [Behavior description] — [what the test will verify]
...
Use AskUserQuestion — header "Behaviors", question "Does this decomposition look right? Adjust, reorder, or approve to start cycling.":
For bug fixes: the first behavior is always "reproduce the bug" — a test that demonstrates the current broken behavior.
Do not write all tests first, then all implementations. That is "horizontal slicing" — treating Red as "write every test in the list" and Green as "implement everything at once." Tests written in bulk test imagined behavior, not actual behavior: they end up checking the shape of things (signatures, data structures) rather than user-facing outcomes, and they become insensitive to real changes — passing when behavior breaks, failing when behavior is fine.
The correct shape is vertical: one test → one implementation → next test. Each cycle responds to what you learned from the previous one. Because you just wrote the code, you know exactly which behavior matters next and how to verify it.
WRONG (horizontal):
RED: test1, test2, test3, test4, test5
GREEN: impl1, impl2, impl3, impl4, impl5
RIGHT (vertical):
RED→GREEN: test1→impl1
RED→GREEN: test2→impl2
RED→GREEN: test3→impl3
...
For the current behavior, write a minimal test that:
testing.md (framework, file location, naming, mocking patterns)"returns 401 when token is expired", not "test auth") — the test name is documentation of what capability exists$CLAUDE_PLUGIN_ROOT/skills/tdd/references/testing-anti-patterns.md before writing mocks; prefer real code over mocks, never assert on mock behavior, mock only external services or non-deterministic dependenciesPlace the test file according to the project's convention (from testing.md). If adding to an existing test file, append; if the convention calls for a new file, create one.
Verification protocol — every test run in this skill (Steps 4, 5, 6) must follow the gate function in $CLAUDE_PLUGIN_ROOT/skills/init/references/verification-protocol.md: identify the command, run it fresh, read complete output, verify the claim matches the evidence, only then report. Never claim "should pass" or "probably works" — state the actual result with evidence (e.g., "14 passed, 1 failed"). This protocol applies to every "Run the test suite" instruction below.
Run the project's test command. The new test must fail. Verify:
If the test passes unexpectedly, the behavior may already be implemented. Use AskUserQuestion — header "Test passed", question "The test passed without new code. The behavior may already exist. How to proceed?":
If the test fails for the wrong reason (import error, missing dependency, syntax error), fix the test — not the source code. The test itself must be valid; only the assertion should fail.
Report to the user:
## Red — [Behavior description]
Test: [test file path]:[test name]
Status: FAILS ✓ (expected)
Reason: [why it fails — e.g., "function returns undefined, expected 'authenticated'"]
Other tests: all passing ✓
Write the minimum code to make the failing test pass. Resist the urge to implement more than what the test demands:
Run the project's test command. All tests must pass — including the new one.
AskUserQuestion — header "Implementation stuck", question "The test has failed after 3 fix attempts. This usually signals a design problem, not a code problem. How to proceed?":
git checkout -- <implementation files>), mark the test as skipped per the project's convention (e.g., skip/xit/@pytest.mark.skip), move to the next behavior"When: the current behavior is a bug reproduction (the first behavior in a bug-fix decomposition). Skip for regular feature behaviors.
This gate proves two things: (1) the test genuinely catches the bug, and (2) the fix genuinely resolves it. Without this, you may have a test that passes regardless of the fix — providing false confidence.
git add <test-file> && git commit -m "test: reproduce <bug-description>"git stash push <implementation-files>git stash popReport:
## Regression Gate — [Bug description]
Test: [test file path]:[test name]
Without fix: FAILS ✓ (test catches the bug)
With fix: PASSES ✓ (fix resolves the bug)
Verdict: REGRESSION GATE PASSED
If the test passes with the fix reverted (step 3), the test is not actually catching the bug. Restore the fix (git stash pop), then rewrite the test to target the actual failure condition.
If a lint or type-check command is configured in CLAUDE.md or the project manifest (e.g., tsc --noEmit, cargo check, go vet, dotnet build), run it. Type errors in implementation code can hide behind passing tests. If it fails, fix the implementation before proceeding to Step 6.
Report to the user:
## Green — [Behavior description]
Test: [test file path]:[test name]
Status: PASSES ✓
Implementation: [file path]:[function/method]
All tests: passing ✓
Type-check: passing ✓ [or omit this line if no type-check command is available]
With all tests passing, review the code just written (both test and implementation) against coding-guidelines.md. Apply each principle as a lens — does the new code satisfy the guidelines? If not, refactor.
Refactoring scope: Review code written in this TDD session and existing code that the new implementation directly interacts with (files it imports, calls, or inherits from). Look for:
Stay bounded: only consider files the new code already references — don't search the broader codebase for extraction opportunities and don't restructure code that the current behavior doesn't interact with. Eliminate duplication created by getting the test to work, but don't refactor further than necessary for this session.
Also review the test:
testing.md conventions?Make improvements only if they genuinely simplify or clarify. Do not add features, handle untested edge cases, or "prepare for" the next behavior.
Run the project's test command after every refactoring change. All tests must remain green. If any test fails, undo the last refactoring change — the refactoring was incorrect.
If a lint or type-check command was run in Step 5, run it here too — refactoring can introduce lint or type errors that tests don't catch. If it fails, fix the issue before proceeding.
Report to the user:
## Refactor — [Behavior description]
Changes: [brief description of what was cleaned up, or "No changes needed — code is clean"]
All tests: passing ✓
After completing one Red-Green-Refactor cycle, automatically commit the work on the feature branch:
git add <specific files> for the test and implementation files touched in this cycle. Use git add -A only if many files were changed (e.g., renames, moves). Never stage files that look like secrets (.env, credentials, keys) — warn the user if any appear in git status$CLAUDE_PLUGIN_ROOT/skills/commit-message/references/conventional-commit-format.md for the format. The message should cover the behavior just completedgit commit -m "<message>"Committed: <short-hash> <commit message>
Then, if behaviors remain, use AskUserQuestion — header "Next step", question "Cycle complete for behavior #[N]. What next?":
If behaviors remain and the user chooses to continue, return to Step 4 (Red) for the next one.
If no behaviors remain, or the user chooses "Stop here", proceed to Step 8 (Quality Gate).
Read these files for the quality gate:
$CLAUDE_PLUGIN_ROOT/skills/tdd/agents/shared-constraints.md — shared constraints for both agents$CLAUDE_PLUGIN_ROOT/skills/tdd/agents/code-simplifier.md — code-simplifier prompt$CLAUDE_PLUGIN_ROOT/skills/tdd/agents/test-guardian.md — test-guardian prompt$CLAUDE_PLUGIN_ROOT/skills/tdd/references/quality-gate.md — execution procedureFollow the Execution section in quality-gate.md. Use <original-branch> from Step 3 to scope the changed files. When complete, proceed to Step 9.
After all behaviors are implemented (or the user stops early):
If there are uncommitted changes (e.g., the user stopped mid-cycle before the auto-commit):
git add <specific files>; use git add -A only if many files changed) and commit: git commit -m "<conventional message covering remaining work>"## TDD Summary
### Behaviors Implemented
| # | Behavior | Test | Status |
|---|----------|------|--------|
| 1 | [description] | [test file]:[test name] | ✓ Complete |
| 2 | [description] | [test file]:[test name] | ✓ Complete |
| 3 | [description] | — | Not started |
### Stats
- Cycles completed: [N] of [total]
- Tests written: [N]
- Tests passing: all ✓
- Files created: [list new files]
- Files modified: [list modified files]
- Quality gate: code-simplifier ([N] findings), test-guardian ([N] findings)
### Coverage
[Detect the coverage command per `$CLAUDE_PLUGIN_ROOT/skills/tdd/references/coverage-detection.md`;
run it before the first cycle and after the last cycle to measure the delta, and omit this section
per that reference's "When to omit" rule.]
- Before: [X]%
- After: [Y]%
- Delta: +[Z]%
If there are commits on the branch:
Push the feature branch: git push -u origin <branch-name>. If the push fails, report the error and stop — skip the remaining Step 9 subsections and leave any worktree in place; the user must resolve the push issue before a PR/MR can be created (re-running /optimus:tdd resumes from the existing worktree).
Report to the user:
### Git Activity
- Branch: `<branch-name>` (from `<original-branch>`)
- Commits: [N]
- Pushed: ✓
If behaviors remain unfinished, note them and suggest re-running /optimus:tdd to continue.
/optimus:prRun /optimus:pr in this same conversation to create the pull/merge request. Staying here lets /optimus:pr read the ## TDD Summary block above and populate the PR description's ## Intent (Scope from behaviors implemented, Non-goals from deferred behaviors, Key decisions from refactor-step reasoning) and ## Test plan (one verification item per behavior, plus the coverage delta); it then owns the rest of the PR/MR flow (default-branch detection, CLI install, existing-PR detection, preview-and-confirm — see $CLAUDE_PLUGIN_ROOT/references/skill-handoff.md).
If a worktree was used (Step 3), read $CLAUDE_PLUGIN_ROOT/skills/tdd/references/tdd-worktree-orchestration.md and follow the Cleanup section.
Tell the user the closing tip per $CLAUDE_PLUGIN_ROOT/references/skill-handoff.md "Closing tip wording" — use Variant A with <continuation-skill(s)> = /optimus:pr and <non-continuation-examples> = /optimus:code-review.