tdd
Skill75 starsChanged 2 months agoMITView on GitHub
Guides test-driven development — decomposes a feature or bug fix into testable behaviors, then runs Red-Green-Refactor cycles with a failing test before every implementation. Auto-detects specs from docs/specs/ or docs/jira/, creates a feature branch (optional worktree), commits per cycle, and pushes. Recommends /optimus:init (falls back to general best practices on your choice); requires a passing test suite.
- Reads credentials
- Commits and pushes
194 other projects use a version of this.
Adopted by
Most recently taken up by
- ishandutta2007/Awesome-Claude-Skillstheir own version, first seen Nov 8, 2026
- trpc/trpctheir own version, first seen Nov 8, 2026
- wowyuarm/dsh-agent-teamtheir own version, first seen Nov 8, 2026
- Contexera/dsh-agent-teamtheir own version, first seen Nov 8, 2026
- Dimon94/dveritytheir own version, first seen Nov 8, 2026
- Dimon94/skillstheir own version, first seen Nov 8, 2026
Used with
Projects with it also use capture-learning-tools, design-frontend-dev and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
The-Vibe-CompanySkillcapture-learning-tools
Turn technical conversations, bugs, CI failures, review comments,
Also in 5 projects that use this
The-Vibe-CompanySkilldesign-frontend-dev
Clean Impeccable frontend design skill. Use when the user wants to
Also in 5 projects that use this
tristanphvnSkillketchup-video
Catch the user up like /keel:ketchup, with a short silent video of slides for what happened and the waiting calls as text under it. Use for /keel:ketchup-video.
Also in 14 projects that use this
jaydubya818Skillfigure-it-out
Use when novel or multi-phase work needs an auditable workflow and no narrower playbook fits.
Also in 54 projects that use this
jaydubya818Skillprinciple-laziness-protocol
Apply when a refactor is adding wrappers or abstractions instead of simplifying.
Also in 45 projects that use this
- +2 more from The-Vibe-Company
- +5 more from jaydubya818
Other versions194 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 194
- mattpocock/skills★ 309ksame name
- trpc/trpc★ 41ksame name
- Yeachan-Heo/oh-my-claude-sisyphus★ 41ksame name
- Yeachan-Heo/oh-my-claudecode★ 41ksame name
- QuivrHQ/quivr★ 40ksame name
- The-Vibe-Company/quivr★ 40ksame name
- ccusage/ccusage★ 19ksame name
- ryoppippi/ccusage★ 19ksame name
- MODSetter/SurfSense★ 17ksame name
- GreyDGL/PentestGPT★ 16ksame name
184 more not listed
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository20 other files it gives its agents.
- AGENTS.mdAGENTS.md
- .claude/CLAUDE.mdCLAUDE.md
- brainstormSkill
- code-reviewSkill
- commitSkill
- deepSkill
- dreamSkill
- gauntletSkill
- handoffSkill
- how-to-runSkill
- initSkill
- jiraSkill
- paper-initSkill
- permissionsSkill
- promptSkill
- prSkill
- refactorSkill
- resetSkill
- unit-testSkill
- worktreeSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
17 rules. 0 are common, 12 are distinctive, and 5 are very specific to this project.
0
Common
Most of the 186 edited versions we read keep these.
12
Distinctive
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 13
If this conversation is in plan mode, stop: TDD needs normal mode.
- Very specific: line 29
If .claude/CLAUDE.md or .claude/docs/coding-guidelines.md is missing, recommend /optimus:init first.
- Very specific: line 69
All work happens on a new branch.
- Distinctive: line 83
If more than 10 behaviors result, split into milestones of ~5-8 that each deliver a coherent slice.
- Distinctive: line 87
Anti-pattern — horizontal slicing: Never write all tests first, then all implementations: bulk-written tests check imagined shape, not …
- Very specific: line 96
Write one minimal test for the current behavior: follow testing.md conventions, test exactly one behavior, and name it as a behavior …
- Distinctive: line 98
Test-result honesty (every test run in Steps 4-8): run the command fresh, read the complete output, and state the actual result (e.g., "14 …
- Distinctive: line 100
Run the test suite. The new test must fail on its assertion for the right reason, and all other tests must still pass.
- Distinctive: line 110
Write the minimum code to make the failing test pass: no untested edge cases, no premature abstraction, no "while I'm here" improvements.
- Distinctive: line 112
Run the test suite — all tests must pass.
- Distinctive: line 122
Only when the current behavior is a bug reproduction (skip for feature behaviors).
- Distinctive: line 126
Run the test — it must fail.
- Distinctive: line 128
Run the test — it must pass.
- Distinctive: line 130
If the test passes at step 3 with the fix reverted, it isn't catching the bug: restore the saved green implementation, then rewrite the …
- Very specific: line 143
Commit only those paths with git commit --only -m "<message>" -- <owned-files>, using the conventional format in …
- Distinctive: line 187
If a mixed-file commit is still deferred, leave the branch local and report what decision is needed before delivery.
- Very specific: line 191
If behaviors remain unfinished, note them and suggest a follow-up /optimus:tdd run with them as the task, started from this feature branch …
“Common” is measured: kept by at least 6 in 10 of the 186 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Test-Driven Development
Implement a feature or bug fix test-first: for each behavior, write a failing test (Red), write the minimum code to pass it (Green), then clean up while tests stay green (Refactor). This skill builds new behavior — for restructuring without behavior change, use /optimus:refactor.
The Iron Law: no production code without a failing test first. If this cycle's implementation is written before its test, undo only that implementation using the ownership record below and begin the cycle fresh. Preserve pre-existing code and user edits; write the cycle's implementation once the failing test exists.
If this conversation is in plan mode, stop: TDD needs normal mode. Tell the user to toggle plan mode off without approving, save any refined plan to its spec, and invoke TDD in a fresh conversation.
Step 1: Pre-flight
If git rev-parse --is-inside-work-tree does not return true, read $CLAUDE_PLUGIN_ROOT/skills/init/references/multi-repo-detection.md and apply it; if a multi-repo workspace is detected, work inside the repo the user is targeting — ask which one if ambiguous. When it returns true, resolve the repository root with git rev-parse --show-toplevel, including in a linked worktree or subdirectory.
Preserve starting work
Record the current branch/HEAD and staged, unstaged, and untracked paths before setup or edits. These changes belong to the user unless the conversation explicitly includes them in this task. Existing authorization persists; ask only when ownership or scope is genuinely ambiguous. A new branch does not isolate dirty work, and a new worktree starts from committed state rather than carrying the user's dirty changes.
Before the first edit to each file in a cycle, record its existence and SHA-256 over its raw bytes. An empty Git status/diff does not prove those bytes are recoverable: index flags and filters can hide differences. Read a candidate HEAD/index blob with git cat-file blob <blob-oid>, capturing binary stdout; use Git as the rollback source only when its bytes exactly match the current file. Save that immutable blob ID and the verified hash. Otherwise copy the exact bytes to the private session scratchpad — or a temporary directory outside the repository when the host offers none — and verify the copy before editing. Keep the recovery source until the cycle is committed or safely rolled back.
For every edited path, record the last bytes/hash and existence written by the cycle, regardless of recovery source. Before any rollback, compare the current state with that last-written state. Restore or delete a whole file only on a match; if it changed independently, remove only identifiable cycle changes, preserving other work. If separation is uncertain, preserve it and show the ambiguity. Delete a newly created file only when it was absent at the cycle boundary and still matches the cycle's last version.
For restoration, load the saved blob or copy and verify its raw-byte hash before overwriting the original; preserve it on any read or verification failure. Restore those verified bytes directly, without checkout filters or reliance on the current HEAD/index. Never use hard reset, broad stash/pop, or cleanup as a substitute for this boundary; never replace the user's starting index or stage unrelated work.
If .claude/CLAUDE.md or .claude/docs/coding-guidelines.md is missing, recommend /optimus:init first; on the user's choice, continue with general best practices. Load:
.claude/CLAUDE.md— project overview, tech stack, test runner command.claude/docs/coding-guidelines.md— applied during Refactortesting.md— test conventions: framework, file location, naming, mocking patterns. In a monorepo, load the target subproject's owndocs/testing.md/docs/files; shared guidelines come from root.claude/docs/docs/product/tech-stack.mdanddocs/product/mvp-prd.md, only if present — low-priority steering that informs decomposition and Refactor but never overrides the task source (precedence:$CLAUDE_PLUGIN_ROOT/references/sdd-mapping.md)
Verify test infrastructure
Locate the test runner command (from testing.md, CLAUDE.md, or project manifests) and run it once:
- Tests pass — proceed
- Tests fail — stop and report; a failing baseline makes Red/Green indistinguishable
- No runner found — stop and recommend
/optimus:initto set up test infrastructure (its Scaffold option covers projects with no code yet)
Then find a coverage command — first match wins: the coverage section of testing.md, a runner flag (vitest --coverage, pytest --cov=., go test -cover, dotnet test --collect:"XPlat Code Coverage"), or a package.json coverage script. If found, run it once and record the Before percentage; Step 8 runs only the After measurement.
Step 2: Task and Suitability
Resolve the task — first match wins; run this even when the user also gave an inline description:
- Explicit reference — the input names a
.mdfile insidedocs/specs/ordocs/jira/: read it and use the sections item 2 (spec) or item 3 (JIRA) names as the task. - Build spec (wins over JIRA context: a brainstorm-authored spec already incorporates it) —
docs/specs/holds.mdfiles: take the most recent (filename date prefix, else modification time) and useAskUserQuestion— header "Build spec", question "Found build spec<path>— use it as the basis?", options "Use it" / "Ignore — describe a different task". When that date is older than 7 days, add to the question: "(This spec is [N] days old — if it is a/optimus:brainstorm-authored spec, you may want to re-run brainstorm for a fresh design.)" From a brainstorm-authored spec use Goal, Components, and Interfaces; from a human-authored one, Goal and Acceptance Criteria. Its## Scenariossection feeds Step 3's scenario-driven shortcut. - JIRA context — no build spec resolved (none found, or ignored) and
docs/jira/holds.mdfiles: take the one with the newest frontmatterdescription-refresh-dateand useAskUserQuestion— header "JIRA context", question "Found JIRA context<path>— use it as the basis?", options "Use it" / "Ignore — describe a different task". When that date is older than 7 days, add to the question: "(This context is [N] days old — you may want to re-run/optimus:jirafor fresh data.)" Use its Goal and Acceptance Criteria. - Nothing resolved — use the inline argument; with none, ask in plain text what feature or bug fix to implement.
Whichever item resolves a file, a ### Refined plan section in it (appended by the plan-mode handoff) takes precedence over the original approach — build from it.
Whatever the source, if the final description is longer than ~2-3 sentences (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?", options Looks good — "Proceed with this goal" / Adjust — "Let me refine the focus". Resolved context feeds this step — it does not bypass Step 3 decomposition (except the scenario-driven shortcut).
Classify the task:
- Suitable — new features with testable behavior, bug fixes reproducible with a test, capabilities added to existing modules, large multi-component features (they just need careful decomposition). Proceed silently.
- Not suitable — stop and report the task, the reason, and the recommended alternative: refactoring →
/optimus:refactor; documentation-only, pure styling, configuration changes, code deletion, or generated code → no testable behavior to build. - Ambiguous — use
AskUserQuestion— header "TDD fit", stating the specific concern, options Proceed with TDD / Use [alternative].
Step 3: Branch, Worktree, Decompose
Feature branch
All work happens on a new branch; the original branch recorded in Step 1 (<original-branch>) is never modified. Name the new branch per $CLAUDE_PLUGIN_ROOT/skills/commit/references/branch-naming.md (feat for a feature, fix for a bug fix), create it with git checkout -b <branch-name>, and report both branch names.
Worktree isolation (optional)
Run git worktree list; if the current directory is inside a linked worktree, skip this offer — the environment is already isolated. Otherwise use AskUserQuestion — header "Workspace", question "Use a git worktree for isolated development? Your main workspace stays on the original branch.", options Use worktree (Recommended) / Stay on branch. On yes, follow the Setup section of $CLAUDE_PLUGIN_ROOT/skills/worktree/references/worktree-setup.md with <branch-name> and <original-branch>; if creation fails, follow its Failure handling, then run git checkout <branch-name> and continue on the branch without a worktree; say so. Otherwise all subsequent commands run inside the worktree.
Decompose into behaviors
Each behavior must be observable (phrase as "When [input/action], then [outcome]"), independent (testable without the others being done), and small (one test, one assertion focus).
Scenario-driven shortcut: if the build spec contains a ## Scenarios section with ### Scenario: headings in Given/When/Then form, use those scenarios directly as the behavior list, in order — one cycle per scenario. They are stakeholder-approved acceptance criteria; do not re-derive a parallel list. Split a scenario only when a compound Then implies multiple sub-behaviors. For scenario-driven bug fixes, verify Scenario 1 reproduces the bug; prepend one if missing.
Otherwise decompose by task type: API endpoints — one behavior per response scenario; business logic — one per rule or edge case; bug fixes — the first behavior is always "reproduce the bug"; data transformations — one per step or boundary.
If more than 10 behaviors result, split into milestones of ~5-8 that each deliver a coherent slice; present the first as the current scope and list the rest as future milestones (the boundary prompt is in Step 7).
Present the numbered behavior list, then use AskUserQuestion — header "Behaviors", question "Does this decomposition look right?", options Start cycling / Adjust.
Anti-pattern — horizontal slicing. Never write all tests first, then all implementations: bulk-written tests check imagined shape, not behavior, and go insensitive to real changes. Work vertically — each cycle responds to what the previous one taught.
WRONG (horizontal): RED: test1..test5 then GREEN: impl1..impl5
RIGHT (vertical): test1→impl1, test2→impl2, test3→impl3, ...Step 4: Red — Write a Failing Test
Write one minimal test for the current behavior: follow testing.md conventions, test exactly one behavior, and name it as a behavior specification (e.g., "returns 401 when token is expired"). Before writing mocks, read $CLAUDE_PLUGIN_ROOT/skills/tdd/references/testing-anti-patterns.md — prefer real code over mocks, never assert on mock behavior.
Test-result honesty (every test run in Steps 4-8): run the command fresh, read the complete output, and state the actual result (e.g., "14 passed, 1 failed") — never "should pass". Red and Green both turn on a real observed result, so a guessed one silently breaks the discipline.
Run the test suite. The new test must fail on its assertion for the right reason, and all other tests must still pass.
- Fails for the wrong reason (import error, syntax error, infrastructure) — fix the test, not the source.
- Exception — the symbol under test doesn't exist yet: for the first behavior of a new module, class, or function, create a minimal stub (empty function, class, or module) so the run fails on the assertion instead. The stub is scaffolding, not an Iron Law violation — the failing test already exists.
- Passes unexpectedly — the behavior may already exist. Use
AskUserQuestion— header "Test passed", options Skip this behavior / Strengthen the test / Investigate.
Step 5: Green — Minimal Implementation
For a bug reproduction, preserve the implementation state at the observed Red assertion failure, including any required stub, before making the fix. Step 5's regression gate restores this state temporarily using Step 1's ownership checks.
Write the minimum code to make the failing test pass: no untested edge cases, no premature abstraction, no "while I'm here" improvements. A hardcoded return that passes is valid — later tests force generalization.
Run the test suite — all tests must pass.
- New test still fails — fix the implementation, not the test. Circuit breaker: after 3 failed attempts, stop and use
AskUserQuestion— header "Implementation stuck", question "The test has failed after 3 fix attempts — this usually signals a design problem, not a code problem.":- Rethink the approach — reconsider the behavior's design or decomposition
- Simplify the behavior — break it into smaller sub-behaviors
- Skip for now — restore only this cycle's implementation using the recovery source and ownership checks from Step 1, mark the test skipped per the project's convention, and move to the next behavior. Preserve the test and all earlier user/cycle work.
- Other tests broke — fix the regression before proceeding.
Bug-fix regression gate
Only when the current behavior is a bug reproduction (skip for feature behaviors). This proves the test catches the bug and the fix resolves it:
- Preserve the green implementation bytes in the scratchpad (or the temporary directory chosen in Step 1). Commit the test separately only when it can follow Step 7's ownership rules; the regression proof does not require a commit.
- Restore the saved Red implementation state using Step 1's ownership checks, leaving the regression test in place. Confirm that only this cycle's fix was removed, not earlier user work.
- Run the test — it must fail.
- Restore the saved green implementation, applying the same independent-change check.
- Run the test — it must pass.
If the test passes at step 3 with the fix reverted, it isn't catching the bug: restore the saved green implementation, then rewrite the test to target the actual failure condition.
Step 6: Refactor — Clean Up While Green
Review this cycle's test and implementation against coding-guidelines.md. Scope: code written in this session plus the files it directly imports, calls, or inherits from — extract duplication with those files, align naming, adjust an existing method to cleanly serve old and new usage. Do not restructure beyond that scope, add features, or handle untested edge cases. Also check the test: behavior-spec name, focused assertions, testing.md conventions.
When the cycle's cleanup is done, run the lint / type-check command if one is configured (CLAUDE.md or project manifest) and fix failures — type errors can hide behind passing tests. Then run the test suite; if it goes red, undo the change that broke it. Step 7 commits without checking again.
Step 7: Commit and Loop
Auto-commit each completed cycle:
- Identify files whose entire change is owned by this task; compare against the starting-work record and inspect the actual diff. Stage only these exact paths (
git add -- <owned-files>), nevergit add -A. Never stage files that look like secrets (.env, credentials, keys) — warn the user if any appear ingit status. - Commit only those paths with
git commit --only -m "<message>" -- <owned-files>, using the conventional format in$CLAUDE_PLUGIN_ROOT/skills/commit/references/conventional-commit-format.md. This excludes unrelated entries already staged by the user. Check the resulting commit and that unrelated staged/unstaged work is preserved. - If a file mixes task changes with pre-existing user changes not already included in the task's authorization, do not stage or commit the whole file. Preserve both, show the concrete mixed diff, and resolve ownership with the user before including it. Keep the cycle's snapshots while its commit is deferred; continue independent work when possible. Do not claim an uncommitted cycle was delivered on the branch.
Then keep cycling — return to Step 4 for the next behavior without asking. Two things interrupt the loop:
- Milestone boundary — the completed behavior ends the current milestone and more remain:
AskUserQuestion— header "Milestone complete", options Next milestone (present its behaviors for approval as in Step 3, then return to Step 4) / Stop here. - The decomposition turns out to be wrong — a behavior that was really several, or one the implementation showed was misframed. Say what changed and confirm the revised list before continuing. (Step 5's circuit breaker covers the narrower case of a test that will not pass.)
Report at those boundaries rather than per cycle: which behaviors landed, their test names, and the commit hashes. If no behaviors remain, or the user stops, proceed to Step 8.
Step 8: Summary, Push, and PR/MR
Commit remaining work
If uncommitted task-owned changes remain (e.g., stopped mid-cycle), run the test suite first: mark a failing mid-cycle test skipped and note it in the summary — or surface the failure to the user before committing if skipping isn't appropriate. Apply Step 7's exact-path ownership rules. Leave unrelated starting work untouched and report any deferred mixed-file commit; do not push or describe that unfinished work as committed.
Present summary
## TDD Summary
### Behaviors Implemented
| # | Behavior | Test | Status |
|---|----------|------|--------|
| 1 | [description] | [test file]:[test name] | ✓ Complete |
| 2 | [description] | — | Not started |
| 3 | [description] | [test file]:[test name] | Skipped — [reason] |
### Stats
- Cycles completed: [N] of [total]
- Tests passing: [actual last-run result — e.g., "14 passed, 1 skipped"]
- Files created / modified: [lists]
### Coverage
[Run the After measurement with the Step 1 coverage command. Include this section only when both
Before and After produced a real percentage — never a half-filled block. Omit it entirely when no
coverage command was found or either run produced no parseable number.]
- Before: [X]%
- After: [Y]%
- Delta: [±Z]%Push
If a mixed-file commit is still deferred, leave the branch local and report what decision is needed before delivery. Continue with a partial push only if the user explicitly chose that scope.
Push the branch: git push -u origin <branch-name>. If the push fails, report the error and stop — skip the rest of Step 8 and leave any worktree in place; once the push problem is fixed, /optimus:pr pushes the branch and opens the PR/MR (a new /optimus:tdd invocation starts fresh — it does not resume this one). On success, report the branch, its origin branch, and the commit count.
If behaviors remain unfinished, note them and suggest a follow-up /optimus:tdd run with them as the task, started from this feature branch — each run is a fresh decomposition; there is no resume.
Next step
Recommend /optimus:code-review first: cross-cycle issues — duplication between behaviors, naming drift, coverage gaps that only surface once the whole feature shape exists — are invisible from inside a single cycle, and it reviews the branch diff with the full agent fan-out. Then /optimus:pr to create the PR/MR, which reads the ## TDD Summary block above for implementation context. Run both in this same conversation; TDD never runs gh/glab itself.
Worktree cleanup
If a worktree was used, ask last, after the recommendations above: AskUserQuestion, header "Worktree", question "Remove the worktree now? /optimus:code-review and /optimus:pr must run from it, so remove it only if you won't run them in this conversation.", options Keep (Recommended) / Remove now. Remove now → follow the Cleanup section of $CLAUDE_PLUGIN_ROOT/skills/worktree/references/worktree-setup.md; Keep → follow that section's keep-the-worktree note.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

