TDD with AI Agents: Red-Green as an Agent Loop
Test-driven development found its killer app: agents. How write-the-test-first turns AI coding into a verifiable loop, and the workflow that makes it stick.
TDD and agents are a natural fit because the agentic loop needs exactly what TDD provides: a machine-checkable definition of done. The workflow — human (or agent, then human-reviewed) writes the failing test; agent implements until green without touching the test; refactor with the net in place — converts 'did the AI get it right?' from a reading problem into a running problem.
Key takeaways
- Agents made TDD's economics flip: the discipline's old cost (writing tests first feels slow) collapses when an agent drafts the tests and another makes them pass.
- A failing test is the perfect agent prompt — unambiguous, self-verifying, and immune to the agent declaring victory early.
- The cardinal rule is test immutability during implementation: the agent makes the test pass, never edits it to pass — enforce it in instructions or hooks.
- Red-green-refactor maps cleanly onto agent ergonomics: red (review the spec-as-test), green (agent iterates against failure output), refactor (agent cleans up under the net).
- TDD doesn't suit everything — exploration and UI taste resist it — but for behavior with a definable contract, it's the highest-trust agent workflow there is.
Test-driven development spent twenty years as the discipline everyone praised and few sustained — the upfront cost kept losing to deadline gravity. Then agents arrived and inverted the economics: the agentic loop needs a machine-checkable goal, and TDD is a machine for producing exactly those. The old chore became the highest-trust way to direct an AI.
Why the fit is structural
An agent works by acting, observing, and iterating. Give it a vague goal ("add retry logic") and the loop has no honest termination — it stops when output looks done. Give it a failing test and everything snaps into place:
- The goal is unambiguous: make this red turn green.
- Feedback is free: every run's failure output tells the agent what to fix next — no human in the inner loop.
- Victory is checkable: the agent can't talk its way past a red suite.
- The spec survives: requirements live in an executable file, not scrollback — kin to spec-driven development, at function scale.
The workflow
Red — author the contract. Write the failing test, or better: have the agent draft tests from the requirement and edit the assertions until they say what you mean (write-tests / test-scaffolder start this). Your review effort lands here, on twenty readable lines — this is the step where thinking happens.
Green — turn the agent loose. Fresh session ideally, with the rule stated plainly: make retry.test.ts pass; the test file is read-only; if you believe the test is wrong, stop and explain. The agent runs the suite, reads failures, edits, repeats — the fix-failing-test loop pointed at tests-as-spec. For stakes, make immutability mechanical: a hook or permission rule denying edits to the test path during the task converts a polite request into physics.
Refactor — clean under the net. With green as the invariant, ask for the cleanup pass: naming, duplication, structure. The suite catches regressions instantly, which is precisely the condition under which agent refactoring is safe.
WARNING
The one corruption to guard against absolutely: an agent "fixing" the test to match buggy code. It's rare with clear instructions, catastrophic when missed, and trivially prevented — diff review always shows test files, and hooks can forbid the edit outright. Test immutability during implementation is the whole game's integrity.
Where TDD-with-agents isn't the tool
Honesty clause: TDD presumes you can state the contract first. Exploration (you don't know what you want yet — vibe-code the spike, then TDD the real build), UI taste (the test is your eyes), and glue with trivial logic all resist it. The heuristic: if you can finish the sentence "done means…" with something checkable, lead with the test; if you can't, that sentence is the work — go find it first.
For the wider verification stack around this loop — reviewing agent-written tests, the self-grading trap, what tests can't see — continue with How to Test AI-Generated Code.
Frequently asked questions
- Why does TDD work so well with AI agents?
- Because the agent loop runs on verifiable feedback, and a failing test is the cleanest feedback that exists: run, read the failure, edit, repeat — no human judging each iteration. It also kills the two classic agent failure modes at once: premature success claims (the suite disagrees) and specification drift (the test IS the spec, in executable form).
- Who writes the test — me or the agent?
- Either, with one constant: a human reviews the test. Practical default — agent drafts tests from the requirement (breadth is its strength), you edit the assertions until they encode what you actually mean, THEN implementation starts (ideally a fresh session, so the implementer pursues the test rather than its own earlier guesses).
- How do I stop the agent from just changing the test?
- State it as a hard rule in the task ('make this pass; the test file is read-only'), and enforce mechanically where stakes warrant: a PreToolUse hook or permission rule denying edits to the test path during the task. If the agent believes the test itself is wrong, the instruction is to STOP and say so — that disagreement is exactly what you want surfaced.
- Does this replace normal code review?
- It narrows it productively. Green suite = the contract holds, so review stops re-deriving correctness and spends on what tests can't see: security, performance, design, scope creep. Tests buy trust in behavior; review buys trust in everything else.
Related
- How to Test AI-Generated CodeAI writes the code; tests decide whether to trust it. The verification stack for agent-written changes — contracts, generated tests, and the review that's left.
- Write TestsGenerate tests covering the happy path and edge cases for the given target.
- Fix Failing TestDiagnose and fix a failing test by finding the real root cause.
- Test ScaffolderScaffold a test file with sensible cases for a given module or function. Use when adding tests to untested code and you want a fast, structured starting point.
- Claude Code Hooks: Automate Formatting, Tests, and GuardrailsHow Claude Code hooks work — the major hook events, the settings.json configuration shape, exit codes and JSON output, plus three hooks worth copying.
- What Is Claude Code?A grounded explanation of Claude Code: an agentic command-line coding tool that reads files, runs commands, and works in a loop toward a goal.
- Spec-Driven Development with AI AgentsWrite the spec, let the agent implement against it — the SDD workflow (spec → plan → tasks → implement), when it beats prompt-and-iterate, and the tooling.