Claude Code vs Codex: Claude Writes, Codex Reviews

Claude Code vs Codex, for me, is not a close call. I write everything in Claude Code, where Opus 5.5 plans and Sonnet 5.5 writes the code. I use Codex for exactly one job: reviewing that code before it gets committed or merged.

A caveat up front. I only just adopted this workflow, and I’m still testing how well it works. This post is a first look with real numbers and real runs, not a final verdict. I’ll write a separate post on the detailed results once I have them.

The split came out of a two-week measurement of what my AI code reviewers cost. They were a quarter of my total usage on the project. I had expected them to be a minor line item.

The short version:

  • Claude Code builds. Opus 5.5 plans and Sonnet 5.5 writes, both at high effort.
  • Codex reviews. gpt-6-astra at high effort checks my code before every commit and pull request.
  • Why split it. Reviewers were 25% of my usage. The code and PR reviews were about 15% of the total, and they now run on a separate ChatGPT plan. A second model family also has different blind spots.
  • Not proven yet. I don’t know if Codex catches everything my Claude reviewer did. More on that at the end.

One note on dollars. I pay flat monthly plans, $200 for Claude Max and $100 for ChatGPT Pro, so I never see a per-token bill on either side. Every dollar figure in this post is what my tokens would cost at the providers’ published API prices, and I did not pay any of it. It is a yardstick for how much each agent used, not an invoice. The cost section explains what it means for me.

Claude Code vs Codex: who does what in my setup?

Opus 5.5 plans, Sonnet 5.5 writes, and Codex reviews the code. That is the whole split.

Job Tool Model Effort
Plan the change Claude Code Opus 5.5 high
Write the code Claude Code Sonnet 5.5 high
Attack the plan (plan-adversary) Claude Code Opus 5.5 high
Check API docs (docs-librarian) Claude Code Sonnet 5.5 high
Review code before a commit Codex gpt-6-astra high
Review a pull request Codex gpt-6-astra high

If Codex is unavailable, my Claude code-reviewer and pr-reviewer agents, both on Opus, step in.

What I prefer about Claude is the code quality and the split where Opus 5.5 plans and Sonnet 5.5 writes (I broke that split down in Claude Code cost). I also like that my pipeline is built on its subagents, skills and MCP servers, and I just like the Opus and Sonnet families.

Codex earns its seat for a different reason. A reviewer from another model family has different blind spots than the model that wrote the code.

Why does Sonnet 5.5 make Claude Code an easier pick?

Anthropic released Sonnet 5.5 on September 28, the day before I wrote this. I have not measured it yet, so what follows is Anthropic’s word, not mine.

On Anthropic’s Sonnet 5.5 page, it scores 70.6% on Terminal-Bench 4.0. Sonnet 5 scored 10.3% on the same table. The price did not move: $2 per million input tokens, $10 output, and $0.20 for cache reads.

Anthropic also says it runs 30% or more faster and costs up to 30% less per task, because it uses fewer tokens and fewer tool steps. Claude Code defaults Sonnet 5.5 to medium effort. I run high.

The migration docs say effort levels are recalibrated, so a setting from Sonnet 5 does not carry over. For agentic coding they suggest medium for well-specified tasks and high for harder or longer ones.

There is one caveat worth knowing. Simon Willison reported that at max effort it thought for 128,000 tokens and ran out before producing anything, which cost $1.28 for nothing.

My measurement window (September 15 to 29) was mostly Sonnet 5, so the 30% figure is unverified on my own data.

What do the benchmarks say about Claude Code vs Codex?

Short version: in every coding row below, the top score is a Claude model. Astra wins two of the six rows. It also costs 2.5 times more per token than Opus 5.5.

Benchmarks score models, not the tools around them. So this compares the three models I use: Sonnet 5.5, Opus 5.5 and OpenAI’s GPT-6 Astra. The bold number is the highest in each row.

