tdd is test-driven development: the red → green loop. Red: write one test that fails, because the behaviour doesn't exist yet. Green: write only enough code to make it pass. Then the next test.
The Skill is a reference that makes that loop produce tests worth keeping:
A good test checks behaviour through a public interface, not the code's insides. The code can change completely and the test still holds. "user can checkout with valid cart" reads like a line of a Spec.
A seam is the public boundary you test at. Tests go only at seams agreed up front: before the first test, the agent writes down the seams and confirms them with you.
Three anti-patterns (common mistakes) to avoid. Implementation-coupled tests mock the code's own parts, test private functions, or check the database instead of the interface. Tautological tests work out the expected value the same way the code does, so they can never disagree with the code. Horizontal slicing writes all the tests first, then all the code.
Vertical slices instead: one seam, one test, one small piece of code per cycle.
Mocks (fake stand-ins) go only at system boundaries, such as an outside API or the clock.
Refactoring, meaning tidying code without changing what it does, isn't part of the loop. It belongs to the review stage, code-review.
Red: write one test that fails
Green: write only enough code
Then the next test.
Refactoring
the red → green loop
When to use it
Building a feature or fixing a bug test-first, such as a new rule in a FastAPI backend.
You mention red-green-refactor, or want integration tests.
Inside other Skills: implement calls it "where possible", at pre-agreed seams, and every implementer subagent in implement-spec calls it to build its Ticket.
When not to use it
To answer a design question fast with throwaway code, use its look-alike prototype. A prototype skips tests on purpose, because it gets thrown away.
For a hard bug whose cause you don't know yet, diagnosing-bugs builds a feedback loop first. A failing test is the first kind of loop it tries.
To tidy code that already passes, wait for the review stage.
What it needs to start
A behaviour to build, from a Ticket or from you.
Seams you've agreed with the agent.
The project's words: it reads GLOSSARY.md, if there is one, so test names match them, and respects the recorded decisions about the area.
What it creates
Tests at the agreed seams, each one failing before its code was written.
Just enough code to make them pass, and no features the tests didn't ask for.
Going deeper
6 min read · Going deeper not read
Why it exists
On The Pragmatic Engineer podcast (2026-09-17), Matt said: "I have a mixed relationship with TDD." His reason is about who the loop was built for. "TDD optimizes for having a very small working memory": a failing test tells a person where they were after a coffee break. Of agents he said: "Agents don't need that."
What agents do need, he said, is feedback: "they need to see what they're doing and how it's interacting with the environment of the code." A test that fails first gives them that, and "It's also very hard for an agent to cheat that." He often asks for "TDD evidence": proof the test "would fail without this change".
The second problem is test quality. Agents "will often just write crap tests", such as one that "writes a constant and then it says expect this constant to be this value." Still, he said: "I do still recommend it just because it gives you so much more confidence in what you're building from a human perspective".
How it works underneath
TDD's loop comes from Kent Beck, who calls it his "rediscovery of TDD". In "Canon TDD" (2023-12-11) he writes the loop as five steps: write a list of test scenarios, turn exactly one into a real test, make it pass, "Optionally refactor", and repeat until the list is empty.
Canon TDD's steps as a flowchart, drawn by Vic Wu and shown in Kent Beck's post. From newsletter.kentbeck.com, 30 October 2026.
Citations (86)
From snapshot/skills/tdd/SKILL.md, line 3: “Test-driven development. Use when the user wants to build features or fix bugs test-first, mentions "red-green-refactor", or wants integration tests.”
From snapshot/skills/tdd/SKILL.md, line 8: “TDD is the red → green loop. This skill is the reference that makes that loop produce tests worth keeping: what a good test is, where tests go, the anti-patterns, and the rules of the loop.”
From snapshot/skills/tdd/SKILL.md, line 10: “When exploring the codebase, read GLOSSARY.md (if it exists) so test names and interface vocabulary match the project's domain language, and respect ADRs in the area you're touching.”
From snapshot/skills/tdd/SKILL.md, line 14: “Tests verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't. A good test reads like a specification: "user can checkout with valid cart" tells you exactly what capability exists”
Two of Beck's named mistakes are close to Matt's anti-patterns:
Turning the whole list into tests first, then making them pass one at a time. When the first test changes your mind, Beck says you get "Rework". Matt calls this horizontal slicing.
"copying actual, computed values & pasting them into the expected values of the test". Beck: it "defeats double checking, which creates much of the validation value of TDD". Matt calls this a tautological test.
Beck also names "delete assertions so the test pretends to pass". With agents this is a real worry. In "Augmented Coding: Beyond the Vibes" (2025-06-25), one of his warning signs was "the genie was cheating, for example by disabling or deleting tests".
Canon TDD and Matt's tdd share one test at a time. But Canon TDD starts from a test list, while Matt's tdd starts from agreed seams. And only Canon TDD keeps a refactor step.
Canon TDD
Matt's tdd
one test at a time
yes
yes
starts from
a test list
agreed seams
a refactor step
yes
no
Canon TDD and Matt's tdd
Matt removed that step in pull request #393 (opened 2026-06-30, merged 2026-07-01): "Refactoring belongs to the review stage, not the implementation loop." His Skill page gives the reason: the step was dropped "because agents almost never performed it".
The same pull request explains why the Skill is so short. It cut SKILL.md from "111 → ~30 lines". One reason it gives: the loop is "anchored by leading words the model already holds (TDD, red/green, tracer bullet)". So the PR dropped the spelled-out Workflow and kept a reference: seams, anti-patterns and the rules of the loop.
A real example
Until October 2026, the seam question named seams by label only. Matt's Skill page, updated 2026-08-24, called this "the most-reported friction with the skill" and said "There is no fix shipped yet."
Matt's pull request #1192 (opened 2026-10-06, merged 2026-10-07) fixed it with one line. Its evidence shows the difference:
Before: "Which seam: A (component boundary) or B (integration boundary)?" There is no basis for choosing.
After: "A: component boundary: catches rendering bugs, misses network failures. B: integration boundary: catches the full round-trip, slower to isolate."
Today's SKILL.md carries that rule: each proposed seam gets a note on what it catches and what it misses. The Skill page is older, so on this point the SKILL.md wins.
Where it goes wrong
The code comes first anyway. The Skill page quotes one model's answer: "I read it. I just defaulted to my normal habit." Matt doesn't add stricter wording. His advice: "watch the run rather than trusting the skill to enforce it."
A red that proves nothing. In issue #1210 (2026-10-07), a model asked to reproduce a bug wrote tests against a method that didn't exist yet. It reported "confirmed red (no method named drain_settled, 4 compile errors)". The reporter: "This pass did not replicate the target issue." The issue is still open, with a fix waiting: "tdd: a bug fix's red reproduces the bug".
Browser tests first. One agent wrote a Playwright test first, then decided the test was broken, for a feature that didn't exist yet. The page's verdict: "Browser tests are slow enough that the red-green feedback loop stops paying for itself."
A change with nothing to assert. For config, wiring or glue, the loop gives "a test that restates the implementation". The Skill page (2026-08-24) calls issue #746 open. GitHub now shows it "Closed as not planned" on 2026-10-06. Today's SKILL.md still has no rule for it, so that call stays yours.
implement not calling it. Issue #479 says implement skips tdd. On 2026-09-13 one user counted 17 implement runs in their transcripts, with 0 tdd calls. That count is older than Matt's commit of 2026-10-06, which replaced "Use /tdd where possible, at pre-agreed seams." with a Skill tool call. Today's implement still says "where possible", and the issue is still open.
Try it
In your practice project (set it up first with keeping-track's Try it step if you haven't), use tdd to fix one bug in the booking endpoint in api/: a booking still goes through for a class that has already started (or a full class still takes one more booking, if you didn't add that rule in test-first's Try it).
When the agent proposes seams, check that each one has a note on what it catches and what it misses. If one doesn't, ask for it before you confirm.
When it reports the first red, read the failure. If pytest fails with an ImportError or AttributeError, only a name is missing, and the bug was never reproduced, as in issue #1210. Ask for a test that calls the existing booking endpoint and fails because the booking goes through.
Read the expected values. The class's start time (or its size) should be a literal in the test, not a value worked out the way the code works it out.
Going deeper's Check questions are asked in Next up.
“A seam is the public boundary you test at: the interface where you observe behavior without reaching inside.”
From snapshot/skills/tdd/SKILL.md, line 22: “Test only at pre-agreed seams. Before writing any test, write down the seams under test and confirm them with the user.”
From snapshot/skills/tdd/SKILL.md, lines 30–32: “Implementation-coupled: mocks internal collaborators, tests private methods, or verifies through a side channel (querying the database instead of using the interface).”
From snapshot/skills/tdd/SKILL.md, lines 36–38: “Red before green. Write the failing test first, then only enough code to pass it. Don't anticipate future tests or add speculative features. - One slice at a time. One seam, one test, one minimal implementation per cycle. - Refactoring is not part of the loop. It belongs to the review stage (see the code-review skill), not the red → green implementation cycle.”
From snapshot/skills/tdd/mocking.md, lines 3–7: “Mock at system boundaries only: - External APIs (payment, email, etc.) - Databases (sometimes - prefer test DB) - Time/randomness”
From snapshot/web/youtube.com/watch-v-4dhcspkebwi.md, line 844: “even if you get distracted, you go for a coffee or something, you go for a long walk, when you come back, the test is still failing, reminding you of where you are in the implementation”
From snapshot/web/newsletter.kentbeck.com/p-canon-tdd.md, lines 47–55: “1. Write a list of the test scenarios you want to cover 2. Turn exactly one item on the list into an actual, concrete, runnable test 3. Change the code to make the test (& all previous tests) pass (adding items to the list as you discover them) 4. Optionally refactor to improve the implementation design 5. Until the list is empty, go back to #2”
From snapshot/web/newsletter.kentbeck.com/p-canon-tdd.md, line 116: “Mistake: convert all the items on the Test List into concrete tests, then make them pass one at a time. What happens when making the first test pass causes you to reconsider a decision that affects all those speculative tests? Rework.”
From snapshot/web/newsletter.kentbeck.com/p-canon-tdd.md, line 126: “Mistake: copying actual, computed values & pasting them into the expected values of the test. That defeats double checking, which creates much of the validation value of TDD.”
From snapshot/skills/tdd/SKILL.md, line 22: “Test only at pre-agreed seams. Before writing any test, write down the seams under test and confirm them with the user.”
From snapshot/web/aihero.dev/skills-tdd.md, line 144: “The prompt lists candidate seams by name only, with nothing about what each one catches or misses, so you are choosing between labels. There is no fix shipped yet.”
From snapshot/web/aihero.dev/skills-tdd.md, line 152: “A user reported the agent writing a Playwright test first, then spending a long loop re-running it and concluding the test was broken for a feature that did not exist yet. Browser tests are slow enough that the red-green feedback loop stops paying for itself.”
From snapshot/skills/tdd/SKILL.md, line 31: “Expected values must come from an independent source of truth: a known-good literal, a worked example, the spec.”