one write baton · two agents
claudecodex
Give them a coding task. They argue over which of them should take it, the winner does the work, and then the other one hunts for bugs in it — until there are none left.
scroll ↓
what it actually looks like
They talk to each other. You read it.
Every line below is real output from one run on one laptop — the finding, the suggested fix, the timings, the call count. Nothing here was written for this page. A mocked-up transcript would undercut the only thing the tool is selling.
the concurrency model
Exactly one of them can write. Ever.
Two coding agents loose in one working tree is the same bug as two checkouts on one database. So they take turns, and real CLI flags enforce it — not a politely worded prompt that a model can talk itself out of.
the driver
Writable, because editing is the job.
claude --permission-mode acceptEdits codex -s workspace-write
the reviewer
Cannot write. Enforced by the CLI itself.
claude --permission-mode plan
--disallowedTools Edit Write
codex -s read-only
Nobody is asked whether they want the task. "Do you want this?" is a leading question and a model answers yes, which manufactures deadlock and turns the whole thing into expensive theatre over a regex. Each one picks between two named candidates and may name its opponent — and an agent choosing the other one is the strongest signal available.
the loop
Two models left to iterate on each other don't converge.
After the work, the baton keeps alternating — review, fix, review — until the reviewer finds nothing. Most of the engineering is the brakes.
A leg that dies also ends the run, and says which one. A reviewer that crashed, hit a rate limit or has an expired login is never recorded as a clean pass — only a leg that exited 0 with a parseable verdict counts as evidence.
the part that took the longest to get right
The driver gets a memory. The reviewer stays blind.
Every leg is a fresh process, so by round three the driver has no memory of the approach it already tried or why it refused F2. A small docket fixes that — folded into the driver's next prompt, capped at 6,000 characters.
The reviewer never sees it, and that asymmetry is the whole design. A reviewer that can read "the driver says this is fine, because X" starts agreeing with X. Findings drop, the loop ends sooner, every number improves — and independent review is dead while looking exactly like success. So the reviewer forms its findings from the diff alone, and the reconciliation happens locally, in code. Independence costs no extra agent call.
// nothing throws when that breaks, so the test asserts the shape of the code
test('THE REVIEWER STAYS BLIND: review.mjs cannot even see the docket', () => {
assert.ok(!/from\s+'\.\/docket\.mjs'/.test(src));
assert.ok(!/\bdocket\b/.test(src));
});
Threading the docket into a review prompt breaks the suite. So does giving a read-only leg a
write flag, or adding a real git commit. Each one was broken on purpose to check
it fires — a tripwire that can't go off is worse than no test.
measured, not estimated
What it costs, honestly.
Claude tokens before any work starts. claude -p reloads its context every
call and no flag avoids it.
Codex's leg, on a ChatGPT subscription.
Hard cap on agent calls per invocation — the conference plus six fix rounds, and no more.
Tests, including tripwires that were each broken on purpose to prove they fire.
A conference is ~8–12 seconds. After that a review leg took 9–20s and a headless fix round
took ~54s, on one Mac in July 2026. The spread on the review leg is the model, not the
wrapper. --fast exists for when you already know the answer.
install
Node, plus the two CLIs you already have.
git clone https://github.com/hangryclaude/claudecodex cd claudecodex mkdir -p ~/bin ln -sfn "$PWD/bin/claudecodex.mjs" ~/bin/claudecodex ln -sfn "$PWD/bin/claudecodex.mjs" ~/bin/ccx
No build step and no npm install — a fresh clone runs as it stands, and
~/bin only has to be somewhere on your PATH. Needs Node 18.17+, plus
claude and codex each signed in to its own subscription.
Zero runtime dependencies.
ccx "<task>" confer, work, then review and fix until it's clean ccx --fast "<task>" router only. instant, $0, no conference ccx --why "<task>" print the decision and stop. spends nothing ccx --robot "<task>" headless, one json object on stdout ccx --stats per-domain record and router agreement
the limits
What it doesn't do.
- Correctness only. A finding has to name inputs or state that produce a wrong result, a crash or data loss. Style and formatting opinions are dropped unread, so a fix round can never churn working code over a preference.
- It reviews the driver's delta, not your repo. Breakage in a file the driver never touched is outside what the reviewer is shown.
- It doesn't check the task got done. The loop only asks whether the diff has bugs — which is why a diff that shrinks by half is reported as scope collapse instead of scored as a win.
- It doesn't settle disagreements. Once the driver has refused everything still open, the loop stops and hands both sides to you.
- It never commits, branches or opens a PR. The work is left in your tree for you to read.