Benchmark What it tests Sonnet 5.5 Opus 5.5 GPT-6 Astra
Terminal-Bench 4.0 Multi-step coding tasks in a terminal 70.6% 66.4% 57.9%
FrontierCode 1.1 (Main) Whether a maintainer would merge the code 46.2% 54.4% 53.3%
CursorBench 4.0 Real tasks from Cursor coding sessions 55.5% 57.8% not reported
GDPval-AA 2.1 (Elo) Professional work like documents, slides and spreadsheets 1844 1846 1542
AutomationBench Business workflows across several apps not listed 40.0% 41.4%
Terminal-Bench-Science 0.1 The science edition of Terminal-Bench not listed 58.7% 64.6%

The first three rows are the coding ones. Sonnet 5.5’s FrontierCode score is at max effort.

Before you trust these numbers, know three things:

  • Most of them are vendor-reported. The Opus 5.5 and Astra columns come from Anthropic’s Opus 5.5 page, which is a competitor’s table. The Sonnet 5.5 column comes from Anthropic’s Sonnet 5.5 page.
  • I checked Astra against OpenAI. OpenAI’s announcement matches on Terminal-Bench 4.0, FrontierCode, AutomationBench and Terminal-Bench-Science. It does not list GDPval-AA, so that number rests on Anthropic’s word alone.
  • Effort settings differ. OpenAI reports each Astra score as the maximum at any effort, and it ran FrontierCode with a Codex-style developer message. I read gaps of a point or two as ties. Sonnet 5.5 and Opus 5.5 are two Elo points apart on GDPval-AA.

The “what it tests” column comes from each benchmark’s own page: FrontierCode, CursorBench, GDPval-AA and AutomationBench. Anthropic calls Terminal-Bench 4.0 an agentic coding evaluation.

What does each model cost?

Price is the other axis. These are API list prices per million tokens.

Model Input Cache read Output Compared with Opus 5.5
Sonnet 5.5 $2 $0.20 $10 Half on input and output, same on cache reads
Opus 5.5 $4 $0.20 $20 Baseline
GPT-6 Astra $10 $1 $50 2.5 times on input and output, 5 times on cache reads

Sources: Anthropic’s two pages above, OpenAI’s Astra model page and OpenAI’s announcement, which both list $10 in and $50 out.

What do independent numbers say?

Artificial Analysis runs its own Intelligence Index (higher is better) and reports what each model costs per task. Its Astra write-up and its Sonnet 5.5 page give these numbers.

Model (effort) Intelligence Index Cost per task
GPT-6 Astra (max) 53 $3.26
Sonnet 5.5 (max) 56 $7.60
Sonnet 5.5 (high) 47 $1.08

Those come from two separate pages, so I would not lean on the exact gaps. Artificial Analysis also says Astra used about 27,000 output tokens per task at max effort, roughly a third of Claude Fable 5.1.

The honest read is that these models are close enough that a benchmark can’t tell me which one catches bugs in my code. Only running each on my own past bugs will, and I haven’t done that yet.

What did my AI code reviewers actually cost at list price?

Claude Code saves every session and every subagent run as a log file, and each response records its token usage. I parsed all of them from September 15 to September 29, 2026: 754 subagent runs and 167 main working sessions. I later cleaned out part of those session logs, so I can’t re-run that window. The numbers here are from my September 29 run.

I removed duplicate usage records, since streaming writes the same usage more than once. I labeled each run by its agent type, then priced the tokens at list price.

Two terms matter. A cache read is when a long conversation gets re-sent and the provider recognizes the unchanged start, so it charges a fraction of the input price. A cache write is the pricier first time a chunk of context is stored so it can be re-read cheaply.

Cache writes cost 1.25 times the input price for the five-minute cache and 2 times for the one-hour cache. For older models where I had no published cache-read price, I assumed a tenth of the input price.

On models: the reviewers ran on Opus 5 until Opus 5.5 arrived on September 22, a week into the window. The logs show most reviewer runs on Opus 5 and the rest on Opus 5.5. The docs librarian ran on Sonnet, mostly Sonnet 5.

Agent Runs List-price estimate Share List price per run Median model calls per run
Main working sessions 167 $2,032 63% $12.17 7
code-reviewer 144 $500 15% $3.47 38
Explore (search helper) 103 $158 5% $1.54 18
plan-adversary 57 $151 5% $2.65 30
An older reviewer I have since deleted 29 $118 4% $4.08 36
General-purpose helpers 307 $115 4% $0.37 25
docs-librarian 33 $37 1% $1.13 19
pr-reviewer 2 $4 0% $2.21 54
All agents, including small ones not shown 921 about $3,238 100%

These are list-price estimates, not what I paid. Below I explain what they mean for me.

Estimated list-price cost by agent, Sept 15 to 29, 2026 Horizontal bars. Main working sessions cost $2,032, the code reviewer $500, Explore $158, the plan adversary $151, a since-deleted reviewer $118, general helpers $115, the docs librarian $37 and the PR reviewer $4. Main working sessions $2,032 code-reviewer $500 Explore (search helper) $158 plan-adversary $151 Since-deleted reviewer $118 General helpers $115 docs-librarian $37 pr-reviewer $4
Estimated list-price cost by agent over two weeks. Bar lengths are drawn from the dollar figures in the table above.

All the review agents together came to about $811, or 25% of the total. I had guessed reviewers were a small line item. I was off by roughly an order of magnitude.

The bigger pot is the main working sessions at 63%. Seventy percent of that was cache reads, from very long sessions that peaked at 758,000 tokens of context.

By model, most of that main-session cost was Sonnet 5 at $1,406, with Opus 5.5 at $311 and Opus 5 at $190. Switching the main model barely helps, because Sonnet 5.5 and Opus 5.5 both charge $0.20 per million for cache reads. The lever there is shorter sessions, which is a separate project. My Claude Code cost post covers the /clear habit.

What does the $500 mean if I pay a flat price?

I pay a flat monthly price, so the $500 is not money I spent. It is a yardstick. Three different things get called “cost,” and they are not the same:

What What it is Do I pay it?
List-price estimate The tokens I used, multiplied by the provider’s published API price per token No
Plan price $200 a month for Claude Max, $100 a month for ChatGPT Pro Yes, a flat amount
Usage limit The five-hour window and the weekly cap a plan enforces Not money. It is what I can run out of

Where the $500 came from: my code-reviewer runs logged 567 million cache-read tokens, 20 million cache-write tokens and 4.9 million output tokens. I priced each token type at its model’s list price and added it up. The script below does the same for any set of logs.

Here is how the limits work, per Anthropic. On a plan, usage resets on a five-hour session window, and there is also a weekly limit across all models. Max 20x, the $200 plan, gives 20 times Pro’s per-session allowance.

Anthropic does not publish exact token allowances, and the two pages I read don’t say whether the limit is counted in tokens, messages or dollars. So I can’t turn $500 into a percentage of my weekly limit. I wrote more about how the limits work in how to get the most out of a $20 Claude plan.

What it means for me: $500 is about 15% of the roughly $3,238 my agents used at list price over those two weeks. If my weekly limit tracks list price, moving the code and PR reviews to Codex frees about 15% of my Claude usage. That is a projection, because I don’t know that the limit tracks list price.

My main goal is to make sure I don’t hit my weekly limit. I haven’t hit it, and I’m being careful. My five-hour limit is fine most of the time.

Here is a real reading. When I ran /usage on September 29, my weekly limit for all models showed 53% used, resetting October 2 at 10am Pacific. The current five-hour session showed 4% used. The screen says its numbers are approximate and cover only this machine, not other devices or claude.ai.

