
Your AI Agent Writes Code. Is Anything Actually Reviewing It?
AI coding agents are shipping code faster than ever, but review practices haven't kept up. Here's how to close the gap without killing velocity.
AI coding agents have crossed the line from autocomplete to autonomous contributor. They open pull requests, refactor modules, migrate frameworks, and occasionally push to main when nobody's looking. The throughput is staggering. The review pipeline, in most teams, is not.
This piece is not an argument against AI-generated code. It's an argument that the review surface has to grow at the same rate as the generation surface, and in most organizations it hasn't. We'll look at what's actually breaking, why traditional PR review doesn't transfer cleanly, and a tiered framework for reviewing agent-written code without becoming the bottleneck yourself.
- 1. The Velocity Problem
- 2. What Makes Agent-Written Code Different
- 3. Why Traditional Review Breaks Down
- 4. A Tiered Review Framework
- 5. Automating the Mechanical Layer
- 6. What Humans Should Actually Read
- 7. Measuring Whether It's Working
- 8. Frequently Asked Questions
1. The Velocity Problem
A year ago, a senior engineer might produce 200-400 lines of meaningful change per day. Today, a single engineer directing an agent can plausibly generate 2,000-5,000 lines across multiple PRs in the same window. The ratio of code written to code read has inverted, and review capacity — which scales with human attention, not compute — has not.
The symptoms show up in predictable places:
- PR queues that never empty. Agents file PRs faster than humans clear them. The queue becomes a backlog of "merged on Friday because it was there."
- Review fatigue masquerading as approval. Reviewers skim diffs that are too large to hold in working memory and approve because rejecting feels like blocking progress.
- Tests that exist but don't test. Agents are great at generating tests that pass. They're worse at generating tests that fail when the code is wrong, which is the only kind that matters.
- Silent contract violations. An agent renames a field, updates the callers it can see, and misses the three services in another repo that consume the same event. Nothing fails locally.
None of this requires the agent to be "bad" at code. It requires the system around the agent to be unprepared for the throughput.
2. What Makes Agent-Written Code Different
Agent-written code is not just faster human code. It has structural properties that change how you should review it.
It's locally coherent but globally inconsistent. An agent can produce a flawless function that uses a naming convention, error-handling style, and logging format that no human on your team would choose. Each file passes review; the codebase drifts.
It optimizes for the prompt, not the system. The agent was asked to "add retry logic." It added retry logic. It did not consider that retries amplify load on an already-struggling dependency, because that wasn't in the prompt and wasn't in the diff's immediate neighborhood.
It has no memory of why. A human who wrote a workaround leaves a comment, a Slack message, a tribal scar. An agent leaves nothing but the code, and the code looks intentional even when it's a hack.
It's confident. LLMs don't hedge. A 60%-correct implementation reads identically to a 99%-correct one. There's no "TODO: not sure about this" to triage.
These properties don't make agent code worse than human code in every case. They make it differently risky, and that difference is the whole problem with applying a uniform review process.
3. Why Traditional Review Breaks Down
The standard PR review model assumes a few things that stop being true:
- The diff is small enough to read. Agent PRs routinely exceed 1,000 lines. Reviewers cannot hold that in working memory; they revert to pattern-matching and rubber-stamping.
- The author understands the change. When a human writes code, they can answer "why did you do it this way?" An agent's author often can't, because they directed rather than authored.
- One reviewer is enough. The single-reviewer model works when author and reviewer share context. Agent code has no shared context with anyone.
- Approval means "I read and agree." In practice, approval increasingly means "CI is green and I don't see anything obviously wrong."
The honest fix is not to make humans review harder. It's to move most of the verification left into automation and reserve human attention for the things automation cannot judge.
4. A Tiered Review Framework
Think of review as four tiers, each catching a different class of defect. The goal is to push as much as possible into tiers 1 and 2 so that tier 3 and 4 are tractable.
Tier 1 — Automated static checks (seconds). Formatting, linting, type checking, secret scanning, dependency vulnerability checks, license compliance. These should be non-negotiable gates. If an agent-generated PR fails tier 1, it never reaches a human.
Tier 2 — Automated behavioral checks (minutes). Unit tests, integration tests, contract tests, property-based tests, mutation testing, snapshot diffs for generated code. This is where most of the value lives, and it's the tier most teams underinvest in because it's harder than linting.
Tier 3 — Targeted human review (minutes to tens of minutes). Not "read the whole diff." Read the plan, read the boundaries, read the contracts. More on this below.
Tier 4 — Architectural / security review (scheduled). For changes that touch auth, data models, public APIs, or infra. This should be a separate, slower track, not a PR comment.
The key insight: tier 3 should shrink as tiers 1 and 2 grow. If your humans are still reading formatting nits and obvious null checks, your automation is underbuilt.
5. Automating the Mechanical Layer
A realistic tier-1/tier-2 setup for a TypeScript service might look like this. The point isn't the specific tools; it's that everything here runs on every PR without a human clicking anything.
# .github/workflows/review-gate.yml
name: review-gate
on: [pull_request]
jobs:
static:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm run lint
- run: npm run typecheck
- run: npm run secrets:scan
- run: npm audit --audit-level=high
behavioral:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm test -- --coverage
- run: npm run test:contracts
- run: npm run mutation:test -- --threshold 70
A few non-obvious additions that pay off specifically for agent-written code:
- Mutation testing. Agents generate tests that pass. Mutation testing tells you whether those tests would catch a regression. A suite with 90% line coverage and 30% mutation score is a liability, not an asset.
- Contract tests against real schemas. If an agent renames a field, a contract test against the OpenAPI spec or the protobuf file catches it even when unit tests don't.
- Snapshot diffs on generated artifacts. If your repo contains generated code (ORM models, route tables), diff them explicitly. Agents love to "improve" generated files by hand.
- A size gate. Reject PRs over a threshold (say, 500 lines changed) unless they're explicitly flagged. Force the agent (or its operator) to split. Reviewability is a property of the diff, not the code.
6. What Humans Should Actually Read
If automation handles tiers 1 and 2, tier-3 human review should be narrow and opinionated. Concretely, reviewers should spend their minutes on:
The plan, not the diff. Require every agent-authored PR to include a short "intent" section: what was asked, what approach was taken, what was considered and rejected. If the author can't write this, the change isn't ready for review. This is the single highest-leverage habit in this article.
The boundaries. Where does this code touch the outside world? Database migrations, external API calls, auth checks, message queue producers/consumers, feature flags. These are where agent code bites, because the agent only sees the local graph.
The contracts. Public interfaces, event schemas, shared types. An agent that changes a return type and updates all in-repo callers is correct locally and broken globally.
The tests' quality, not their existence. Read the tests as if the code were wrong. Do they assert behavior, or do they assert the implementation? Would they fail if you flipped a comparison operator? This is the manual equivalent of mutation testing and it's the best use of human judgment.
What's not there. Error handling on the unhappy path. Logging that would let you debug this in production. Rollback story. Agents optimize for the happy path because that's what "make it work" means.
What humans should not be doing: reading every line of a 1,200-line refactor, debating naming, reformatting. Those are tier-1 concerns and should be enforced by tooling, not taste.
7. Measuring Whether It's Working
You can't improve what you don't measure, and "review quality" is notoriously hard to measure. A few proxies that are actually tractable:
- Defect escape rate by source. Track production incidents and tag them as agent-authored, human-authored, or mixed. If agent-authored code has a higher escape rate, your review pipeline is the problem, not the agent.
- Time-to-merge distribution. A bimodal distribution (fast merges and week-old PRs) signals review bottlenecks more than a slow average does.
- Mutation score trend. Track it per module. Modules with declining mutation scores are modules where tests are being generated to pass, not to protect.
- Revert rate. Agent-authored PRs that get reverted within 48 hours of merge. High revert rate means tier-3 review is approving too fast.
- Review comment density. If agent PRs get far fewer comments than human PRs of similar size, reviewers aren't reading them.
None of these require new infrastructure — they're aggregations of data you already have in Git, CI, and your incident tracker.
8. Frequently Asked Questions
Should we require human approval on every agent-authored PR? Yes, but make it meaningful. A rubber-stamp approval is worse than no approval because it creates false confidence. If your review can't be meaningful given the diff size, the fix is smaller diffs, not more reviewers.
Can we use an LLM to review LLM-generated code? Yes, as a tier-2.5 layer, with caveats. A second model reviewing the first's output catches a surprising number of bugs and is cheap. It does not catch architectural mistakes or contract violations, because those require system context the reviewing model doesn't have. Treat it as an additional signal, never as the deciding one.
How do we handle agents that push directly to main? Don't, in production code. The only acceptable direct-to-main automation is for changes that are fully covered by tier-1 and tier-2 gates and are reversible (feature flags, config, generated docs). Everything else goes through a PR with human approval. The velocity loss is smaller than the incident cost.
What's the right PR size limit for agent code? Lower than for human code. Humans write large PRs when a refactor genuinely requires it; agents write large PRs because they don't feel the pain of review. A 300-500 line limit, enforced by CI, forces decomposition and makes review tractable. Exceptions should require a written justification, not just a label.
The goal was never to stop AI agents from writing code. It's to make sure that when they do, someone — or something — is actually checking the work. The teams that figure out the review side of this equation will get the velocity and keep the reliability. The ones that don't will ship faster right up until they don't. For more on engineering practices and developer tooling, see Tamiz's Insights.