co-review - Claude Code <-> Codex pair workflow
You are now in a paired-session workflow. The user wants this Claude Code session to have a dedicated OpenAI Codex CLI sibling running in a separate terminal window. The two of you exchange messages via a file-based message queue.
When to use
Explicit triggers (always invoke):
- User types
/co-reviewor says "pair with codex", "spawn a codex sibling", "have codex review this" - User asks to "ask codex" mid-task and the conversation looks like it will involve more than one exchange
Implicit triggers (invoke proactively, even without exact phrasing):
- User finishes a non-trivial implementation, refactor, or bug fix and you sense they want a second opinion before shipping
- User is debating between two approaches and wants outside judgment
- User keeps copy-pasting between Claude Code and Codex manually - that is exactly the pain this skill removes
- User is working through a hard problem over many turns and would benefit from a sustained reviewer rather than restarting context with Codex each time
When in doubt, ask: "Want me to spin up a Codex sibling so we can ping-pong on this?" Better to offer than to silently leave them copy-pasting.
When NOT to use:
- Single one-shot Codex review (use the existing
codexskill -/codex review,/codex challenge,/codex consult- it is faster for that) - The user wants Claude alone, not a paired review workflow
- Simple lookups or questions that don't need a second agent
co-review is specifically for sustained ping-pong over many turns. The setup cost (spawning a listener window) only pays off if the user will ask Codex more than once.
Architecture (read this once, then act)
- Pair dir:
~/.cc-codex-pairs/<pair-id>/(Windows:C:\Users\<user>\.cc-codex-pairs\<pair-id>\)to-codex.jsonl- messages Claude sends (one JSON per line)to-claude.jsonl- messages Codex sends backstate.json-{ "last_processed": "<msg-id>", "codex_session_id": "<thread-id-or-null>" }pair.json-{ "pair_id", "created_at", "project_cwd", "task_hint" }listener.pid- PID of the spawned listener (written at startup, removed on exit)listener.log- human-readable listener activitydisagreements.log- one line per stylistic disagreement Claude demoted out of the main thread (see Disagreement protocol below). Only created when first written to.- JSONL message files retain full prompts and replies until archived or deleted
shutdown- touch file; listener exits cleanly when it sees this
- Codex window: a new PowerShell console window (spawned minimized by default) running
codex-listener.ps1. It pollsto-codex.jsonl, runscodex exec(orcodex exec resume <thread-id>for follow-ups), and appends responses toto-claude.jsonl. The window's cwd is the project cwd (so Codex picks up the project'sAGENTS.md), not the pair dir. - Pair ID is the only thing you must remember inside this conversation. Pass it to every script call. Lose it and you can't reach the sibling (recover via
list-pairs.ps1).
Primitives - invoke via the PowerShell tool using the call operator
Use the PowerShell tool (not Bash) and call scripts with the & operator. Never pass -ExecutionPolicy Bypass - Claude Code's permission classifier auto-denies it. The user's CurrentUser policy (typically RemoteSigned) is sufficient for local skill scripts.
All script paths are under ~/.claude/skills/co-review/scripts/ (or the equivalent junction target).
1. Create a pair (start the sibling)
& "$env:USERPROFILE\.claude\skills\co-review\scripts\new-pair.ps1" -Task "Review my refactor of the auth middleware"
Output (last line is JSON):
{"pair_id":"pair-20260516-153012-a3f1","pair_dir":"...","window_spawned":true}
A new PowerShell window spawns minimized by default - visible in the taskbar but never stealing focus or overlaying the user's other windows. Tell the user the pair ID so they can spot the right taskbar icon if they want to peek.
Optional flags:
-CodexModel "gpt-5.5"- which Codex model to use. Defaults togpt-5.5. Override only if the user explicitly asks for a different model (e.g., "use gpt-5 instead").-CodexReasoning medium- reasoning effort:low/medium/high. Defaults tomedium. Bump tohighfor security audits or hard architectural reviews where Codex should think longer; drop tolowfor quick sanity checks.-WindowMode Hidden- listener has no visible window at all (activity still visible via~/.cc-codex-pairs/<pair-id>/listener.logandlist-pairs.ps1).-WindowMode Foreground- old behavior, opens the window in the foreground. Avoid unless the user explicitly asks.-CodexTimeoutSec 1800- max seconds to let one Codex turn run before the listener kills it and returns an error.
The defaults (gpt-5.5, medium) are pinned in the skill so behavior is consistent across machines regardless of each user's ~/.codex/config.toml. The -m and reasoning flags are passed explicitly to every codex exec call.
Capture pair_id from the JSON line - you will need it for every other call.
2. Send a message and wait for the reply (most common)
& "$env:USERPROFILE\.claude\skills\co-review\scripts\ask.ps1" -PairId "pair-20260516-153012-a3f1" -Message "Here is my diff. Review for correctness and edge cases:`n`n<diff>" -TimeoutSec 600
Blocks until Codex replies (or timeout). Default timeout 600s. Matching is done by in_reply_to == msgId, so it is race-free.
For long prompts (large diffs), use -MessageFile <path> instead of -Message to avoid command-line length limits.
Optional per-ask flag:
-Reasoning low|medium|high- override the pair-level reasoning effort for just this one ask. Empty / omitted = use pair default (typicallymedium). Bump tohighfor security audits, hard correctness questions, or architectural decisions. Drop tolowonly for cheap sanity checks. Defaultmediumis the right answer for most reviews - don't pre-emptively go high without a reason.
3. Send without blocking
& "$env:USERPROFILE\.claude\skills\co-review\scripts\send.ps1" -PairId "pair-20260516-153012-a3f1" -Message "<text>"
Returns the new message ID.
4. Poll / wait for new replies
& "$env:USERPROFILE\.claude\skills\co-review\scripts\recv.ps1" -PairId "pair-20260516-153012-a3f1" -Since "cdx-0003" -Wait -TimeoutSec 300
-Since is the last reply ID you have already seen (omit on first call to get all). -Wait polls until something new arrives.
5. End the pair (close the Codex window cleanly)
& "$env:USERPROFILE\.claude\skills\co-review\scripts\end-pair.ps1" -PairId "pair-20260516-153012-a3f1"
Use -Archive to move the retained pair logs under ~/.cc-codex-pairs/archive/. Use -Delete to remove the retained prompts/replies after shutdown.
6. List active pairs (recovery)
& "$env:USERPROFILE\.claude\skills\co-review\scripts\list-pairs.ps1"
Status is determined by listener.pid liveness, not just the shutdown file.
7. Purge retained logs
& "$env:USERPROFILE\.claude\skills\co-review\scripts\purge-pair.ps1" -PairId "pair-20260516-153012-a3f1" -Force
Deletes a stopped pair directory permanently. This removes to-codex.jsonl, to-claude.jsonl, state.json, and logs.
Operating instructions for you (Claude)
- Spawn at most one pair per Claude conversation. Before calling
new-pair.ps1, check:- Do you already have a
pair_idtracked from earlier in this conversation? If yes, reuse it. Do NOT spawn another. - If you are unsure (e.g. long conversation, you can't find the pair_id in context), run
list-pairs.ps1first. If there is anactivepair whoseproject_cwdmatches the user's current working directory and whosetask_hintmatches what you are doing, reuse that
- Do you already have a