XavierFok
← all posts

I put AI code review on my own commits. Does it help?

2026-08-15 · by Xavier Fok

# I put AI code review on my own commits. Does it help?

A few months back I wired an AI reviewer into my commit pipeline. Every time I commit code, a model reads the diff and leaves comments before anything lands in the main branch, a second set of eyes on every change with no waiting on a human. This is an honest account of how that has gone, because the answer turned out to be more interesting than yes or no. It catches things I am glad it caught. It misses whole categories completely. Occasionally it costs me a minute I had not planned to spend. Here is the setup, the wins, the failures, and how I actually use it now.

The setup, minus the fog

There is a lot of vagueness around the phrase AI code review, so let me be concrete about the mechanics. When I commit a change, the diff, meaning the exact lines added and removed, goes to a model. The model reads those lines and returns comments: a possible bug, a variable name that fails to describe what it holds, a missing check that could bite later. All of this happens before the merge, and the comments land in the pull request in the same place a human reviewer's would.

That last detail matters more than it sounds. The feedback lives inside the workflow I already have, so there is no separate tool to remember to open, and reading the comments takes zero extra ceremony.

The other thing to understand is what the model can see. It has no memory of the codebase, no knowledge of decisions made last month, and no idea of the business reason behind the change. It sees one diff, in isolation, every time. That constraint is simultaneously its greatest strength and the root of everything it gets wrong, and both halves of this post flow from it.

What it reliably catches

The wins are real, so I will start there. The most consistent catch is the class of small mistake you make while tired or moving fast. A variable still named temp three changes after it stopped being temporary. A condition that reads backwards in one specific edge case. A missing null check on a value that exists every time except the one time it matters.

A careful human catches these too, but only while actually being careful, and the uncomfortable truth is that reviewers skim. I skim. Everyone skims, most of all on a small change we wrote ourselves and already believe we understand. The model never skims. It reads every line with identical attention on every pass, without fatigue and without the false confidence of authorship. For this narrow class of mechanical mistake, that consistency is genuinely worth having on every diff.

Two catches that earned their keep

One example stuck with me. A function of mine was supposed to log an error message to a file, and I had typed the wrong variable name in the logging call. The name existed in scope, so nothing would ever throw. The error path never fires in tests, so every test passed. The code would simply have logged something useless at exactly the moment I most needed the real error. A human reading at normal speed would sail past it. The model flagged it in seconds, noting a mismatch between the variable being logged and the variable actually holding the error. That was a genuine bug, and it had a future late night debugging session written all over it. It never got the chance.

The second win was a missing bounds check. I wrote a function that assumed its input list held at least one item, and an empty list would have crashed it with an index error. I had skipped the guard because, in my head, the caller always passes something. The reviewer pointed out the unchecked access and suggested a guard. I knew exactly why I had skipped it and still considered the risk low, and the flag was correct anyway. Thirty seconds later the guard existed and the function was meaningfully safer. That is the tool doing precisely its job.

The blind spot it cannot fix

Now the other half. The model has no idea why a change was made, and that plays out worse in practice than it sounds on paper.

I once refactored a function to be slightly less clean on purpose, because a production edge case had forced a workaround, and the workaround made the code a little awkward. The reviewer flagged the awkward section and suggested a tidier pattern, unaware that the tidier pattern was exactly the code that had just failed in production. It had no way to know. The diff carries no history, no incident report, no memory of what broke three days earlier. I knew why the code looked that way. The model could not.

No prompt engineering fixes this. The information is absent from the input, full stop. Anyone deploying one of these reviewers should hold that limitation in mind every time a suggestion sounds plausible.

The nitpicks that cost real minutes

The second frustration is style commentary on things that were never problems. A note that a variable could be named more descriptively when the name is perfectly clear in context. An observation that a function is a bit long, with no specific split that would improve anything. A flag on a mildly unconventional pattern that has worked in this codebase for two years.

Each comment takes a minute to read and consider, and ends with me doing nothing. The observations are technically valid from the model's limited view, which is exactly why it keeps producing them. Over time the noise carries a compounding cost: every false alarm teaches you to read the next comment with less attention, and eventually the real catches get skimmed too. Managing that erosion is part of owning the tool.

There is a sharper version of the same problem. One module of mine does something that looks wrong at a glance and is correct because of how a specific library behaves internally. The model flags it on every single diff that touches the module. Every time, I read the comment, confirm it is the same known issue, and move on, thirty seconds of friction that will never go away. A human who watched me respond to the same comment three times would stop raising it. The model cannot stop. Every diff is a fresh start with no memory of the last conversation, and that is a structural property of the approach rather than a bug awaiting a patch.

The verdict, framed carefully

Does it help? Yes, under a specific framing. It is a cheap, tireless mechanical reader that catches the small structural mistakes tired humans skip past. It does not catch design problems. It does not understand the architecture. It cannot tell you whether the change was the right change to make at all. What it can tell you is whether the lines you wrote contain surface level issues a careful reader would spot, and at that narrow job it is reliable on every commit, never distracted, never in a hurry to get to lunch.

For someone working alone with no reviewer at all, or on a team where reviews run slow and shallow, that guaranteed baseline of mechanical attention on every diff is worth real money. Just hold the frame: it is an additional reader, never a replacement for a thoughtful human one.

Advisory or nothing

The most important lesson of the whole experiment: this only works while the reviewer stays advisory. The moment it can block a merge until every comment resolves, you have built a system that can halt your workflow over a naming opinion.

Teams have tried the gatekeeper configuration, and the outcome is predictable. Developers write dismissive replies to every flag just to clear the gate, nobody reads any comment with care anymore, and the quality signal evaporates entirely. The model needs to be a voice in the conversation rather than a lock on the door. Treated as a second opinion I can accept or decline with my own judgment, it adds real value. Turned into a barrier I must argue past to ship, it becomes a frustration tax that makes the whole team resent it.

How it runs in my workflow now

The reviewer fires on every commit, and I read every comment without exception. Where I agree, I fix before the code lands. Where I disagree or already know the context, I leave a short reply explaining why and move on. It never blocks a merge on its own authority.

The framing that finally made it click for me: treat it like a junior developer who reads with total care, has good instincts, and lacks the full picture. You take their good catches seriously, you explain your reasoning when they misread something, and you do not hand them veto power over decisions they lack the context to judge. Junior advisor, never senior gatekeeper. It took me a while to land there, and once I did, the tool settled into being a genuine addition. It catches the mechanical, misses the contextual, generates noise I actively manage, and still earns its slot. I would not rip it out of my setup.

Check out more breakdowns like this at [xavierfok.com](/).

Get new guides and videos first — join the Telegram channel.