コードを書いたAIとは別のAIに、最後のレビューを頼む。
考え方は単純です。
ただ、自分の運用では受け渡しが単純ではありませんでした。
一方の画面から変更内容を取り出し、もう一方へ貼る。
返ってきたfindingを元の作業へ戻し、直したらもう一度同じ往復をする。
レビューそのものより、間をつなぐ手作業が増えていた。
そこで、CodexとClaude Codeの間を直接つなぎ、cross-model reviewをone-shotで閉じる形を試しました。
結果は便利だった、だけではありません。
公式pluginでつながる方向と、自分で作ったローカルwrapperでつなぐ方向は非対称だった。
しかも、別modelの回答が増えても、最後に真偽を決めるのは人の仕事でした。
2つのAIへ同じdiffをコピペするのをやめたかった
以前は、実装を終えたあとに別のAIへレビュー用の説明を作っていました。
対象のdiff、確認してほしい範囲、変更してはいけない条件をまとめ、回答を元の作業へ戻す。
慎重にやるほど、受け渡し文が長くなります。
問題はコピペの回数だけではありません。
対象scopeが少しずれたり、古いdiffを渡したり、レビュー結果を修正指示としてそのまま採用したりする余地が残る。
人が間にいることは必要でも、人が毎回データを運ぶ必要はないと思いました。
以前、ClaudeとCodexをAIチームとして使った記録では、それぞれへ違う役割を持たせました。
今回やったのは、その役割分担をコードレビューの最後へ絞ることです。
実装担当とreviewerを分け、受け渡しだけを小さな仕組みに寄せました。
ClaudeからCodexを呼ぶ方向はOpenAI公式pluginだった
Claude CodeからCodexへreviewを頼む方向には、OpenAI公式のcodex-plugin-ccを使いました。
pluginが用意する/codex:reviewは、現在のworking treeやbase branchとの差分を対象にできます。
OpenAIのコマンド定義ではreview-onlyとされ、patchを適用しない役割です。
ここは、自作の連携ではありません。
pluginはローカルにあるCodex CLIとCodex app serverを使い、同じ認証状態と設定を参照します。
app serverは、threadの開始や再開などを扱うJSON-RPC interfaceです。
自分が確認した環境では、Claude Code 2.1.236、codex-plugin-cc 1.0.6、Codex CLI 0.148.0でした。
ただし、pluginのmainやローカル版は更新されます。
この記事の実測は、この時点の組み合わせに限ります。
Claude→Codexのmodelや費用は、今回の記録では分からない
OpenAIの公式資料では、Codexのmodelとreasoning effortを設定できることが説明されています。
認証も、ChatGPT sign-inとAPI key sign-inで利用枠や課金、data handlingの境界が変わります。
しかし、今回のClaude→Codex reviewで実際に選ばれたmodelとreasoning effortは取得していません。
token、cost、実際のbilling pathも未確認です。
設定できることと、そのrunで何が使われたかは別の話。
そのため、こちらの方向を「このmodelがこの金額で動いた」とは書けません。
公式pluginだから自動的にChatGPT利用枠だった、と決めることもできない。
確認できていない値は、不明のまま残します。
CodexからClaudeを呼ぶ方向はローカルwrapperにした
逆方向には、同じ公式pluginがあるわけではありません。
CodexからClaudeへreviewを頼むため、自分の環境ではClaude Code CLIを1回だけ呼ぶread-only wrapperを使いました。
Claude Code CLIのprint modeには、--json-schemaでschemaに沿った出力を求める仕組みがあります。
--no-session-persistenceを使えば、その実行を再開可能なsessionとして保存しない形にもできます。
wrapperでは、この公式CLI機能を利用しています。
ただし、wrapper自体は自分のローカル運用です。
Anthropic公式の「Codex連携plugin」ではありません。
公式なのはClaude Code CLIとstructured outputの仕様であり、scope固定、exactly once、read-onlyというまとめ方は自分の実装判断です。
ここを混ぜると、誰でも同じpluginを入れれば双方向になるように読めてしまいます。
実際には、片方はOpenAI公式plugin。
もう片方は、公開されたCLIの機能を使ったローカルwrapperです。
6→5→1→0は、AI同士が正解へ収束した数字ではない
ClaudeからCodexへreviewした側では、findingが6件、5件、1件、0件と変わりました。
数字だけを見ると、AI同士で修正を繰り返し、正解へ収束したように見えます。
でも、実際の中心はそこではありません。
各回でmaterialなfindingが出た時、自分が修正前に再現しました。
本当にその不具合が起きるのか。
契約したscopeの中なのか。
既存仕様を壊す指摘ではないか。
再現できたものだけを修正し、もう一度reviewした結果が6→5→1→0でした。
0 findingsは「完全に安全」の証明ではありません。
指定したdiffと、そのreview条件では追加findingが出なかった、という終了点です。
これは、AIの仕事を会話ではなく成果物で確認する運用と同じでした。
回答を信じるのではなく、手元で再現できる対象へ戻す。
cross-model reviewでも、最後に残ったのはその地味な作業でした。
逆方向では4 findingsのうち3件を再現できた
CodexからClaudeへ依頼したone-shot reviewでは、requested modelをOpus 5、effortをHighにしました。
実行時間は161,770ms、観測costは0.735708 USD、findingsは4件でした。
この値は、この1回のローカル実測です。
自分で確認すると、3件は再現できました。
残る1件は、review対象をtracked-onlyにしたため、未追跡assetが比較へ含まれなかったことで生じたscope artifactでした。
modelが間違えた、と一言で片付けるより、reviewへ渡した範囲が実装全体を表していなかった問題です。
retry、別modelへのfallback、reviewerによるsource repositoryへの書き込みは0回でした。
一度だけ走らせ、結果を構造化して受け取り、人が再現する。
この順序なら、reviewerが増えても作業の主導権を戻しやすいと感じました。
structured outputはfindingの真偽判定器ではない
JSON Schemaを使うと、severity、対象、理由、確認方法など、返してほしい項目を揃えられます。
自由文からfindingを拾い直す作業は減りました。
機械的に後工程へ渡す時にも扱いやすい。
一方で、schemaへ適合したJSONが返ったことは、内容が正しいことを意味しません。
Anthropicのstructured outputsは出力形式を制約する仕組みです。
不具合の再現、仕様との一致、scopeの妥当性までは保証しない。
同じ理由で、finding件数をmodelの順位表にも使いません。
4件見つけたmodelが1件のmodelより優秀、とは限らない。
対象scope、指示、既知情報、誤検知の数が違えば、件数の意味も変わります。
見るべきなのは、materialな指摘を人が再現できたか。
修正後の限定scopeで、出荷を止めるfindingが残っているか。
数字は作業記録であって、model rankingではありません。
cross-model reviewを閉じる5つの境界
今回の運用で残した境界は5つです。
- read-only:reviewerは調査とfinding返却だけを行い、sourceへpatchを書かない。
- scope固定:working tree、branch、base refなど、何を比較するreviewかを先に決める。
- exactly once:失敗や無応答を理由に、状態確認なしで同じreviewを重ねない。
- structured result:severity、根拠、対象、再現方法を同じ形で返す。
- author reproduction:materialなfindingは、修正する前に実装担当者が再現する。
この5つは、modelの性能を上げる設定ではありません。
reviewが長い会話へ広がり、誰が何を決めたか分からなくなるのを防ぐ運用面です。
read-onlyでも、対象scopeがずれていれば役に立たない。
schemaが整っていても、再現しなければ誤検知を修正へ混ぜる。
どれか1つではなく、5つを一続きにして初めて閉じやすくなりました。
常時review gateにはせず、materialなdiffへ1回だけ使う
OpenAI公式pluginには、Claude Codeの停止時にCodex reviewを走らせるreview gateもあります。
公式READMEにも、長時間のClaude / Codex loopになり、利用量を消費する可能性があると警告されています。
自分の運用では、すべての小さな変更へ常時gateを置きません。
認証、data loss、公開処理、rollback、複数fileにまたがる変更など、影響が大きいdiffへ絞ります。
そして、one-shot reviewを追加の確認層として使う。
reviewerを増やせば安全になる、とは限りません。
確認対象と終了条件が曖昧なままmodelだけを増やすと、findingの整理と再実行が新しい仕事になります。
今回減らしたかったのはコピペだけでなく、この終わらない状態でした。
小さく始めるなら、片方向と1つのdiffで十分
最初から双方向の仕組みを作る必要はありません。
Claude Codeを使っているなら、公式pluginのread-only reviewを1つのworking treeで試す。
Codex側から別reviewerを呼ぶなら、書き込み禁止、対象diff、出力項目、1回だけという条件を先に固定します。
最初の目的は、finding数を増やすことではありません。
コピペでscopeがずれないか。
返ってきた指摘を自分で再現できるか。
0件になった時、何をもって終了とするか。
この3点を確認できれば、次の変更へ広げる判断ができます。
逆に、再現確認へ時間を取れないならreviewを増やさない方がいい。
人の確認を省く仕組みではなく、人が確認する場所を狭くする仕組みだからです。
AI agentの基礎から整理したい人には、次の書籍が入口になります。
この記事で実使用した書籍ではなく、agentへ仕事を分け、確認点を作る考え方を補う次の一冊として選びました。
まとめ。相互レビューの最後は人が閉じる
CodexとClaudeを相互レビューさせると、diffとfindingを画面間で運ぶ手間は減らせました。
ただし、2方向は同じ仕組みではありません。
Claude→CodexはOpenAI公式plugin、Codex→Claudeは自分のローカルread-only wrapperです。
そして、別modelから返った結果も、そのまま正解にはしない。
schemaに適合しているかと、findingが正しいかを分ける。
件数を競わせず、materialな指摘を人が再現する。
read-only、scope固定、exactly once、structured result、author reproduction。
自分が残したのは、この5つでした。
相互レビューを自動化しても、最後に閉じるのは実装した人です。