The same screen lists what contributed to my limits in the last 24 hours. 99% of my usage came from subagent-heavy sessions, and 63% of it was at more than 150,000 tokens of context. By agent, general-purpose was 18%, Explore 4%, code-reviewer 2%, docs-librarian 1% and plan-adversary 1%. Those are independent characteristics, not a breakdown that adds up to 100%, and it is a one-day window, so it does not compare directly with my two-week list-price figures. It does suggest the Claude reviewers were a small part of my limits over those 24 hours.

Can you run this on your own logs?

Yes, in two steps. This is the script I used to check my numbers, cleaned up. It uses only the Python standard library. It works on any date range with logs still on disk. Another option is npx ccusage@latest daily, which reads the same logs and now reads Codex’s too. Some of my own September 15 to 29 logs are gone, so I can’t re-run my exact window.

  1. Save the script below as agent_cost.py.
  2. Run python3 agent_cost.py ~/.claude/projects/<your-project-folder> 2026-09-15 2026-09-29.

It prints one line per agent type. This is the top of what it printed for my project:

main                           169 runs  $   2,047
code-reviewer                  141 runs  $     494
Explore                        103 runs  $     158
plan-adversary                  57 runs  $     147
...
total                          900 runs  $   3,199

main is your normal sessions, and the other names are subagent types. Not sure which folder is yours? Run ls ~/.claude/projects. Each folder is named after a project path, with slashes, dots and spaces turned into dashes.

Show the script (61 lines)
import json, sys, collections
from pathlib import Path

# List prices in $ per million tokens: input, output, cache read, 5-minute cache write, 1-hour cache write.
# Source: platform.claude.com/docs/en/about-claude/pricing, checked September 29, 2026.
PRICES = {
    "claude-opus-5-5": (4, 20, 0.20, 5, 8),
    "claude-opus-5": (5, 25, 0.50, 6.25, 10),
    "claude-opus-4-8": (5, 25, 0.50, 6.25, 10),
    "claude-opus-4-7": (5, 25, 0.50, 6.25, 10),
    "claude-sonnet-5-5": (2, 10, 0.20, 2.5, 4),
    "claude-sonnet-5": (2, 10, 0.20, 2.5, 4),
    "claude-sonnet-4-6": (3, 15, 0.30, 3.75, 6),
    "claude-haiku-4-5-20251001": (1, 5, 0.10, 1.25, 2),
    "claude-fable-5-1": (10, 50, 0.25, 12.5, 20),
}

def run_cost(path, skipped):
    """Return (start time, estimated cost) for one session or subagent log."""
    usage, start = {}, None
    for line in open(path):
        try:
            rec = json.loads(line)
        except ValueError:
            continue
        msg = rec.get("message") or {}
        if msg.get("role") == "assistant" and "usage" in msg:
            start = start or rec.get("timestamp", "")
            usage[msg.get("id")] = (msg.get("model"), msg["usage"])  # streaming repeats a message, the last copy wins
    cost = 0.0
    for model, u in usage.values():
        if model not in PRICES:
            skipped[model] += 1
            continue
        inp, out, read, w5, w1h = PRICES[model]
        writes = u.get("cache_creation") or {"ephemeral_5m_input_tokens": u.get("cache_creation_input_tokens", 0)}
        cost += (u.get("input_tokens", 0) * inp + u.get("output_tokens", 0) * out
                 + u.get("cache_read_input_tokens", 0) * read
                 + writes.get("ephemeral_5m_input_tokens", 0) * w5
                 + writes.get("ephemeral_1h_input_tokens", 0) * w1h) / 1e6
    return start, cost

project, first_day, last_day = Path(sys.argv[1]).expanduser(), sys.argv[2], sys.argv[3]
logs = [("main", p) for p in project.glob("*.jsonl")]
for meta in project.glob("*/subagents/agent-*.meta.json"):
    logs.append((json.loads(meta.read_text()).get("agentType", "unknown"), meta.with_suffix("").with_suffix(".jsonl")))

totals, skipped = collections.defaultdict(lambda: [0, 0.0]), collections.Counter()
for agent, path in logs:
    if not path.exists():
        continue
    start, cost = run_cost(path, skipped)
    if start and first_day <= start[:10] <= last_day:
        totals[agent][0] += 1
        totals[agent][1] += cost

for agent, (runs, cost) in sorted(totals.items(), key=lambda kv: -kv[1][1]):
    print(f"{agent:28} {runs:5} runs  ${cost:8,.0f}")
print(f"{'total':28} {sum(r for r, _ in totals.values()):5} runs  ${sum(c for _, c in totals.values()):8,.0f}")
if skipped:
    print("skipped (no price listed):", dict(skipped))

Four caveats:

  • The log format is internal to Claude Code, not a documented API, so a future version can break this.
  • Prices are list prices from Anthropic’s pricing page, checked on September 29, 2026. A model missing from the PRICES table is skipped and reported at the end.
  • A run counts if its first message falls inside your dates. When I ran it on September 29, before I cleaned out part of my logs, it totaled $3,199 against the $3,238 in my table, about 1% lower. A few small rows sit a few dollars apart. It also leaves out my two pr-reviewer runs, which started on September 13, and it puts general helpers at $131 against $115 in the table.
  • On a subscription plan nothing here is a bill, so read the output as usage.

Why did one reviewer reach $500 at list price?

The code reviewer used about 567 million cache-read tokens, 20 million cache-write tokens and 4.9 million output tokens across 144 runs.

That splits into cache reads at 51% of its cost ($255), cache writes at 25% ($123), and output at 24% ($121). Fresh, uncached input was close to zero.

My first theory was that the reviewer wanders the codebase and re-reads files. The data says it mostly doesn’t.

  • A run reads each distinct file about 1.24 times (median). That is close to once.
  • Test output is small. Across 521 test runs the median was 1,324 characters and the largest was about 10,000. Tests made up 2.7% of everything the reviewer read.
  • Of what it reads, 46% is whole files through the Read tool (about 9,200 characters each), 15% is git output, 13% is files read through shell commands, 11% is grep results and 5% is web docs.

So the exploring is fine. What drives the bill is how often the reviewer gets launched.

The 144 runs came from 18 sessions. The median was 5 code-reviewer runs per session, and the maximum was 30.

Of those runs, 110 were independent reviews or re-reviews of fix passes, at about $3.59 each ($395 total). The run descriptions include “Re-review C2 fix pass”, “Review fixes from second pass” and “Final review of earnings fixes”. The other 30 were the multi-angle sweep (efficiency, reuse, conventions and so on) at about $3.26 each ($98).

Every re-review starts from zero. It re-reads the whole diff and pays a new cache write, even when the fix touched ten lines. Thirty reviews in one session is not a review process. It is a loop with a receipt.

Which token-saving ideas did I skip?

Before building anything I looked at a proposal to cut reviewer cost with a “review pack” and an evidence store. I weighed it against five other ideas, using my own numbers.

Idea Verdict
Evidence store and “review pack” High effort, low measured upside, real quality risk
rtk (compresses command output) No
Caveman-style terse prompting No
Code graph Optional, small
Scoped re-reviews Aimed at the real driver, not built yet
Move the reviewers to another vendor’s model Built. This is the rest of the post

The evidence pack precomputes changed symbols, callers and tests, then lets the reviewer fetch exact snippets. It is a reasonable idea. But reviewers already read each file about once, and test output is small, so there is little to squeeze inside a run.

The bigger risk is quality. A reviewer that starts from a precomputed list tends to look where the list points. The bugs that hurt this project are often outside any list, like a missing migration order, an env var, a queue name, or a test fake that accepts what the real database client rejects.

Most of the server is plain JavaScript too, so a TypeScript-based dependency analysis misses links like route strings and dynamically named queues.

rtk is a proxy that filters shell output before the model sees it. It trims git diff, truncates long grep lines and collapses passing tests to a count. Its README says it cuts up to 90% of the bash output your agent reads, and adds that this “is not the same as cutting your bill by 90%.”

