Skip to main content

codex-debate

Run an automated codex⇄Claude debate to consensus — no round cap, no deadlock exit. Two explicit subcommands. `review` (also the bare/back-compat default) — codex (reviewer) critiques the current diff and a Claude subagent (author) fixes/disputes, looping until they agree. `answer` — Claude and codex each answer a freeform prompt in parallel, then cross-check until they agree, and a unified answer is returned. Use when the user types `/codex-debate`, asks to "have codex review this", "run the codex debate", "review this PR with codex", "argue this with codex until you agree", or passes a question to "have Claude and codex debate/answer until they agree".

Source facts

Repository
srid/emanote
Last source activity
June 28, 2026 at 21:24
Detected SKILL.md language
English
Stars
963
Forks
80

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
8 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
codex-debate
description
Run an automated codex⇄Claude debate to consensus — no round cap, no deadlock exit. Two explicit subcommands. `review` (also the bare/back-compat default) — codex (reviewer) critiques the current diff and a Claude subagent (author) fixes/disputes, looping until they agree. `answer` — Claude and codex each answer a freeform prompt in parallel, then cross-check until they agree, and a unified answer is returned. Use when the user types `/codex-debate`, asks to "have codex review this", "run the codex debate", "review this PR with codex", "argue this with codex until you agree", or passes a question to "have Claude and codex debate/answer until they agree".
argument-hint
review [<pr-number>] [--base <branch>] [--no-commit] [--no-comment] [--rationale <note>] [--context <note>] | answer "<prompt>"
# Codex ⇄ Claude debate This skill runs an automated debate between **codex** and **Claude** that loops to consensus with no round cap and no deadlock exit. It has **two modes**, selected by an **explicit leading subcommand** — never by guessing from the argument's shape: - **`review`** — codex reviews the current diff, a Claude author fixes/disputes, round after round until they agree, and the trail is **committed + posted to the PR** (a mutating, outward-facing mode). This is everything from [Review mode](#review-mode) down. - **`answer`** — Claude and codex **each answer a freeform prompt in parallel**, then **cross-check each other** until both agree, and a **unified answer** is returned to you (read-only; plus a saved transcript). See [Answer mode](#answer-mode). The two modes have **different side-effect contracts** (review mutates + writes to the PR; answer is read-only), so the mode is chosen **explicitly**, not inferred from whether the argument looks like a PR number or like prose. Inferring a mutating action from prose shape is exactly the coupling this design avoids. ## Mode detection (do this first) Look at the **first whitespace-delimited token** of `$ARGUMENTS`: - **`answer`** → **answer mode**. The prompt is everything after the `answer` token. Jump to [Answer mode](#answer-mode); the review-mode steps do not apply. - **`review`** → **review mode**. The remaining args are the review grammar (`[<pr-number>] [--base …] [--no-commit] [--no-comment] [--rationale <note>] [--context <note>]`). Continue with [Review mode](#review-mode). - **No args, OR the first token is a number (a PR number) or a `--flag`** → **review mode** (the backward-compatible bare alias for the original `/codex-debate [<pr>] [flags]`, so existing callers like `/be-review` keep working). Continue with [Review mode](#review-mode). - **Anything else** (freeform prose with no recognized subcommand) → **ambiguous**. Do **not** guess — ask the user to pick an explicit mode and stop, e.g.: "Did you mean `/codex-debate answer \"<your prompt>\"` (read-only) or `/codex-debate review [<pr>] [flags]` (mutating)?" Only the safe, backward-compatible review grammar auto-routes; prose never silently triggers a mode. Both modes require Claude Code's **`Workflow` tool** (the engine). Under codex/opencode runtimes the skill is inert. <a id="review-mode"></a> # Review mode — Codex ⇄ Claude review debate Automate the back-and-forth you'd otherwise courier by hand: **codex** (the reviewer) critiques the current change, a **Claude subagent** (the author) fixes what it agrees with and disputes what it doesn't, codex re-reviews, and so on — round after round, **until they reach consensus**. codex reviews from a **warm session**: round 1 cold-starts the reviewer, and every later round *resumes that same codex session* (`codex exec resume`), so codex carries its own prior review and reasoning forward instead of reconstructing it from the diff + rebuttal each round — when Claude disputes a finding, codex argues from its original rationale. There is no round cap and no "deadlock" surrender: a debate that quits without agreement defeats the purpose, so the two sides keep arguing until one concedes. You stay out of the middle: each round lands as its own commit whose message carries the debate context (codex's findings + Claude's dispositions) so the PR history reads as the debate, and the summary is **posted to the PR** as a comment at the end. ## Why this shape The two sides are asymmetric, and that asymmetry is the whole design: - **codex** is CLI-invokable headlessly (`codex exec`, authed via ChatGPT), so it runs from a shell command. - **Claude on a Max plan is *not* headless** — `claude -p` doesn't work with Max auth. But the **Workflow tool's `agent()` spawns Claude subagents through the harness**, not `claude -p`, so it works. That subagent is the author side. So the debate runs as a Workflow: `agent()` is Claude, a Bash-invoked `codex exec` is the reviewer, and the script couriers structured verdicts between them and decides when they agree. Both sides are forced to emit schema-constrained JSON, so consensus is detected in code, not by vibes. **This skill requires Claude Code's `Workflow` tool** (it is the engine). Under codex/opencode runtimes the skill is inert. ## Arguments A leading `review` subcommand token, if present, is consumed by mode detection; what remains is `[<pr-number>] [--base <branch>] [--no-commit] [--no-comment] [--rationale <note>] [--context <note>]` (the bare alias passes the whole argument string through unchanged). Parse: - **`<pr-number>`** (optional): a PR to debate. If given, `gh pr checkout <n>` first and default the base to that PR's base branch. If omitted, debate the **current branch's** working-tree diff. - **`--base <branch>`**: ref to diff against. Always a **remote-tracking ref**, never a stale local branch. Default: `origin/<PR base>` when a PR number is given, else the repo default branch as `git symbolic-ref --short refs/remotes/origin/HEAD` (e.g. `origin/master`) — used **as-is**, NOT stripped to local `master` (which can lag the remote). Fallback `origin/master`. Step 1 runs `git fetch origin` first so the ref is current. The workflow then resolves this to the **merge-base** of `base` and HEAD and diffs against that, so commits `base` gained since the branch forked aren't reviewed as part of this change. - **`--no-commit`**: don't commit per round — leave all agreed changes uncommitted in the working tree for you to commit yourself. Default is to **commit each round** (see below). - **`--no-comment`**: don't post the debate summary to the PR. By **default**, when a PR exists, the debate summary IS posted as a PR comment (see step 3). Pass this to suppress the outward-facing write and report in chat only. - **`--rationale <note>`** (optional): the author's note on **deliberate** design decisions. Threaded into **both** sides — codex's round-1 review prompt (so it doesn't flag intentional choices as defects; its warm session carries the note across later rounds) and the Claude author's prompt **every round** (so it *disputes*, rather than "fixes", a finding that contradicts a deliberate choice). Mirrors `/lens-debate`'s `rationale`. Pull it from the PR/issue description, or the caller (`/be-review`) passes the change rationale straight through. - **`--context <note>`** (optional): the **main-agent context** the Claude author should **inherit** — what this change is FOR (its task/intent and key decisions the orchestrator already holds). Injected into the author's prompt **every round** so it no longer reconstructs intent from the diff alone (`agent()` is one-shot and can't be resumed the way codex is, so re-injection is how it inherits at all). Given to the **author only**, not codex — codex stays an independent reviewer of the code, not the author's narrative. `/be-review` passes the task context through. ## Steps ### 1. Resolve context - Determine `repoPath` (the worktree root, normally the cwd). - **`git fetch origin`** so remote-tracking refs are current — the base is an `origin/...` ref, and a stale one would diff against the wrong tree. - Resolve `base` per the rules above (a remote-tracking ref like `origin/master`). - If a PR number was given, `gh pr checkout <n>` and confirm the branch. - Confirm there is a non-empty diff: `git diff --stat <base>`. If empty, tell the user there's nothing to review and stop. - **Preflight codex**: `codex login status`. If not logged in, stop and tell the user to run `codex login` (suggest the `!` prefix to do it in-session). ### 2. Run the debate Workflow Invoke the **`Workflow` tool** pointing at this skill's committed script, passing context through `args`: ``` Workflow({ scriptPath: ".claude/skills/codex-debate/debate.workflow.js", args: { repoPath: "<worktree root>", // also the per-worktree scratch dir root base: "<base branch>", commit: <false only if --no-commit>, skillDir: ".claude/skills/codex-debate", context: "<main-agent context the author inherits; omit/'' if none>", rationale: "<author's note on deliberate decisions; omit/'' if none>" } }) ``` The workflow runs in the background and notifies you when it completes. It alternates `codex:roundN` and `claude:roundN` agents under a **Debate** phase — the user can watch live via `/workflows`. Each Claude round edits the working tree and (unless `--no-commit`) **commits exactly that round's changed files in the same session** — one commit per round, with a message embedding the round's codex findings and Claude's dispositions — never pushing or merging. (The commit is no longer a separate `commit:roundN` agent: the author already has the tree open, so it commits its own round.) Ephemeral scratch (verdicts, the debate ledger) lives under the gitignored, per-worktree `<repoPath>/.codex-debate/`, so **parallel debates in different worktrees never collide** and the scratch never shows up in the diff codex reviews. It returns: ``` { status: "consensus" | "commit-incomplete" | "section-incomplete" | "reviewer-error", rounds, base, finalVerdict, filesChanged, commitGaps, sectionGaps, transcript, commentHeader, // the comment's small deterministic header (badge + round count + effort + base) workDir, sectionGlob } // where the per-round section files live; cat them under the header (step 3) ``` (each `transcript[]` round also carries a `commit` SHA when that round committed; `commitGaps` lists the round numbers whose author edited files but returned no commit SHA — empty unless `status === "commit-incomplete"`; `sectionGaps` lists the round numbers whose author left no disposition section file — empty unless `status === "section-incomplete"`.) There is one more, **earlier** terminus the workflow can return **before** the debate loop even starts — `merge-base-error`. If `git merge-base <base> HEAD` fails (a missing/typoed/stale base, or unrelated history), the diff scope can't be trusted, so the workflow **aborts up front** rather than review the base branch's drift as if this change made it. It returns a **different, smaller shape** — no `commentHeader`, `workDir`, or `sectionGlob`, because no debate (and so no section files) ever ran: ``` { status: "merge-base-error", base, rounds: 0, transcript: [], finalVerdict: null, note } // human-readable: which base failed and how to fix it (e.g. `git fetch`) ``` The debate is recorded as small Markdown section files under `<workDir>` — **two per round**: `section-NNN-1-codex.md` (codex's verdict + findings) and `section-NNN-2-claude.md` (the author's per-finding dispositions), zero-padded so the `section-*.md` glob sorts in chronological order. **Each file is written by the party that owns its content**: a Haiku writer renders codex's small *structured* verdict to disk, and the **author writes its own dispositions directly** — the same way codex writes its verdict to a path. That author-writes-its-own-file design is deliberate: it keeps the author's *structured* return a **minimal ack** (`filesChanged`/`commitSha`/`done`), so a big multi-finding narrative can never overflow the structured-output encoding (the failure that used to crash the debate on large diffs). The author's disposition file does triple duty — it's the author's cross-round **memory**, the **rebuttal** codex reads next round (`codex-review.sh` cats it straight into codex's prompt), and the **published comment** (step 3 cats the section files under `commentHeader`). So the comment is still a **deterministic** render — a shell `cat`, never re-improvised through an agent, nothing weak ever retyping a large blob. codex is *not* a memory reader — it keeps its own warm session and only ever reads the one rebuttal file. - **consensus** — every finding codex raised is resolved (any severity — Claude fixed it or codex conceded the dispute). This is the *only* way the debate ends *normally*: it keeps running rounds until codex and Claude agree on every point, with no round cap and no deadlock exit. (The harness's own per-workflow agent backstop is the sole hard ceiling; if you ever need to stop a debate by hand, interrupt it via `/workflows` or `TaskStop`.) - **commit-incomplete** — the debate *converged* (codex approved, nothing open), but a round's author edited files yet returned **no commit SHA**, so its in-session commit didn't land and the "one commit per round" contract broke for the round(s) in `commitGaps`. The edits are **not lost** — they stay in the working tree and the next reviewer diffs them against the base — but this is **not** a clean consensus: a human must reconcile the uncommitted round(s) (e.g. commit the outstanding tree) before relying on the per-round history. Do **not** report it as a plain consensus (see step 3). - **section-incomplete** — the debate *converged*, but a round's author **skipped or under-filled its disposition section file** (`section-NNN-2-claude.md` missing, empty, or missing a backticked marker for an open finding, for the round(s) in `sectionGaps`). That file is the hole-free trail everyone draws on — the author's memory, the rebuttal codex reads next round, and part of the posted comment — so a miss means the published record has a gap. The code guards against feeding an empty rebuttal to codex (it warns and keeps the prior pointer), and the tree edits are still present, but this is **not** a clean consensus: a human must fill in the missing round(s) before trusting the per-round record. Do **not** report it as a plain consensus (see step 3). - **merge-base-error** — an *up-front* abort, **before** any debate round runs: `git merge-base <base> HEAD` failed (missing/typoed/stale base, or unrelated history), so the review scope can't be trusted. The return carries a human-readable `note` (which base failed, how to fix it — e.g. `git fetch`) and **none** of the comment-assembly fields (`commentHeader`/`workDir`/`sectionGlob`), because no section files were ever written. Report the scope failure and **skip comment assembly/posting entirely** (see step 3); fix the base ref and re-run. - **reviewer-error** — the one *abnormal* terminus: codex itself failed to produce a verdict (broken/unavailable CLI), so the workflow synthesized an error verdict and aborted rather than spin forever on a dead reviewer. This is **infrastructure failure, not a debate outcome** — `finalVerdict.summary` carries the failure detail (including how many attempts were made). Do **not** treat it as consensus (see step 3). **Transient failures are retried first:** `codex-review.sh` retries the `codex exec` invocation with linear backoff (default 3 attempts; tune via `CODEX_REVIEW_RETRIES` / `CODEX_REVIEW_BACKOFF`) and only synthesizes the reviewer-error verdict once every attempt comes back empty — so a single codex hiccup no longer sinks the round. ### 3. Present the result **First branch on `status`.** If `status === "merge-base-error"`, the workflow **aborted before any debate ran** — `git merge-base <base> HEAD` failed, so the review scope couldn't be trusted. This return has **no** `commentHeader`, `workDir`, or `sectionGlob` (no section files exist), so there is **nothing to assemble**: do **not** run the posting block below. Report the scope failure — surface the return's `note` (it names the failing base and the fix) — tell the user to repair the base ref (e.g. `git fetch`, fix a typo'd/stale ref) and re-run, and **skip the rest of this section**. If `status === "reviewer-error"`, the debate did **not** reach consensus — codex never produced a real verdict. Report it as a **failure**, not a success: surface `finalVerdict.summary` (and the workflow log) so the user sees codex was broken/unavailable, and tell them to fix codex (e.g. `codex login`, check the CLI) and re-run. Do **not** post a consensus badge or a `## Codex ⇄ Claude debate` PR comment for this path — there is no agreement to report. Skip the rest of this section. If `status === "commit-incomplete"`, the debate converged but at least one round left its edits **uncommitted** (the round numbers are in `commitGaps`). Report it as **converged-but-not-clean**: assemble and post the comment (see the posting block below — `commentHeader` already shows a `⚠️` badge, not the consensus check), then tell the user which round(s) are uncommitted and that the outstanding tree must be committed before the per-round history can be trusted. Do **not** call it a clean consensus. If `status === "section-incomplete"`, the debate converged but at least one round's author **skipped or under-filled its disposition section file** (missing, empty, or omitting a marker for an open finding; round numbers in `sectionGaps`). Report it as **converged-but-not-clean**: assemble and post the comment as usual
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub