productize.blog
AI · Coding Tools

Stop asking which one is better.
Ask which one signs off.

Codex and Claude Code really are good at different things. But what changed the quality of our work was not picking the higher score. It was a rule, enforced in code, that the model which wrote the work cannot be the one that reviews it.

Yim· written with Dobby (AI Oracle)/Aug 12, 2026

On the night of 11 August 2026 I was reading through the code of a review script I had written myself, and something stopped me for a while.

In our system's rules document there is a line, written on 5 July, that says the model that reviews a change must not be the model that made it. The reasoning is plain enough. The same model carries the same blind spots. What it overlooks while writing, it overlooks again while reviewing, for exactly the same reason.

That rule had been followed for over a month. But when I opened the script that actually launches the reviewer, it turned out the model name was hardcoded, and the script did not know the phrase "maker model" at all. Which means that on any day the model doing the writing happened to be the same one, the rule would be broken with nothing raising a hand, and nobody would know.

It had held up all that time because the person issuing the command remembered, not because anything was holding it. Which means the day we are in a hurry, the day someone else edits the pipeline, or the day it is 2am, the rule quietly disappears. The same day it matters most.

Productize runs Codex CLI and Claude Code side by side on real work every day, one writing and one reviewing. This post covers where the two actually differ based on our own measurements, why "which one is better" pays back less than you would expect, and how to turn a rule that sleeps in a document into code that can say no to you.

Part 1Where Codex and Claude Code actually differ

They differ in vendor and in reading habits, not in "one can do this and the other cannot." Both write code. Both review a diff. Both run headless. The table below comes from using them here, not from someone else's benchmark.

Compared onClaude CodeCodex CLI
VendorAnthropicOpenAI
Role we give itmostly the makermostly the reviewer
Reviews a diffYes, built-in review commandYes, codex review, against a base branch, uncommitted work, or one commit
Headless callclaude -pcodex exec
Default effortset per lanewatch out the flagship ships on a low setting, see Part 4
Expired credentialssays so plainlyfooled us once exited zero with an empty report file
Why two, not oneDifferent vendors means the blind spots do not overlap, and that is the only thing that makes a review mean anything

Notice there is no row for who writes prettier code. That is the row that flips with every release, and it is the row that cannot make the decision for you anyway.

Part 2So which one is better

That question does not have the answer people want, and the day we measured it for real, what came back was more interesting than the answer we wanted.

We had a piece of work written by an Anthropic model, and we sent it through three review rounds. Rounds one and two used a reviewer from the same vendor as the maker. Each round returned several real problems, all of which we fixed. On round three we swapped the reviewer to Codex, on code that had already passed two sets of eyes.

That round found three more problems the first two rounds never saw, and all three were a different shape from anything found before.

The point is not that Codex is better. If we flipped it around and had Codex write while Claude reviewed, we would expect the same result in the other direction. The point is that the two are wrong about different things, and what one model cannot see does not get fixed by asking a stronger version of that same model to look again.

Forced diversity buys you something an upgrade cannot, because a newer model from the same vendor still carries the same blind spots.

There is a caveat worth stating. Adding more models to the review does not automatically make it more careful. The moment they all agree is the moment to be most suspicious. We wrote that up separately in AI red teaming with multiple models.

Part 3Turning a rule in a document into code that refuses

Back to the night of 11 August. What we found was not a wrong rule. The rule was right and written clearly. What we found was that there was nowhere for the rule to stand.

There is one question that catches this, and it works on any rule in any team.

Right now, if someone did the opposite of this rule, what would stop them?

If the answer is "whoever is running it remembers" or "we would catch it in review," the rule is not enforced. It is a nicely worded intention.

Three things that make it actually enforceable

We fixed it by writing a small wrapper script that sits between the instruction "go review this" and the reviewer itself. Three principles, and all three transfer to any other rule.

  1. Whatever the rule depends on must be supplied by the caller, with no default. Our script requires the maker's model name to be passed in. No name, no run. If it can guess, then one day it guesses wrong and still reports a pass, which is worse than having no check at all.
  2. A value hardcoded in the script is a rule that cannot inspect itself. The old script had the reviewer model baked into the source, so it had no way of knowing it was colliding with the maker. Pull it out into something set from outside, then compare.
  3. Normalize the names before comparing. Everyone writes model names differently. Some include the version number, some prefix the vendor. Compare raw strings and the check passes because the text differs, while the actual models are the same one.

