Skip to content
Development
Skill

/tdd

Drives feature work and bug fixes through a tight failing-test-first loop. Trigger when implementing, fixing, or refactoring behavior in a codebase that already has tests. Skip for spikes, visual-only edits, throwaway scripts, and generated files.

From plugin
sdd-pipeline
166 skills1 hook

Claude Code

$ npx -y skills add eduwxyz/my-awesome-skills --skill tdd --agent claude-code

SKILL.md

tdd.SKILL.md
name: tdd
version: 2.0.0
description: Drives feature work and bug fixes through a tight failing-test-first loop. Trigger when implementing, fixing, or refactoring behavior in a codebase that already has tests. Skip for spikes, visual-only edits, throwaway scripts, and generated files.
hooks:
  Stop:
    - hooks:
        - type: command
          command: "bash ${CLAUDE_PLUGIN_ROOT}/skills/tdd/hooks/end-green.sh"

TDD

One small failing test, just enough code to pass, then a look. Repeat.

Install

Drop in `~/.claude/skills/tdd/` (per-user) or `<repo>/.claude/skills/tdd/` (per-project).

Skip TDD for

Spikes, copy/style/visual edits, one-off scripts, generated files. If the codebase has no tests at all, see [untested-code.md](untested-code.md) first.

Two rules that keep TDD honest

1. **Never start a second test before the first one passes.** 2. **Never edit production code while red, except to make red green.**

If either slips, back up.

What a good test looks like

The name describes a capability, not a method. Read it out loud — it should sound like something a user or caller would care about.

✅ logged_out_user_cannot_publish_a_post
✅ schedule_overlap_returns_409

❌ post_service_calls_repo_save
❌ schedule_returns_object_with_status

The body has three sections in order — set up, do the thing, check what's observed:

test "expired tokens are rejected":
  token = issue_token(ttl_seconds: 60)
  advance_clock(seconds: 120)

  result = verify(token)

  assert result.ok == false
  assert result.reason == "expired"

If renaming a private function tomorrow would break the test even though no behavior changed, the test was tied to internals. Rewrite or delete it. See [test-anatomy.md](test-anatomy.md).

The cardinal mistake: tests in bulk

Writing five tests up front and then five implementations produces tests that describe an *imagined* system. They lock you into the wrong shape and stop pulling their weight once any pair shares a code path.

Each test must exist because of something you learned writing the previous one.

Wrong:  RED  t1 t2 t3 t4 t5    →   GREEN  c1 c2 c3 c4 c5
Right:  t1→c1, t2→c2, t3→c3, ...

Same mistake in miniature: writing one test and reaching inside to "also handle" something it doesn't cover. Don't.

Before the cycle — wire up the test command

The Stop hook runs your tests at the end of every turn (green allows the turn to end, red blocks it). It reads the command from `.agents/tdd/test-command.txt` at the project root.

If that file is missing, set it up before starting the cycle:

1. Read `CLAUDE.md` first — projects often document the canonical test command there. 2. Otherwise check `package.json` (`scripts.test`), `pyproject.toml` / `pytest.ini`, `Makefile` (`test:` target), `Cargo.toml`, or analogous config files for the project's stack. 3. If multiple plausible commands exist (e.g. `test:unit` vs `test:e2e`), ask the user which one to use for TDD.

Once decided, create `.agents/tdd/` if missing and write the command on a single line to `.agents/tdd/test-command.txt`. Confirm with the user the first time.

The user can edit the file at any time to change the command (e.g. switching from `npm test` to `npm run test:unit`).

The cycle

**1. Decide.** If a `spec/<slug>.md` exists for this task, read it — Behaviors + Acceptance criteria are your queue. Otherwise list the behaviors to verify in rough order with whoever cares.

**2. Smoke run.** Pick the first behavior. Test → fails → minimum code → passes. If this first cycle takes more than 15 minutes, the slice is too big.

**3. Each next behavior.** Same shape. One test at a time. No speculation. No "while I'm here." If a rule slips, see [smells.md](smells.md#warning-signs-while-you-work).

**4. Cleanup.** Tests green? Invoke the `simplify` skill on the recent changes — it reviews code for reuse, quality, and efficiency and applies any improvements found. After simplify, see [cleanup.md](cleanup.md) for additional cleanup. Cleanup only on green; never add behavior during cleanup. (The Stop hook will also remind you to invoke `simplify` once per session if you forget.)

When you're done

Stop adding tests when all are true:

  • Every acceptance criterion has a test.
  • Every interesting branch has a test (skip getters, plumbing).
  • The domain edge cases (empty input, expired things, races, boundaries) are covered.
  • Reading just the test file would teach the feature.

100% coverage with bad tests is worse than 70% with good ones.

Per-cycle checklist

  • [ ] Test names a capability, not a method.
  • [ ] Test only touches the public API.
  • [ ] Test would survive a rename of internals.
  • [ ] Code written is the minimum for this test.
  • [ ] No second test queued before this one is green.

Map

  • [test-anatomy.md](test-anatomy.md) — body shape, assertions per test, naming.
  • [smells.md](smells.md) — bad-test patterns + warning signs while you work or review.
  • [boundaries.md](boundaries.md) — mocks, fakes, stubs; what counts as an edge.
  • [untested-code.md](untested-code.md) — TDD on legacy.
  • [shape.md](shape.md) — deep modules + designing for tests.
  • [cleanup.md](cleanup.md) — what to do after green.
Read more
@eduwxyz
Ships withsdd-pipeline

A spec-driven development pipeline for Claude Code and Codex CLI. Refine the spec before you code, let TDD enforce it, verify nothing slipped, then review.

Stars on GitHub

Momentum

stars in total
16
Star history of eduwxyz/my-awesome-skills on GitHub, a chart by star-history.com

Other skills on sdd-pipeline.

diagnose

diagnose

Turn a bug symptom into a fix with a regression test that locks it down. If the user opens vague ("there's a bug", "/diagnose"),…

feature

feature

Kick off the full feature workflow — interview-to-spec, optional spec-approach, tdd, verify, then review — when starting a new…

interview-to-spec

interview-to-spec

Conduct a focused interview to draft a spec.md for an upcoming task (the input step of SDD — spec-driven development). Walks…

spec-approach

spec-approach

Add a refined `## Approach` section to an existing feature spec.md before TDD executes it. Reads the spec, explores the codebase…

verify

verify

Verify that a spec.md's Acceptance criteria are observably covered by green tests before opening a PR. Reads the spec, finds the…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills11d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc13d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react2d252k
@facebook@facebookInstall Skill

Questions about tdd.

Which coding agents can use tdd?
tdd installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.