Write a failing test first. Then write only enough code to make it pass. The test is red while it fails and green once it passes. Then do the next small piece the same way. In the main Flow, code gets built one red-green slice at a time.
One slice at a time
Each cycle is one seam, one test and the smallest code that passes it. Don't add features no test asks for yet.
The trap is horizontal slicing: writing all the tests first, then all the code. Those bulk tests check behaviour you imagined, not behaviour you've seen. They test the shape of things, they stop noticing real changes, and they lock in a test structure before you understand the code.
Work in vertical slices instead: one test, its code, then the next test. Each test responds to what the last cycle taught you.
horizontal slicing
vertical slices
writing all the tests first, then all the code
one test, its code, then the next test
Those bulk tests check behaviour you imagined, not behaviour you've seen.
Each test responds to what the last cycle taught you.
The trap is horizontal slicing
Tests live at seams
A seam is the public boundary you test at, where you can see what the code does without reaching inside. For a FastAPI backend, that might be the HTTP API rather than each private helper function.
Agree the seams before writing any test, and confirm them with the person you're building for. You can't test everything, so agreeing the seams puts the testing effort where it matters most.
What a good test checks
A good test checks behaviour through a public interface, not how the code works inside. The code can change completely and the test shouldn't need to. It reads like a description of what the system can do: "user can checkout with valid cart".
Where refactoring goes
Tidying the code without changing what it does is not part of the loop. It belongs to the review stage.
Where it shows up
to-spec plans for it before any code exists. It sketches the seams the feature will be tested at, as few and as high as it can (ideally one), and checks with you that they match what you expect.
implement calls tdd wherever it can, at seams agreed beforehand. In implement-spec, each implementer subagent calls it to build its own Ticket.
Going deeper
5 min read · Going deeper not read
Why it exists
Matt's README names the problem. You and the agent agree on what to build, and the agent still produces crap. His answer: "Without feedback on how the code it produces actually runs, the agent will be flying blind." For tests, he calls a red-green-refactor loop "critical" (README, written 28 April 2026 and unchanged at the pin commit).
In September 2026 he put it more sharply on The Pragmatic Engineer podcast. "TDD optimizes for having a very small working memory." Agents hold much more, so he thinks TDD is "sort of aiming at the wrong problem". What agents really need is feedback loops. Even when he doesn't use TDD directly, he will often say: "Give me TDD evidence, right? That it's it would fail without this change." He calls it "a mixed relationship with TDD", and still recommends his tdd Skill.
So the idea under test first is not only the order you write things in. It's also proof that a test can fail, and that your change is what turns it green.
How it works underneath
Red-green comes from test-driven development (TDD). Kent Beck wrote its plainest form down in "Canon TDD" (11 December 2023). It has five steps. It starts with "a list of the test scenarios you want to cover". Then one item becomes a runnable test, the code changes until it passes, and the loop repeats until the list is empty. Step 4 is "Optionally refactor to improve the implementation design".
Canon TDD's steps as a flowchart, drawn by Vic Wu and shown in Kent Beck's post. From , 30 October 2026.
Citations (55)
From snapshot/skills/tdd/SKILL.md, lines 36–37: “- 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.”
From snapshot/skills/tdd/SKILL.md, line 32: “Horizontal slicing: writing all tests first, then all implementation. Bulk tests verify imagined behavior: you test the shape of things rather than user-facing behavior, the tests go insensitive to real changes, and you commit to test structure before understanding the implementation.”
From snapshot/skills/tdd/SKILL.md, line 32: “Work in vertical slices instead: one test → one implementation → repeat, each test a tracer bullet that responds to what the last cycle taught you.”
From snapshot/skills/tdd/SKILL.md, line 20: “A is the public boundary you test at: the interface where you observe behavior without reaching inside.”
Matt's tdd starts with seams agreed with you, not a test list, and as the short part says, refactoring waits for review. His tdd page (updated 24 August 2026) says why. The step was dropped in June 2026 "because agents almost never performed it", and because review and building work better as separate sessions. He adds: "Whether the result still counts as TDD by the book matters less than whether the loop produces better code." So Matt's red-green is not Canon TDD. It's red-green with the refactor step taken out.
Canon TDD
Matt's tdd
It starts with
a list of the test scenarios you want to cover
seams agreed with you
Refactoring
Optionally refactor to improve the implementation design
not part of the loop
Matt's red-green is not Canon TDD
One trap: the words disagree inside Matt's own repo. At the pin commit, tdd's description still says it fires when you mention "red-green-refactor", and the README says "red-green-refactor" too. That README wording dates from 28 April 2026, before the refactor step was dropped in June 2026. The Skill's body is newer, and it decides: "Refactoring is not part of the loop." Issue #589 (opened 16 July 2026) asks to fix the description, and it is still open. Matt's tdd page says the phrase still loads the Skill, but what you get is red-green.
Why does red have to come first? Matt's answer is about agents: when the agent builds the failure first, "It's also very hard for an agent to cheat that."
Anthropic's Claude Code guide makes the same point from the other side. Claude "stops when the work looks done". With nothing to run, "that makes you the test suite". It says to ask for evidence, because "All tests pass" on its own tells you very little.
A real example
Issue #479 is about implement skipping its tdd step. On 18 July 2026 one user, maximumaliens, reported a real run. The agent made the code changes first and added the tests afterwards. "The resulting green suite did not demonstrate that the tests could detect the pre-fix behaviour." To get that proof back, they had to stash the code changes and run the new tests against the old code. That is "TDD evidence", gathered by hand after the fact.
Where it goes wrong
The agent writes the code first anyway. Matt's tdd page quotes one agent: "I just defaulted to my normal habit." The Skill accepts this. If a slice really matters, watch the run rather than trusting the Skill to enforce it.
Tests that restate the code. Matt says agents "will often just write crap tests", like one that "writes a constant and then it says expect this constant to be this value." The current tdd Skill (pin commit, 29 October 2026) names this anti-pattern "Tautological", for example "a constant asserted equal to itself". Beck warns of a close cousin: copying the code's computed values into the test's expected values.
Faking green. Beck's list also has "Mistake: delete assertions so the test pretends to pass."
Slow tests first. One user's agent wrote a browser test first, then decided the test was broken for a feature that didn't exist yet. Matt's page: "Browser tests are slow enough that the red-green feedback loop stops paying for itself."
Try it
In your practice project (set it up first with keeping-track's Try it step if you haven't), add one small rule to the booking API, test first. For example: a class that is full refuses a new booking.
Agree the seam with your agent: the HTTP API in api/, not a private helper.
Ask for one test at that seam. Run it with docker compose exec api pytest and read the failure. It should fail because the booking went through, not because of an import error or a typo.
Let the agent write only enough code to pass it.
Then ask for TDD evidence: the command it ran and the output, red before and green after.
Going deeper's Check questions are asked in Next up.
seam
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. No test is written at an unconfirmed seam. You can't test everything, so agreeing the seams up front is how testing effort lands on the critical paths and complex logic instead of every edge case.”
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”
From snapshot/skills/to-spec/SKILL.md, lines 15–17: “Sketch out the seams at which you're going to test the feature. Existing seams should be preferred to new ones. Use the highest seam possible. If new seams are needed, propose them at the highest point you can. The fewer seams across the codebase, the better - the ideal number is one. Check with the user that these seams match their expectations.”
From snapshot/web/youtube.com/watch-v-4dhcspkebwi.md, lines 846–850: “Agents, the thing that's great about agents is that they have a much larger working memory than humans, right? [79:08] They can actually hold a lot more in their heads than than humans can currently, which is very useful. [79:13] But um they don't have an infinite working memory. [79:18] And TDD it's sort of aiming at the wrong problem I think. [79:22] But the thing that agents really do need is that they need to have feedback loops.”
From snapshot/web/youtube.com/watch-v-4dhcspkebwi.md, lines 856–858: “even if I'm not using TDD directly where it, you know, writes the failing test first, then uh fixes it, then refactors, I will [80:02] often say, provide proof that your change does the thing it's purported to do. [80:06] Give me TDD evidence, right? That it's it would fail without this change.”
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/aihero.dev/skills-tdd.md, line 118: “There is no refactor phase. The skill dropped it in June 2026 because agents almost never performed it, and because review and implementation work better as separate sessions.”
From snapshot/skills/tdd/SKILL.md, line 3: “description: 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/web/aihero.dev/skills-tdd.md, line 140: “The mismatch between the trigger phrase and the body is filed as issue #589 and is still open, so "red-green-refactor" continues to work as a phrase that fires the skill. What you get is red-green”
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/web/code.claude.com/docs-en-best-practices.md, line 206: “Claude stops when the work looks done. If it has nothing to run that tells it whether the work actually is done, “looks done” is all it has to go on. In practice that makes you the test suite”
From snapshot/web/github.com/mattpocock-skills-issues-479.md, line 407: “The agent made the implementation edits first and added the test scripts afterwards, despite /tdd requiring: “Red before green. Write the failing test first.” The resulting green suite did not demonstrate that the tests could detect the pre-fix behaviour. I had to stash the implementation changes and run the new tests against the old code to recover that evidence manually.”
From snapshot/web/youtube.com/watch-v-4dhcspkebwi.md, lines 859–862: “another thing with TDD that agents get wrong is they will often just write crap tests. [80:19] They'll often just write especially toological tests where the test is just asserting the implementation itself. [80:27] It's just like a duplicate of it. [80:29] You know it it >> writes a constant and then it says expect this constant to be this value.”
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.”