Our agents kept approving their own code. I'd ask the agent that wrote a change to review it, and it would read the change with the same reasoning that produced the bug, then tell me it looked fine. Teams worked this out a long time ago, which is why nobody approves their own pull request. Agents need the same rule.
With an agent it's worse than with a person. If it reviews its own work in the same session, it still has every assumption it made while writing, so you don't get a real second opinion. Tae-Eun Song tested this in a preprint called Cross-Context Review. The study planted 150 errors in code and documents and compared different ways of reviewing them. A reviewer in a fresh session, with no access to the original conversation, did better than the same agent reviewing its own work a second time in the same session.
How a change gets through now
Now the agent that writes a change never decides whether it's done. The work starts before there's any code. We agree the tests first, which means a plain-language QA plan built from the ticket's requirements, plus unit tests that fail until the feature exists. Then an agent writes the code to make those tests pass.
After that, several checks run at the same time, each in a fresh context. That just means the agent starts with a clean slate and never sees the conversation where the code was written. Browser tests walk through the QA plan the way a tester would. A separate run tries to break the change on purpose. A code reviewer checks that the code is correct and that it does what the ticket asked for, which is the closest thing to a classic peer review. That last check catches the most common failure with agents, code that's good but wrong. It neatly solves a slightly different problem from the one in the ticket.
Once those pass, the automated checks run. Next, another check reads what the docs and code comments say about the code and confirms it's actually true. Then a senior-level reviewer looks at the big picture and asks whether this is the right change or just a patch over a symptom. That reviewer will turn down a change that's correct on its own terms but wrong for where the system is going.
flowchart TD tests[Tests agreed before any code] --> write[Agent writes the code] write --> browser[Browser tests run the QA plan] write --> breaker[A separate run tries to break it] write --> review[Code reviewer checks it against the ticket] browser --> checks[Automated checks, then docs checked against the code] breaker --> checks review --> checks checks --> senior[Senior review of the big picture] senior --> human[Developer approves before anything ships]
Last, a human developer reviews the change and has to explicitly approve it. Only then is the code pushed, opened up for merging and announced to the team, and a person still does the actual merge. The agents hand the work along between them, so nobody's copy-pasting anything from one step to the next. By the time a change reaches the developer, it's been tested in a browser, attacked, checked against the ticket and reviewed for the big picture. The developer no longer has to be the first line of defense against everything, so their attention goes to the calls that really need a person.
Why one reviewer wasn't enough
Most of what makes a team of people reliable carries over to agents almost directly: separation of duties, fresh eyes, written decisions and clear briefs. I keep running into that across our whole agent setup, and code review is just the clearest case of it.
We started with a single reviewer agent and a long checklist. It did what a person with a long checklist does. It paid attention to whatever stood out most and skimmed the rest. Splitting the checks into separate contexts gives each one full attention. A check whose only job is to break the change can't get sidetracked by code style, because style isn't part of its brief.