Codex CLI は 1 Skill にまとめるな ― `codex-review` と `codex-ask` を分けた意思決定ログ
TL;DR
Codex CLI を Claude Code から呼ぶ Skill を 1 本にまとめる構成から、codex-review(差分レビュー)と codex-ask(汎用)の 2 本に分離した。きっかけは「PR レビュー」と頼んだときに codex exec モード(汎用)に誤振り分けされ、プロンプト側で git diff を自前で埋め込もうとする挙動に遭遇したこと。以降は「1 CLI = 1 Skill」を捨て、description をルーティング規則として設計するようにした。
関連する前日談は 個人ブログ基盤を AI にゼロから作らせたら何に躓いたか に書いた AI ピアレビューの話に繋がっている。
事故の具体
統合 Skill 構成で書いていた頃のこと。コード差分レビューを頼んだら、Skill は発火したものの内部で codex exec "<prompt>" モードに落ちた。プロンプト側に git diff を AI が埋め込もうとし、出力は codex exec review がやってくれる構造化レビューとはまるで違う自由記述に。やり直しの指示も通らず、Skill 境界の内部で 2 重推論が起きているらしいと気付いた。
Claude Code 側は description を見て「どの Skill を使うか」を決める。ここまでは理解していた。問題はその先で、統合 Skill 内にある「review モード / ask モード」の分岐推論に Claude は直接関与できないことだった。Skill 本体の中でモード選択を推論するのは Claude ではなく、Skill の中身を辿っている内部状態である。この二段推論のどちらかが外れると、リカバリ経路がない。
この 1 件だけで「1 Skill 統合は無理筋」という結論に傾いた。理屈で考えて分離にしたのではなく、体験的に「そうするしかない」と思った、という順序。
インターフェース自体が非対称だと気付いた
分離方針で再設計するタイミングで codex -h を洗い直し、codex exec と codex exec review が入力の流れからして逆向きだと改めて認識した。
| 観点 | codex exec | codex exec review |
|---|---|---|
| 主役の入力 | 自然言語プロンプト | Git 差分(コマンドが自動取得) |
| プロンプト | 任意(引数または stdin) | 任意(省略可能) |
| 専用オプション | なし | --uncommitted / --base / --commit / --title |
| 期待される出力 | 自由形式 | レビュー中心の最終メッセージ(形式は設定や指示に依存) |
| 入力の支配権 | 呼び出し側 | CLI 側 |
codex exec review は差分取得が CLI に組み込まれた宣言的インターフェース。codex exec はプロンプトが主役の命令的インターフェース。入力をどちらが持っているかが反対である。このレベルで非対称なものを 1 Skill に押し込むのは、そもそも無理があった。
代替案を一応眺めて、どれも選ばなかった理由
分離と決める前に、あと 2 案だけ検討した。
- Claude sub-agent として立てる(Task ツール経由で Codex を委譲)— 試したら、JSON 受け渡しで Codex 特有の「自然文にしれっと示唆を混ぜる」ニュアンスが削がれた。Codex を使う旨味の一部が消える。
- MCP サーバーで wrap する — ツール名で呼べる利点はあるが、Codex CLI のバージョン追従が MCP 層の改修サイクルに引きずられる。個人事業主 1 人で保守するには重い。
結果、SKILL.md 1 枚で済む Skill 分離が一番軽かった。この判断は「運用者の時間コスト」を最優先した、ともいえる。
description をルーティング規則として書く
2 本の Skill を分けただけでは、Claude が正しい方に振り分けてくれる保証がない。そこで description に相手 Skill へのクロスリファレンスを明記した。
codex-review側: 「コードレビュー以外の汎用タスクはcodex-askスキル(codex exec)を使うこと」codex-ask側: 「コードレビュー(差分に対するレビュー)にはcodex-reviewスキル(codex exec review)を使うこと」
この**「自分じゃなければ相手を呼べ」**という negative clue を入れたとたん、PR レビュー依頼が codex-ask に誤発火する事象は目撃頻度が下がった。厳密な計測はしていない、主観の域である。
description は単なる自己紹介ではなく、ルーティング規則として設計する。これが今回の一番の持ち帰り。
AI 呼び出し前提の 3 点固定
両 Skill とも同じデフォルトを敷いた。
--full-auto: 低摩擦実行のエイリアス(v0.106.0 の--helpでは-a on-requestと--sandbox workspace-writeの組み合わせ相当)--ephemeral: セッション非永続化-o <dir>/.claude/codex-(review|ask)-<theme>.md: 最終メッセージをファイル化
codex-ask 側はさらに、プロンプト末尾に「確認や質問は不要である。具体的な提案・修正案・コード例まで自主的に出力してほしい」を必ず付ける。これが無いと Codex は追加情報を求めてくることがあり、非対話前提が破綻する。1 行のプロンプト工学で挙動が明確に変わる。
副作用ファイルはセッションの中で閉じる
-o で保存する結果ファイルを残し続けると、後続セッションで Claude が勝手に過去ログを参照して誤結合する事故が 1 回起きた。読み取り → 要約 → 削除、をワークフロー末尾に組み込む方針に変更。ただし rm グロブは境界が甘くなりやすいので、次のように対象を限定する。
find "$TARGET_DIR/.claude" -maxdepth 1 -type f \
\( -name 'codex-review-*.md' -o -name 'codex-ask-*.md' \) -delete
ユーザーが途中で中断した場合の残骸には対応できていない。housekeeping スクリプトで定期掃除する運用を検討中。
実行環境
- Claude Code / Codex CLI v0.106.0
- Codex 側モデル:
gpt-5.3-codex(デフォルト) - Skill 配置:
~/.claude/skills/codex-(review|ask)/SKILL.md - サンドボックス:
--full-auto(workspace-write)
残った課題
- description への negative clue をどこまで厚く書くとルーティング精度が頭打ちするか、未検証。
- Codex のレートリミットが
codex reviewと それ以外で区分されているかもしれないという情報を見たが、公式確認は取れていない。現状 Skill 分離の主要根拠は「責務分離」に置いており、レート区分最適化は脇に退けている。 - 同時に 2 セッションで
codex execを走らせたとき、-oの出力先ファイル名が衝突する可能性。<theme>スラッグの一意化では完全には防げない。
設計としては閉じたが、運用の細かい穴がまだ開いている。ここに残しておくのは、半年後にまた「なぜこうしたんだっけ」となったときに自分で読み返す備忘でもある。