But does it actually refuse

This matters more than the code, because a check you have never seen reject something is a check you cannot prove exists. So we deliberately fed it the cases that must be rejected, one at a time, and read the exit code that came back.

What we fed inWhat should happenExit code
Maker and reviewer are the same modelrefuse, never start the review4
Maker and reviewer from different vendorspass, run the review normally0
Maker model not suppliedrefuse, do not guess1
Unrecognized model namerefuse, and say why2

The first row is the valuable one. Not because it passed, but because we told it to reject and it rejected. Before that, if anyone had asked whether the rule was working, the honest answer was "no idea."

Part 4Two things that fooled us during setup

One: exit code zero does not mean it reviewed

On 29 July we ran the reviewer on a Mac against a piece of work. It came back fine. Exit code zero. A report file was written. If we had stopped there we would have said "reviewed, nothing found," and that would have been untrue.

Opening the report showed nothing but authentication errors. The credentials on that machine had been revoked. The tool looped on authorization until it gave up, and still exited zero. The report file was about six hundred bytes, the only clue visible from outside.

Moved to a machine where the credentials still worked, the same piece of work came back with four findings. One was a request sending an empty body that made the server return an error, reproducible on the live system immediately. Trusting that exit code would have shipped it.

Read the artifact it produced, not the absence of complaints. We changed how we read results: open the report and look for the reviewer's actual verdict block. No findings listed does not mean pass. It may mean the review never started.

Two: the strongest model ships with the weakest default

Setting up the review lane, we wanted the best Codex model, so we went looking at which model was which. The model table is embedded in the CLI binary itself, and it said something we did not expect.

The flagship, the one whose own description calls it the most capable, sets its default reasoning effort to low, while the tier below it, described as the balanced model for everyday work, defaults to medium. Which means calling the strongest model plainly gives you less thinking than calling the weaker one.

It is not a mistake. That model's own blurb says it is designed to be capable at lower effort and invites you to turn it up for harder jobs. But for anyone who does not read that line, the consequence is an upgrade that is a downgrade.

There is a second layer folded into this. Pass a misspelled model name and the tool does not complain. It prints the name you typed and carries on. You find out later when something breaks, or worse, you never find out. So the proof that the model you ran is the model you asked for has to come from the provider's own session log, not from the absence of red text.

The rule out of these two is short. Whenever you set a model, set the reasoning effort in the same breath. And the lane that needs the highest quality, the review lane, must never fall through to the account default, because a value you did not specify is a value the provider can change whenever it likes without telling you.

Part 5The verdict, and which one to pick

It depends on where you are. There is no single answer.

Your situationDo this
One subscription, working soloPick whichever fits your workflow better, and do not let it review its own work as the last step. Read the diff yourself.
You already have bothWhichever you are most fluent with writes, the other vendor reviews before merge. Do not swap the roles by mood from day to day.
A team, or automationPut the rule in the script so it refuses when maker and reviewer collide. Memory does not scale past one person.
Tight budget, one place to spendSpend on the review lane, not the writing lane. A slightly cheaper model can write. A reviewer that barely thinks finds nothing.

Three things you can do tomorrow

  1. Take the last thing an AI wrote for you and hand the same diff to an AI from the other vendor. Count how many things it finds that the first pass did not. That number is your answer on whether any of this is worth it for your work.
  2. Open the report file your reviewer produces and actually read it once. Do not trust "finished successfully."
  3. Go check whether your review lane pins both the model and the reasoning effort. Anything you did not specify is something someone else is choosing for you.

The one thing worth remembering

If you take one thing from this, take this. For any rule in a document that says must or must not, ask immediately: right now, if someone did the opposite, what would stop them? If the answer is a person's memory, the rule is not enforced yet.

Codex versus Claude Code is just the most tangible example of that rule. Tomorrow the version numbers change and the comparison tables reshuffle. The question of who signs off on whose work, and whether anything is actually holding that line, stays the same.

If you want the longer version of why the model that wrote the code cannot see its own bugs, we covered it in AI code review with Codex CLI for Claude Code. And if you want more examples of checks that report a pass without ever checking, try when your checks say pass but never ran.

Sources and references
Follow along

Get new posts and free resources first

Leave your email. New posts and the occasional free resource land in your inbox. No spam.

Email only, for updates.

Comments

Join the conversation

Share a thought.

Name is shown publicly. Email stays private and is never shown.

Loading comments…