For a reviewer, that is the material it must see in full. And it never touches the file-reading tool, which is 46% of what my reviewer reads.

Caveman has a skill that makes the agent answer in terse fragments. Its README reports 8.5% fewer output tokens on 86 real coding tasks in a JetBrains benchmark, with quality flat. Its newer proxy claims 33.2% fewer input tokens in the project’s own six-case benchmark, and one case got 9.9% worse.

Reviewer reports are a small share of output, and terse reports are harder to read. The proxy compresses the same diffs and test output the reviewer needs whole. So that is a no from me.

A code graph, in its lightest form, is the editor-style “find references” tool. It gives exact answers without dropping anything and might trim some of my roughly 2,100 grep calls. A pre-built graph database goes stale and has the same anchoring problem as the evidence pack.

Scoped re-reviews are the fix that matches the data. Keep the first review of a change fully fresh and independent. Then review later passes as fixes: the previous findings plus the fix diff. I have not built it.

Why is Codex the reviewer if it costs more per token?

It is a fair question, since the table above shows Astra costing more than Opus 5.5 on every token. At list prices, moving the same review from Opus 5.5 to Astra would raise the bill, not cut it.

But I don’t pay per token on either side. My Claude usage draws down one limit, and my ChatGPT plan is a separate bucket. I wrote about stretching the Claude side in how to get the most out of a $20 Claude plan.

The gates I moved are the code reviewer, the sweep and the PR reviewer. Together that was about $500 of list-price usage over two weeks, roughly 15% of all usage on the project, if Codex replaces them one for one. That load leaves my Claude limit and lands on the ChatGPT plan.

The plan-adversary ($151, Opus) and docs-librarian ($37, Sonnet) stay on Claude. The docs librarian relies on Claude-side documentation connectors, and the plan adversary reviews written plans rather than diffs.

The limit is the catch. OpenAI’s pricing page lists Pro at $100 a month with 25 to 225 Astra messages per five hours, plus weekly caps. It also says code review usage is tracked separately only when Codex reviews through GitHub, and mine run locally, so they count toward the general limit.

At roughly ten reviews a day, I could hit that limit mid-session. That is what the fallback below is for.

One more trade-off, stated plainly. Using Codex means sending my code to a second vendor. That is a privacy trade-off, and it’s yours to weigh for your own code.

How do you set up Codex as a review gate?

You end up with one command that runs a Codex review of your uncommitted changes and prints the report, plus how much of your usage limit it used. Here is how mine is built, step by step. The file names and flags below come from my real setup.

Prefer not to write a script? OpenAI ships an official plugin, codex-plugin-cc, with commands like /codex:review and /codex:adversarial-review. I wrote my own small wrapper instead.

Step 1: Add a Codex skill

A skill is a folder with a SKILL.md file holding a name, a description and instructions, per OpenAI’s skills docs. Codex looks for them in .agents/skills/. I have two:

.agents/skills/
  code-reviewer/
    SKILL.md
    agents/openai.yaml
  pr-reviewer/
    SKILL.md
    agents/openai.yaml

This is the top of my code-reviewer/SKILL.md, trimmed:

---
name: code-reviewer
description: "Independent pre-commit code review of Tradion changes ... Use only when explicitly asked to run $code-reviewer. ... Read-only: reports findings, never edits."
---

The instructions below it tell Codex a few things:

  • You are the second opinion. The skill says the change was written by Claude, so Codex is a different model from a different vendor and should not assume Claude’s shortcuts are right.
  • Read-only. Never edit, create, delete, stage, commit, stash or reset anything. Running tests is fine.
  • No helper agents. Do the review yourself.
  • The last message is the whole report. Only the final message gets captured.
  • Include new files. Scope covers brand-new untracked files, which a plain git diff silently omits.

Step 2: Turn off automatic triggering

I don’t want an everyday Codex session to start a review on its own. Each skill has an agents/openai.yaml file that switches that off:

