Published on , Aurélien Vandaële

Making an AI agent write the tests before the code: my Claude Code method

In my chain, a first agent writes the tests and proves they fail, a second writes the code that makes them pass, a third reviews without having seen any of the writing. Tests written first act as a contract: the agent that codes can no longer decide on its own that “it works”.

The problem when an agent codes, then tests

Ask an agent to write a function, then its tests. The tests will almost always pass, and that is exactly the issue: they describe what the code does, not what it was supposed to do. A misunderstanding ends up carved twice, once in the code and once in the test that approves it.

Reversing the order breaks that loop. The test is written from the request, before a single line of code exists. It fails, which proves it checks something. Only then is the code written.

Three roles, never in the same head

In Claude Code, a subagent is a Markdown file stored in .claude/agents/: a description, the tools it may use, and its instructions. Each subagent starts with a fresh context. That is what makes the separation of roles possible.

  • The test agent receives the brief of one task. It writes the tests, runs them, shows that they fail for the right reason, and stops there. It is not allowed to write the code.
  • The code agent receives those tests and makes them pass. It is not allowed to weaken a test to get there. Tests and code go into a single commit.
  • The review agent can only read. It receives the diff and the brief, never the conversation that produced the code. It returns a verdict: what blocks, what should be fixed.

The reviewer is the most important piece. An agent reviewing its own work finds it convincing, because it remembers why it wrote it that way. An agent that only has the result in front of it asks the questions a colleague would ask.

The guardrails that hold the chain

  • Two fix rounds, no more. If the reviewer still blocks after two round trips, the chain stops and I take over. Beyond that, agents go in circles.
  • The same checks on every commit: lint, types, tests. Nothing moves until everything is green.
  • Hooks that forbid shortcuts: tests cannot be skipped, no --no-verify, and a session cannot end in red.

These rules do not rely on the model's good will. They are executed by the tool, so they also apply on the days when the model is in a hurry to finish.

What a session looks like

I packaged this chain as a Claude Code plugin that I use on all my projects. Once the plan is written, one command is enough:

/pipeline:init          # once per project
/pipeline:build plan.md # runs the plan, task by task

For each task in the plan, the command chains the three agents, runs the checks, and moves on to the next. I read the result at the end, and I am warned earlier if a task has used up its two rounds.

You can build the same thing without a plugin: three files in .claude/agents/, a reviewer limited to read tools, and a single command that runs lint, types and tests.

What it changed in production

I built this chain at Bayard, on the La Croix app, from what the team was already doing before AI: unit tests, end-to-end tests, visual regression, static analysis. Measured result: three times more tickets shipped and 40% fewer errors in production.

The gain does not come from a smarter model. It comes from every step being checked by something other than whoever did it.

Article written with the help of AI, from my daily practice and my projects.

The whole notebook