Claude Code and Codex review each other's work.
See the codeClaude Code and Codex review each other's work. Each runs as a live session in its own terminal, and they talk through a shared directory on disk.
terminal A: claude terminal B: codex ("be my reviewer")
finish task
pair send request ──▶ ~/.pair/<repo>-<hash>/claude-to-codex/<thread>/001-request.md
pair wait ⏳ pair wait ◀── picks it up
002-review.md ◀── pair send review --verdict changes
verify findings, fix
pair send response ──▶ 003-response.md
pair wait ⏳ pair wait ◀── re-checks fixes
004-review.md ◀── pair send review --verdict approve
done ✓
Roles are symmetric: Codex can ask Claude for a review the same way.
npm install -g claude-codex-pair
Requires Node 22 or later. This installs the pair command.
To install from source, clone the repo, then run npm install && npm link inside it.
If you installed from source before the package was renamed to claude-codex-pair, run
npm uninstall -g cc-pair first. Otherwise the install fails with EEXIST on bin/pair.
cd your-repo
pair init
init writes a Claude Code skill (.claude/skills/pair/SKILL.md) and a section in AGENTS.md
for Codex. Both explain the protocol to the agent.
Claude Code 2.1.277 and later can also read AGENTS.md. The pair section there starts by telling
any agent other than Codex to ignore it, so Claude keeps its own role. If you ran pair init with
an earlier version of this package, run it again to refresh both files.
Both agents' sandboxes must be able to write to ~/.pair, or $PAIR_HOME if set. pair init
prints the configuration snippets with your actual path; add them to the corresponding configs.
For the default directory, they look like this:
# ~/.codex/config.toml
[sandbox_workspace_write]
writable_roots = ["/Users/you/.pair"]
// ~/.claude/settings.json
"sandbox": { "filesystem": { "allowWrite": ["~/.pair"] } }
After setup, start Claude Code and Codex in separate terminals in the same worktree of this repo. Each worktree has its own channel, so an agent started in another checkout won't see the messages (see Worktrees). Restart any sessions that were already open so they load the new instructions and sandbox settings.
pair wait.The channel comes from the worktree root, so each git worktree gets its own. You can run one pair per worktree in parallel without them seeing each other's messages.
git worktree add ../your-repo-feature -b feature/x
cd ../your-repo-feature
pair init # needed unless AGENTS.md and .claude/skills/pair/ are committed on this branch
pair status # worktree: /Users/you/your-repo-feature
Then start Claude Code and Codex in ../your-repo-feature, not in the main checkout. If one agent
never receives the other's messages, ask each agent to run pair status and compare the channel:
lines. Pair needs no extra sandbox config, because every channel lives under ~/.pair (or $PAIR_HOME).
git worktree remove leaves the worktree's channel in ~/.pair. To delete it too, run
pair status in the worktree first to get its channel: path, then remove that directory.
The agents run send and wait themselves. You'll mostly use init, status, history and clean.
pair send <request|review|response> --as <claude|codex> [--verdict approve|changes] <file|->
pair wait --as <claude|codex> [--timeout seconds] # prints "no message … yet" on timeout: run again
pair status
pair history [thread-id] # list finished threads (latest first), or print one (any unique part of its id)
pair clean --keep N # delete all but the N newest finished threads
pair init
pair status shows the channel, worktree root, installed package version, and each lane's turn.
It also checks the generated instructions on disk:
channel: /Users/you/.pair/your-repo-12345678
worktree: /Users/you/your-repo
version: claude-codex-pair 0.1.0
claude-to-codex: idle
codex-to-claude: idle
instructions on disk (does not verify what running agents loaded):
AGENTS.md (pair section): current
.claude/skills/pair/SKILL.md: current
Instruction states are current, stale, missing, or unreadable. The check compares only
the marked pair section in AGENTS.md, so your other instructions don't affect it. Status
doesn't change files. Run pair init to refresh missing or stale instructions, then reload
agent sessions; fix access to unreadable files first. Current files on disk don't guarantee
that a running agent has loaded them.
If a channel read or write fails with EACCES or EPERM, the command names the path and prints
sandbox configuration snippets using your actual channel directory. Check ordinary filesystem
permissions as well as sandbox settings. Automatic archive cleanup failures remain warnings,
so a cleanup problem doesn't prevent delivering a review or starting the next thread.
| Env var | Default | Meaning |
|---|---|---|
PAIR_HOME | ~/.pair | Root directory for channels |
PAIR_AGENT | (none) | Default for --as |
PAIR_MAX_ROUNDS | 3 | Number of review rounds before escalation |
PAIR_KEEP | 100 | Finished threads to keep, by finish time. Older ones are deleted whenever a thread finishes. all keeps everything, 0 keeps none |
These are messages from a real run, shortened. The bug in round 1 was planted on purpose.
== pair: review from codex · claude-to-codex · round 1 · verdict changes ==
### F1 [medium] src/paginate.js:8: Partial last pages are omitted from the page count
`totalPages(5, 2)` returns 2 ... Use `Math.ceil(count / pageSize)`.
### F2 [medium] src/paginate.js:2: Invalid pagination inputs produce unrelated items
`paginate([1, 2, 3, 4, 5], 1, -2)` returns `[1, 2, 3]` ...
== pair: review from codex · claude-to-codex · round 2 · verdict approve ==
F1 and F2 are fixed. I re-read src/paginate.js and ran 41 assertions ... All passed.
See DESIGN.md for the protocol, storage layout, and known limits.
Claude Code and Codex review each other's work.
See the codeClaude Code and Codex review each other's work. Each runs as a live session in its own terminal, and they talk through a shared directory on disk.
terminal A: claude terminal B: codex ("be my reviewer")
finish task
pair send request ──▶ ~/.pair/<repo>-<hash>/claude-to-codex/<thread>/001-request.md
pair wait ⏳ pair wait ◀── picks it up
002-review.md ◀── pair send review --verdict changes
verify findings, fix
pair send response ──▶ 003-response.md
pair wait ⏳ pair wait ◀── re-checks fixes
004-review.md ◀── pair send review --verdict approve
done ✓
Roles are symmetric: Codex can ask Claude for a review the same way.
npm install -g claude-codex-pair
Requires Node 22 or later. This installs the pair command.
To install from source, clone the repo, then run npm install && npm link inside it.
If you installed from source before the package was renamed to claude-codex-pair, run
npm uninstall -g cc-pair first. Otherwise the install fails with EEXIST on bin/pair.
cd your-repo
pair init
init writes a Claude Code skill (.claude/skills/pair/SKILL.md) and a section in AGENTS.md
for Codex. Both explain the protocol to the agent.
Claude Code 2.1.277 and later can also read AGENTS.md. The pair section there starts by telling
any agent other than Codex to ignore it, so Claude keeps its own role. If you ran pair init with
an earlier version of this package, run it again to refresh both files.
Both agents' sandboxes must be able to write to ~/.pair, or $PAIR_HOME if set. pair init
prints the configuration snippets with your actual path; add them to the corresponding configs.
For the default directory, they look like this:
# ~/.codex/config.toml
[sandbox_workspace_write]
writable_roots = ["/Users/you/.pair"]
// ~/.claude/settings.json
"sandbox": { "filesystem": { "allowWrite": ["~/.pair"] } }
After setup, start Claude Code and Codex in separate terminals in the same worktree of this repo. Each worktree has its own channel, so an agent started in another checkout won't see the messages (see Worktrees). Restart any sessions that were already open so they load the new instructions and sandbox settings.
pair wait.The channel comes from the worktree root, so each git worktree gets its own. You can run one pair per worktree in parallel without them seeing each other's messages.
git worktree add ../your-repo-feature -b feature/x
cd ../your-repo-feature
pair init # needed unless AGENTS.md and .claude/skills/pair/ are committed on this branch
pair status # worktree: /Users/you/your-repo-feature
Then start Claude Code and Codex in ../your-repo-feature, not in the main checkout. If one agent
never receives the other's messages, ask each agent to run pair status and compare the channel:
lines. Pair needs no extra sandbox config, because every channel lives under ~/.pair (or $PAIR_HOME).
git worktree remove leaves the worktree's channel in ~/.pair. To delete it too, run
pair status in the worktree first to get its channel: path, then remove that directory.
The agents run send and wait themselves. You'll mostly use init, status, history and clean.
pair send <request|review|response> --as <claude|codex> [--verdict approve|changes] <file|->
pair wait --as <claude|codex> [--timeout seconds] # prints "no message … yet" on timeout: run again
pair status
pair history [thread-id] # list finished threads (latest first), or print one (any unique part of its id)
pair clean --keep N # delete all but the N newest finished threads
pair init
pair status shows the channel, worktree root, installed package version, and each lane's turn.
It also checks the generated instructions on disk:
channel: /Users/you/.pair/your-repo-12345678
worktree: /Users/you/your-repo
version: claude-codex-pair 0.1.0
claude-to-codex: idle
codex-to-claude: idle
instructions on disk (does not verify what running agents loaded):
AGENTS.md (pair section): current
.claude/skills/pair/SKILL.md: current
Instruction states are current, stale, missing, or unreadable. The check compares only
the marked pair section in AGENTS.md, so your other instructions don't affect it. Status
doesn't change files. Run pair init to refresh missing or stale instructions, then reload
agent sessions; fix access to unreadable files first. Current files on disk don't guarantee
that a running agent has loaded them.
If a channel read or write fails with EACCES or EPERM, the command names the path and prints
sandbox configuration snippets using your actual channel directory. Check ordinary filesystem
permissions as well as sandbox settings. Automatic archive cleanup failures remain warnings,
so a cleanup problem doesn't prevent delivering a review or starting the next thread.
| Env var | Default | Meaning |
|---|---|---|
PAIR_HOME | ~/.pair | Root directory for channels |
PAIR_AGENT | (none) | Default for --as |
PAIR_MAX_ROUNDS | 3 | Number of review rounds before escalation |
PAIR_KEEP | 100 | Finished threads to keep, by finish time. Older ones are deleted whenever a thread finishes. all keeps everything, 0 keeps none |
These are messages from a real run, shortened. The bug in round 1 was planted on purpose.
== pair: review from codex · claude-to-codex · round 1 · verdict changes ==
### F1 [medium] src/paginate.js:8: Partial last pages are omitted from the page count
`totalPages(5, 2)` returns 2 ... Use `Math.ceil(count / pageSize)`.
### F2 [medium] src/paginate.js:2: Invalid pagination inputs produce unrelated items
`paginate([1, 2, 3, 4, 5], 1, -2)` returns `[1, 2, 3]` ...
== pair: review from codex · claude-to-codex · round 2 · verdict approve ==
F1 and F2 are fixed. I re-read src/paginate.js and ran 41 assertions ... All passed.
See DESIGN.md for the protocol, storage layout, and known limits.