interface:
  display_name: "Tradion code reviewer"
  short_description: "Independent pre-commit review gate for Tradion changes"
policy:
  allow_implicit_invocation: false

Naming the skill ($code-reviewer) still loads it, even though it no longer shows in the skills list.

Step 3: Pin the model and effort

The docs don’t say a skill can choose its own model or reasoning effort, so the script passes them on the command line every time. These are the two Codex commands inside it, trimmed:

# code and pr modes
codex exec -m gpt-6-astra -c 'model_reasoning_effort="high"' -s workspace-write -o "$report" "$prompt"

# sweep mode
codex review --uncommitted -c 'model="gpt-6-astra"' -c 'model_reasoning_effort="high"' -c 'sandbox_mode="read-only"'

I also set the same two values as my defaults in ~/.codex/config.toml.

Step 4: Wrap it in a script

The script, codex-review.sh, has three modes:

Command What it runs
codex-review.sh code My $code-reviewer skill on the uncommitted work, including new untracked files
codex-review.sh sweep Codex’s built-in codex review --uncommitted, in a read-only sandbox
codex-review.sh pr 123 My $pr-reviewer skill on pull request 123, with the PR data fetched by the script

It also checks its own work. It snapshots the repo before and after each review, and any difference fails the run. Each run writes to a fresh temp file, so an old report can never pass for a new one. The exit code tells the caller what happened:

Exit code Meaning What I do
0 Review finished Read the report
2 Codex failed, for example an error or a rate limit Run the Claude reviewers instead
3 Codex returned an empty report Run the Claude reviewers instead
4 The working tree changed during the review Stop and look
5 The script could not fetch the PR data with gh Run the Claude PR reviewer instead

An exit code of 1 just means the command was typed wrong.

Step 5: Tell Claude to run it

A short section in my project instructions makes the gate automatic. This is adapted from mine:

Before `git commit`: run `.claude/scripts/codex-review.sh code`, then `.claude/scripts/codex-review.sh sweep`
Before `gh pr create`: run `.claude/scripts/codex-review.sh pr <number>`
Run each as one background command and make no edits until it finishes
If the script exits 2, 3 or 5, run the Claude reviewers instead and tell me
If it exits 4, stop and tell me

Step 6: Watch your usage

Codex saves a log of every session, and each log records the account’s usage limit. So the script prints usage after every review:

Codex tokens this review: input 38,173 (cached 24,448), output 311 (reasoning 13)
Codex usage: 15% of weekly limit used, resets Sat Oct 3 7:34 PM

It warns at 80% and when the limit is reached. One wrinkle is that the review sweep does its work in a child session, so the numbers live in a second log. The script finds both and adds them up.

What has Codex used so far?

This comes from the Codex session logs for September 29, the day I turned the gate on. A session here counts both my review runs and the child sessions Codex starts for a review.

Measure September 29
Codex sessions 30
Model and effort 29 on gpt-6-astra at high, 1 on gpt-6-luna
Input tokens 17.3 million, of which 15.4 million (89%) came from cache
Output tokens 65,600, of which 15,900 were reasoning
Largest single run The final review of one pull request: about 2.6 million input and 6,500 output tokens
Weekly limit 28% used, resets Saturday, October 3 at 7:34 PM
Same day at API list price About $38, from ccusage (17.6 million tokens, checked later in the day)

That $38 is a list-price estimate like my Claude figures, not what I paid, and a flat plan has no per-review price. The weekly limit is the number I’m watching. The results section below covers my first three runs. The 30 sessions above include the reviews I ran on real work afterward, and I haven’t written those up yet.

What did the plan adversary catch before I built it?

