Coding agents are fast enough now that the slow part of the job has moved. Writing the code takes Claude Code or Codex CLI a few minutes. Making sure the code is right is still on you, and it's tempting to skip. The agent says "All tests pass, the feature is implemented," the terminal looks tidy, and you type git commit -am "add feature".
Then, three days later, you find out the tests pass because the agent deleted the one that failed.
This is the review routine I use before committing anything an agent wrote. It doesn't need special tools: it's git, your test runner, and a few habits. It takes five to fifteen minutes for a typical change, and that's a lot less time than debugging a bad commit later.
1. Start from a clean baseline
Reviewing is much easier when the only uncommitted changes in your tree belong to the agent. Before you start a session, commit or stash your own work:
git status
git stash push -m "my work before agent session"
Now whatever shows up in git status afterward came from the agent. If you mix your half-finished edits with the agent's, you can't tell which lines you're supposed to be reviewing.
2. Ask the agent for a summary, then don't trust it
When the agent finishes, ask it to explain what it did. Something like:
List every file you changed, created, or deleted. For each one, say in one
sentence what changed and why. Then list anything you were unsure about,
any tests you modified or skipped, and any new dependencies you added.
This summary is useful as a map, not as evidence. Agents sometimes describe what they intended rather than what they did, and they tend to leave out the edits they made along the way, like "I also tidied up this other function." Treat the summary as a list of claims you're about to check against the diff.
3. Read the shape of the change first
Before reading any code, look at how big the change is and where it landed:
git status
git diff --stat
git diff --name-status
--stat shows lines added and removed per file. --name-status shows whether each file was modified (M), added (A), deleted (D), or renamed (R). This is where you catch the big surprises cheaply:
- A file you never mentioned has 200 changed lines.
- A test file shows up as D.
-
package.json,requirements.txt,Cargo.toml, or a lockfile changed when you didn't ask for a dependency. - A config file, CI workflow, or
.env.examplechanged.
One trap: git diff doesn't show new files that haven't been staged. Agents create files all the time, so list them explicitly:
git ls-files --others --exclude-standard
If you want new files to show up in the diff alongside everything else, mark them with intent-to-add. It records that the file exists without staging its contents:
git add -N path/to/new_file.py
git diff
4. Read the diff file by file
Don't scroll through one giant diff. Go a file at a time, starting with the files that matter most (core logic, then tests, then everything else):
git diff -- src/payments/refund.ts
If the agent reformatted things and the noise is drowning out the real change, ignore whitespace while you read:
git diff -w -- src/payments/refund.ts
And run git diff --check once to flag trailing whitespace and leftover conflict markers.
For each file, ask three questions: Does this change belong to the task? Do I understand every line of it? What happens when this code gets bad input?
5. Look for the usual agent mistakes
Agents make a fairly predictable set of mistakes. They're worth checking for by name, because they don't jump out at you when you're just skimming.
Deleted or weakened tests. This one matters most. If a test was failing, the fastest way to "fix" it is to delete it, mark it skipped, loosen the assertion, or change the expected value to whatever the code now returns. Look for removed test cases, new skip or xfail markers, .only left in JavaScript tests, and assertions that got vaguer (toEqual(42) becoming toBeDefined()).
Swallowed errors. An empty catch block, except Exception: pass, a try that logs and carries on, or a ?? [] that quietly turns a failure into an empty result. These make the error go away without fixing anything.
Invented APIs. A method that sounds right but doesn't exist in your version of the library, or a config option it guessed at. Type checkers and tests catch some of these. For the rest, check the call against the library's docs or source.
Unrelated edits. Renamed variables, reordered imports, "improved" functions nobody asked about, or comments deleted. Each one might be harmless, but together they bloat the diff and hide the real change. Revert them unless you actually want them.
Hardcoded values. Magic numbers, a hardcoded user ID or URL from the example you gave it, a fixed date, a file path that only exists on your machine, or (worst) a real API key pasted in for testing.
New dependencies. A whole package added to do something your standard library already does. Check that it's real, maintained, and actually needed before you accept it, and look at how much the lockfile changed.
Leftover debris. console.log and print statements, TODOs, commented-out blocks, scratch scripts, and backup files in the repo root.
A quick search helps with a few of these:
git diff | grep -nE "^\+.*(console\.log|print\(|TODO|FIXME|\.only\(|skip)"
It's crude and will produce false positives, but it only takes a second.
6. Run the checks yourself
The agent saying "tests pass" isn't the same as the tests passing. Maybe it ran a subset, maybe it ran them before its last edit, or maybe the run failed and it misread the output. Run them yourself in your own terminal:
npm test # or pytest, cargo test, go test ./...
npm run lint # or ruff check ., cargo clippy, etc.
npm run typecheck # if your project has one
Use whatever commands your project actually has. If there's a test that covers the feature, make sure it would fail without the change. A quick way to check is to stash the source change, keep the test, and run it again. A test that passes either way isn't testing anything.
If the change is something you can see, like a UI, a CLI, or an endpoint, try it by hand too. Spend two minutes on the happy path and one obvious edge case.
7. Stage hunk by hunk with git add -p
This is the habit that makes the biggest difference. Instead of git add ., stage interactively:
git add -p
Git shows you each hunk and asks what to do with it. The keys you'll use most are y (stage this hunk), n (skip it), s (split it into smaller hunks), q (quit), and ? (help). Keep the hunks you've reviewed and agree with, and skip the rest.
It forces you to look at every change one more time, and it lets you commit the good 80% of a session while leaving the questionable 20% unstaged. Before you commit, check exactly what's going in:
git diff --staged
If you staged something by mistake, unstage it without losing the edit:
git restore --staged path/to/file
8. Run a second-pass review with a fresh context
The agent that wrote the code is a poor judge of it, because it's still anchored to its own reasoning. A new session, or a different tool, does better. Start a fresh Claude Code or Codex session, or paste the diff into one, and give it a narrow, adversarial brief:
Review the staged diff (git diff --staged) as a strict senior reviewer.
Do not rewrite anything. Report only:
1. Bugs or edge cases that would break in production
2. Tests that were removed, skipped, or weakened
3. Errors that are caught and ignored
4. Calls to functions or options that may not exist
5. Changes unrelated to the stated goal: <describe the goal>
For each issue, give the file, the line, and why it matters.
Telling it not to rewrite anything keeps it from opening a new round of edits. Treat what it reports as leads to check, not verdicts. A second model can invent problems as easily as the first one invented APIs.
9. Keep diffs small enough to review
Most review pain comes from how the agent was asked, not from the review itself. A prompt like "build the settings page" produces a 900-line diff that nobody reads properly. Smaller asks give you diffs you can actually review:
- Give the agent one task per session, and say what's out of scope ("don't touch the API layer").
- Ask it to stop after each step so you can review and commit before it continues.
- Commit working checkpoints often. Small commits are cheap, and each one becomes a safe point to go back to.
- If a diff is too big to review honestly, split it with
git add -pacross a few commits, or throw it out and ask again in smaller pieces.
10. Know when to throw it away
Sometimes the right review outcome is "no." If the approach is wrong, re-prompting on top of a messy diff usually makes things worse. Reset and try again with a better prompt.
To discard the changes in one file:
git restore path/to/file
To discard all uncommitted changes to tracked files:
git restore .
That deletes the work for good, so if you might want any of it back, stash it instead:
git stash push -u -m "agent attempt 1: wrong approach"
git stash list
The -u flag includes untracked files, which matters because agents create so many of them. Later you can look at it with git stash show -p stash@{0} or bring it back with git stash pop.
For any untracked files left over, preview before you delete:
git clean -n # shows what would be removed
git clean -f # actually removes them
The checklist
Before you commit agent-written code:
- Started from a clean tree, so every change is the agent's
- Asked for a summary and checked it against the diff
- Read
git diff --stat,--name-status, and the list of untracked files - Read every file's diff, most important first
- Checked for deleted tests, swallowed errors, invented APIs, unrelated edits, hardcoded values, new dependencies, and debris
- Ran tests, linters, and type checks yourself
- Staged with
git add -pand rereadgit diff --staged - Got a second-pass review from a fresh session on anything non-trivial
- Reverted or stashed whatever you didn't trust
None of this is new. It's how you'd review a pull request from a fast, confident colleague who sometimes makes things up. The agent writes code much faster than any colleague, which is exactly why the review step can't be skipped.
Disclosure: I built TokenBar, a $15 lifetime Mac menu bar app that shows your Claude Code and Codex usage and cost, which helps when second-pass reviews start eating into your limits. It's built on the MIT-licensed open-source CodexBar. tokenbar.site
Top comments (0)