メインコンテンツへスキップ
KatoKyo works

Codex CLI は 1 Skill にまとめるな ― `codex-review` と `codex-ask` を分けた意思決定ログ

| 読了 5 分 | 技術

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 execcodex exec review入力の流れからして逆向きだと改めて認識した。

観点codex execcodex exec review
主役の入力自然言語プロンプトGit 差分(コマンドが自動取得)
プロンプト任意(引数または stdin)任意(省略可能)
専用オプションなし--uncommitted / --base / --commit / --title
期待される出力自由形式レビュー中心の最終メッセージ(形式は設定や指示に依存)
入力の支配権呼び出し側CLI 側

codex exec review は差分取得が CLI に組み込まれた宣言的インターフェース。codex exec はプロンプトが主役の命令的インターフェース。入力をどちらが持っているかが反対である。このレベルで非対称なものを 1 Skill に押し込むのは、そもそも無理があった。

代替案を一応眺めて、どれも選ばなかった理由

分離と決める前に、あと 2 案だけ検討した。

  1. Claude sub-agent として立てる(Task ツール経由で Codex を委譲)— 試したら、JSON 受け渡しで Codex 特有の「自然文にしれっと示唆を混ぜる」ニュアンスが削がれた。Codex を使う旨味の一部が消える。
  2. 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> スラッグの一意化では完全には防げない。

設計としては閉じたが、運用の細かい穴がまだ開いている。ここに残しておくのは、半年後にまた「なぜこうしたんだっけ」となったときに自分で読み返す備忘でもある。