Before writing anything, I ran the plan through plan-adversary. It is the agent from my automated code review pipeline, and its job is to refuse to believe the plan. (I’ve since measured it with LLM evals.) It found six real problems:

  • A file the plan assumed was identical to another had changed. Copying one over the other would have deleted a new rule.
  • The “did the reviewer change any files?” check had a hole. A plain git diff and git status can’t see the contents of new untracked files or gitignored ones. The final check hashes HEAD, the stash list, the full status, the binary diff, every untracked file, and key config and instruction files, before and after each review.
  • A reused output file could make a failed review look like a pass. It would leave the last run’s report in place. Each run now writes to a fresh temp file, and a Codex error or empty report stops the script with a distinct exit code.
  • The new instructions could make Codex call Codex. The file Codex reads also held the “run the Codex reviewer” gate. I fixed it with an explicit “Claude Code only” line, plus each skill saying to ignore that section.
  • Network access for the PR reviewer was risky. The sandbox has no network by default. Turning it on would let test runs reach real services, and an enabled GitHub plugin could post comments. Now the script fetches the pull-request data itself and hands Codex only file paths.
  • The sweep’s sandbox wasn’t pinned. It now runs read-only.

What did the first Codex reviews find?

I have three real runs and one failure test. That is a sanity check, not a benchmark.

Test Result
Code review of uncommitted changes Clean. No blocking issues in a .gitignore change. Model, effort and scope reported correctly.
Review sweep (codex review) Clean. Confirmed gpt-6-astra, effort high, read-only sandbox.
Review of an open pull request Request changes, two blockers, both reproduced by the reviewer under UTC.
Fake model name (failure path) Script stopped with exit code 2 and no report.
Working tree changed during any review Never.

The pull-request review found two real bugs:

  1. A retry could bill twice. If a database write failed silently and a follow-up fetch then failed, the endpoint told the client to retry. The reviewer reproduced one signal, two paid model calls and two credits consumed.
  2. A billing cutoff timestamp excluded analyses created around deployment. That produced a non-retryable 503 for a user with no credits.

A footnote, to be fair to my own process. Both bugs were in code that a later local commit had already deleted, but that commit had not been pushed, so the pull request on GitHub still contained them. The reviewer did its job on what it was given.

Two limits showed up. Codex ran the frontend tests fine, 814 passed and 1 skipped. But the server test suite hung inside the no-network sandbox and never finished, most likely because something waits on Redis. The reviewer said so plainly, so for now Codex reviews can’t fully verify server tests.

What do I still not know about this setup?

  • Quality is unproven. The test I want is to run Codex on three to five past changes where the Claude reviewer caught a real bug, and see whether it catches the same ones. I haven’t done it. The one run that found bugs is my only evidence of Codex catching real ones.
  • Savings are projected, not measured. The $500 is list-price usage of those gates on Claude, not money saved. I haven’t compared it against actual Codex usage yet. The weekly percentage the script prints will tell me over the next two weeks.
  • Usage limits could bite. At roughly ten reviews a day, I could hit the Codex limit mid-session. The weekly limit read 28% used when I checked on September 29, and it resets October 3. The fallback is for that.
  • I didn’t judge the Claude reviewers’ findings either. The data shows what runs cost, not whether every finding was valid. That needs a human labeling pass.
  • The Sonnet 5.5 savings are Anthropic’s claim. My window was mostly Sonnet 5.

Next up: that head-to-head test on past bugs, then scoped re-reviews for second and later passes, then the long main sessions, which are the biggest pot at 63% of spend. In two weeks I’ll re-measure and publish the before and after.

What would I take from this?

  1. Measure before you optimize. My guess about where the money went was off by roughly an order of magnitude.
  2. Read cost by behavior, not just by agent. Here the driver was how often a reviewer runs, not how it explores.
  3. Be careful with savings that limit what a reviewer can see. A cheap-looking one, like output compression, can quietly remove the evidence the reviewer needs.
  4. A second model family is a quality move and a limits move at once. It is not a per-token saving, and you still have to verify it.
  5. Put an adversary on the plan before you build. It found six issues, several of which would have made the reviewers silently pass or fail.

I pick Claude Code to write and Codex to grade. Which model reviews the code in your setup, and is it the same one that wrote it?