How to actually review AI-generated code (you can't read it all)
At agent throughput you cannot line-read every diff. Here is a layered system for reviewing AI-generated code: automated review, tests as a gate, and human eyes where they matter.
An agent can produce more code in an afternoon than you used to review in a week. Three of them running in parallel produce more than you will ever line-read, and if you are honest about it, you already know you are not reading all of it. You open a pull request, the diff is green, the change looks like the kind of thing you would have written, and you approve it. That approval is a lie you tell quietly, and it is how bugs ship.
The dangerous part is not that AI writes bad code. It writes plausible code. A human writing a bug usually leaves a smell: an awkward variable name, a comment that argues with itself, a function that is clearly fighting the codebase. Generated code is fluent. It reads like it knows what it is doing. So the failure mode is specific: a large green diff that looks reasonable gets rubber-stamped, and the one inverted check buried on line 340 sails through because nobody was ever going to read line 340.
So stop pretending. You are not going to read all of it, and building your process around the fantasy that you will is the actual risk. The answer is not more willpower. It is defense in layers, because no single reviewer catches enough on its own.
Layer one: automated review that never gets tired
The first pass should be a machine, because a machine reads every line of every diff at 2am on a Friday with exactly as much attention as it had on Monday morning. Run a reviewer bot like Greptile and static analysis on every change, not on the ones you remember to check. This layer is cheap and it never skims. It will not understand your product, but it is very good at the mechanical stuff humans skip when they are tired: an unchecked null, a resource that is opened and never closed, a value shadowed two scopes up, a Promise nobody awaited.
The point of this layer is not that it is smart. It is that it is relentless. Consistency beats brilliance when the failure you are guarding against is inattention.
Layer two: tests as an objective gate
A reviewer bot has an opinion. Tests have a verdict. That difference matters, because the change is not done until the suite is green, and “green” is not a matter of taste.
Make this a rule the work has to clear, not a nice-to-have. If the area the agent touched has no coverage, then writing a test is part of the task, not a follow-up ticket that never gets filed. This is also the honest way to review code you did not read: you may not have traced every branch of the new function, but if a test asserts the behavior you actually care about and it passes, you have evidence rather than a feeling.
Agents are good at making tests pass, which is both the point and a trap. Watch for tests that assert nothing, tests that were quietly weakened to go green, and snapshots blessed without a look. A passing suite is only a gate if the tests were worth passing.
Layer three: humans, aimed where machines are blind
Now the part that is actually yours. You have a bot reading every line and a suite proving behavior, so you do not have to be the linter. Spend your limited attention on the things machines cannot judge.
Read for intent. Does this change do what the task asked, or something adjacent that happens to compile? Read the boundaries: the empty list, the expired token, the second concurrent request, the error path nobody exercises. Read the shape of the approach, because an agent will confidently build the wrong thing well, and no amount of static analysis flags “correct code, wrong design.”
A few habits make this pass sharper:
- Review the diff, not the chat log. The transcript is the agent’s story about what it did. The diff is what it actually did. When they disagree, the diff wins, and it is the only one of the two that ships.
- Watch the diff as it is produced. If you see edits arrive live, surprises surface while they are cheap to fix, not after the agent has built three more things on top of a bad decision.
- Some changes are always human-read, regardless of size. A three-line diff that touches authentication, money, a database migration, or a delete gets your eyes every time. Blast radius, not line count, decides what you read closely.
What a skim misses
Here is the kind of bug that walks past a tired human and gets caught by the other layers.
// Only admins should be able to delete a project.if (!user.isAdmin) { return deleteProject(projectId);}throw new ForbiddenError();Read that quickly and your eye registers “isAdmin, delete, ForbiddenError, looks like a permission check” and moves on. The logic is inverted: every non-admin can delete, and admins are the only ones blocked. It is four lines. It is green. It reads fine. A reviewer bot flags the inverted guard against the comment above it, and a test that asserts a normal user gets a 403 fails on the spot. A human on a skim approves it.
The off-by-one that drops the last row of a batch, the missing await that makes a check pass locally and race in production, the inverted flag above: none of these look wrong. That is exactly why you need layers that do not rely on anything looking wrong.
Where Fletch fits
Fletch is built around this idea: no single reviewer is enough, so it puts all three layers in front of you and refuses to let you skip past them.
The Code panel has a Live view, an activity feed of the agent’s edits rendered as unified diffs that auto-follows the file being edited. That is the “watch it as it happens” habit made default. You see the change take shape instead of meeting it fully formed in a pull request, so a wrong turn is a comment now rather than a revert later.
The Git panel is where the gate lives. When a branch has a PR, it shows a CI check rollup, pending, passing, or failing, with per-check detail and the real merge-gate state, so tests are a status you can see rather than a tab you forgot to open. It surfaces PR review comments with bot comments flagged, so a Greptile finding is right there next to the diff instead of buried in a notification. Any comment can be pushed into the composer with “-> chat,” which turns a review note into the agent’s next task without copy-paste. When checks fail, “Fix checks with agent” hands the failure straight back.
Fletch does not replace Greptile, your CI, or your test suite. It orchestrates the reviewers you already trust and lines them up as gates: the bot has read it, the suite is green, and you have read the part that needed a human. Then it merges, and not before. That is the whole trick. You were never going to read all of it, so build the process that assumes you won’t.