Doing Code Review With Claude Code

2026-07-11 · 6 min

Claude Code is genuinely useful as a code reviewer — not because it replaces a human, but because it's tireless at the mechanical parts humans skim: tracing every branch, checking each error path, noticing the null that isn't handled three files over. Used well, it catches a real class of bug before it reaches a teammate. Used badly, it produces a confident wall of "looks good to me" that teaches you nothing.

The difference is almost entirely in how you set up the review. This guide covers how to get a diff in front of Claude with the context it needs, what to make it hunt for, why an independent reviewer beats inline self-review, and — honestly — what it's good and bad at.

Get the diff in front of it, with the intent

The first mistake is reviewing the wrong thing. "Review my code" points Claude at the whole file when you changed six lines. Give it the actual diff. Claude Code has shell access, so the cleanest input is a real git command it runs itself:

git diff                 # unstaged working changes
git diff --staged        # what you're about to commit
git diff main...HEAD     # the whole branch vs main
gh pr diff 482           # a teammate's PR, if you use the GitHub CLI

Ask it to run one of these and review the output. Now it's looking at exactly the change under review, with surrounding context it can expand by reading the files.

The second mistake is bigger: reviewing a diff without the intent. A diff tells Claude what the code does; it can't tell it what the code is supposed to do. Without that, the best it offers is a description of the change and some generic hygiene notes. Give it the spec in one or two sentences — "this endpoint should apply a coupon once and reject a second redemption" — and the review changes character entirely. Now it can hunt for the gap between intent and behavior, where the real bugs live. A review is only as sharp as the "correct" it measures against.

What to make it hunt for

Left to its own devices, an agent drifts toward style nits — they're easy and always available. Direct it at the dimensions that actually matter, and ask for the failure, not the vibe:

  • Correctness against the intent. Does every path do what the spec says? Inverted conditions, a guard that checks the wrong variable, a return that skips cleanup.
  • Edge and boundary cases. Empty input, zero, negative numbers, the off-by-one at a range boundary, a list with one element, a null where the happy path assumed an object.
  • Concurrency and state. A check-then-write that isn't atomic, a shared mutable value, an assumption that two requests won't race.
  • Security. Missing authorization on a new endpoint, an ID from the request trusted without an ownership check (IDOR), unsanitized input reaching a query or a shell, a secret about to be logged.
  • Contract drift. The change updates a caller but not the type, or a response shape that a consumer three files away still expects in the old form.

The instruction that raises signal the most: report only findings you can attach a concrete failure to — an input, and the wrong output it produces, with a file:line. "Consider adding validation" is noise. "A negative quantity yields a negative total the endpoint returns as a valid discount, pricing.ts:88" is a finding. Tell it to rank by severity and to say "I couldn't break X" rather than padding the list to look thorough.

Inline self-review vs an independent reviewer

Here's the part most people get wrong. If Claude just wrote the change, asking that same conversation to review it is weak — and not for lack of effort. It's anchored. It already concluded the code was correct when it wrote it, so re-reading its own diff, it reads each line the way it intended the line to work, not the way the line actually behaves. The subtle bug it introduced is exactly the bug its self-review is blind to, because the flawed assumption is shared by author and reviewer. They're the same mind.

The fix is a subagent — a separate Claude with its own context window that never watched the code get written. In Claude Code, a subagent is a Markdown file under .claude/agents/ (or ~/.claude/agents/ to share it across your projects); Claude discovers it automatically, and its YAML frontmatter sets which tools it's allowed to use. Hand one the diff and the intent and it reviews with no stake in the code, which is what lets it see the hole the author rationalized away.

Two setup details do most of the work:

  • Scope it to read-only tools via the frontmatter tools field — Read, Grep, Glob, Bash, no Edit or Write. You want findings from a critic, not edits.
  • Put the adversarial posture in the file body, which becomes the subagent's system prompt — "treat the diff as wrong until it survives an honest attempt to break it." (The separate description field is what tells Claude when to hand a review to this subagent, so make it specific.) Pass the intent every time, or the review degrades into summarizing the code back to you.

This is worth wiring up once and committing so your whole team shares it. If you'd rather start from a working file than write one cold, the free claude-code-starter repo includes an adversarial-reviewer subagent you can drop in and adapt. Many Claude Code installs also ship review-oriented slash commands for the working diff and for GitHub PRs — check the current docs for the exact names and flags rather than trusting a command you saw in a blog post, since these evolve.

What it's good at

Be specific about where it earns trust, because that's where you should lean on it:

  • Local, mechanical correctness. Within the diff and its immediate neighbors, it's excellent at unhandled errors, missing null checks, a map that ignores a rejected promise, resource leaks, inverted logic.
  • Boundary enumeration. Ask "what inputs break this" and it lists the empty, zero, negative, and overflow cases a human reviewer mentally skips at 5pm.
  • Reading breadth. It'll open every call site of a changed function to check the contract still holds — tedious work humans cut short.
  • Consistency. It notices the new handler doesn't match the error shape of the ones beside it.

What it's bad at

And where it will confidently mislead you if you don't keep judgment in the loop:

  • Whole-system and product judgment. It can tell you the function is correct; it can't reliably tell you the function is the right thing to build, or that the architecture is sound. That's your call.
  • Domain truth it has no spec for. If "correct" depends on a business rule or a production invariant you never told it, it will happily approve code that's precisely wrong. It only measures against the intent you gave it.
  • Overconfidence and fabrication. It can invent a file:line, cite a function that doesn't exist, or report a "bug" that isn't one. Treat every finding as a claim to verify — telling it "don't invent findings" reduces this but doesn't eliminate it.
  • Proof. A clean review means "it tried and didn't find a break," never "this is provably correct." It is not a substitute for tests or for running the code.

The practical stance: use it to widen coverage and catch mechanical misses, then verify anything load-bearing yourself.

Reviewing code you didn't write

This applies just as well to a teammate's PR — arguably better, since you're already unanchored from code you didn't author. Feed it gh pr diff, give it the PR description as the intent, and ask it to flag the correctness and security issues you'd want to raise. Confirm the real findings against the code and drop the noise. It surfaces the boring-but-real issues, leaving your attention for the design questions it can't judge.

Conclusion

Good code review with Claude Code isn't a magic command — it's a setup. Give it the actual diff, tell it the intent, aim it at correctness, edges, and security instead of style, and prefer an independent reviewer over the anchored author. Then remember what it is: a sharp, tireless first pass that finds more than an unaided read and reports honestly about what it couldn't break — not a replacement for your judgment or your tests. Keep those, and it makes you faster without making you sloppy.

Related guides

Set up Claude Code the right way

Start free with the open-source starter — a ship skill, an adversarial-reviewer subagent, a bug-hunt workflow, and a CLAUDE.md template. Want the full kit? The Pro Pack adds 6 skills, 3 subagents, 3 workflows, 4 templates and a handbook.

Free starter on GitHub Get the Pro Pack — $39