A pull request written by an agent has an odd property: the person who opened it did not write it, and the thing that did write it cannot be asked what it meant. The usual review shortcut, trusting the author’s judgment on the parts you skim, stops working. Approval still carries your name, and the reviewer is now the only human who has read the diff closely.

That changes what review is for. Our general code review practices still apply, but agent-written changes fail in some distinctive ways, and a checklist tuned to them is faster than rereading everything with equal suspicion.

What the evidence says, with caveats

Two vendor studies are worth knowing, as long as you remember each vendor sells a product in this area.

CodeRabbit’s December 2025 report analyzed 470 open source pull requests, 320 labeled as AI co-authored and 150 human-only. It found about 10.83 issues per AI pull request against 6.45 for human ones, with logic and correctness issues up 75% and security issues up 1.5 to 2 times. The sample is small and the labeling relies on how contributors tagged their own work.

Veracode’s 2025 GenAI Code Security Report tested more than 100 language models on 80 curated tasks and found insecure code in 45 percent of cases. Those were isolated generation tasks, not agents working inside a mature codebase with tests and linters.

Neither study settles how your agent performs on your repository. They do agree on the direction: more defects slip through, concentrated in logic and security, and those are the categories a linter will not catch for you.

Before you read a line of the diff

1. Confirm the intent matches the ticket

Read the task or issue first, then the pull request description, and ask whether the change solves that problem. Agents are good at producing plausible work for a slightly different problem. Look for scope drift: renamed functions, reformatted files, and “while I was here” cleanups. If the diff touches files the task did not mention, ask why before reading further.

2. Check the size and shape

A change that is too large to review is too large to merge, whoever wrote it. Agents will happily produce a 1,500-line diff. Send it back with a request to split it, or ask for a stack of smaller pull requests. Mechanical changes such as renames and formatting belong in their own change, separate from behavior.

3. Run it yourself

Pull the branch and exercise the change. The description may claim the feature works, and the agent may sincerely believe it, but a claim is not an observation. Reproduce the original bug or run the new path by hand at least once.

Reading the code

4. Test the tests

Agent-written tests often confirm the implementation instead of the requirement. Three patterns to check:

  • Tests that mirror the code. A test that recomputes the expected value using the same logic as the function proves nothing.
  • Over-mocking. If every dependency is mocked, the test exercises the mocks.
  • Weakened assertions. Check whether existing tests were modified or deleted in the same pull request. An agent that hits a failing test sometimes changes the test instead of the code.

A fast sanity check is to revert the implementation change locally and confirm the new tests fail. A test that passes both ways is decoration.

# Vacuous: passes whether or not the discount logic works
def test_discount_applied():
    result = apply_discount(100, 0.1)
    assert result is not None

# Meaningful: pins the behavior
def test_discount_applied():
    assert apply_discount(100, 0.1) == 90

For deeper guidance on what good tests look like, see our unit testing strategy guide.

5. Hunt for invented APIs and dependencies

Language models sometimes call functions, flags, or package names that do not exist, or that exist in a different version than your lockfile pins. Verify every new import and every unfamiliar method against the official documentation for the pinned version. For new dependencies, check that the package is real, maintained, and the one you intended. Look-alike package names are a known supply-chain attack route, so a new line in a manifest deserves more scrutiny than any line of application code. Our guide to supply chain security, SBOMs, and signing covers the controls that back this check up.

6. Read error paths and edge cases

Agents write the happy path well. Look at what happens on empty input, timeouts, partial failures, and retries. Watch for swallowed exceptions, broad except or catch blocks that return a default, and retries without backoff or limits. These are the logic faults behind the correctness numbers above.

7. Review security-sensitive code line by line

Anything touching authentication, authorization, input handling, file paths, deserialization, SQL, or secrets gets a slow read, however small the diff. Check that user input never reaches a query, shell command, or template without proper handling, that authorization is enforced on the server and not only in the UI, and that nothing logs sensitive data. Veracode reported that models failed most often on cross-site scripting and log injection, which is a reason to look at output encoding and log statements specifically.

8. Look for duplication and misplaced abstractions

An agent working from a narrow context window will often reimplement a helper that already exists three directories away. Search the codebase for existing utilities before accepting a new one. Duplicated logic is cheap to create and expensive to maintain, and it is one of the first forms of debt that agent output adds.

Judging the blast radius

9. Check the files that are not code

Review configuration, migrations, CI workflows, infrastructure definitions, and permission changes with the same care as application code. An agent that edits a pipeline file or loosens a permission to make a build pass has fixed the symptom. Any change to CI, secrets handling, or deployment settings should require a human who owns that system.

10. Ask whether you could debug this at 3 a.m.

The final question is the practical one. If this change causes an incident, can the on-call engineer understand it from the code and its comments alone? If the logic is clever in a way that required the agent’s context to follow, ask for simplification before approving.

Team practices that make the checklist stick

A checklist helps only if the process around it supports it.

  • Label agent-authored pull requests. Reviewers calibrate differently when they know. A label or template field costs nothing.
  • Require a human owner. Each agent pull request should have a named engineer who is accountable for the change and who has read it, not merely a person who clicked merge.
  • Keep instructions in the repository. Many tools read a checked-in instruction file for conventions and commands. Putting your test command, style rules, and off-limits paths there reduces repeat mistakes and makes expectations reviewable.
  • Let automation take the mechanical work. Formatting, linting, type checking, and dependency scanning should run before a human looks, so reviewer attention goes to intent, design, and risk.
  • Track what you find. If reviewers repeatedly catch the same class of problem, such as missing authorization checks, add a lint rule, a test template, or an instruction-file line so the next change arrives without it.

Approving a pull request means you are willing to defend the change later. When the author is an agent, that standard does not drop; it moves entirely onto you. A short, repeatable checklist is how you meet it without reading every change as if it were hostile.