Codex を並列で動かすと、必ずどれかが止まって待っています — 承認待ちを見つける

Codex を並列で動かすと、必ずどれかが止まって待っています — 承認待ちを見つける

昼を食べて戻ってきて、ブラウザの格子を眺めます。

左上は進んでいます。右上も、さっきより行が増えています。真ん中の枠だけ、出かける前と同じ画面のままです。

拡大すると、いちばん下にこう出ていました。

Allow codex to run `npm test`? (y/n)

45分前のことでした。

止まる理由

Codex は、コマンドを実行する前に「これを実行してよいか」と聞いてきます。ファイルを書き換えるとき、シェルを叩くとき、その都度ダイアログが出ます。

これは安全のための仕組みなので、止まること自体は正しい動きです。1つだけ動かしているなら、聞かれたらその場で答えればよいだけです。

並列にすると前提が変わります。5つ動かしていると、どれか1つは高い確率で承認待ちです。そしてどれが待っているかは、その画面を見るまで分かりません。

Claude Code には承認を飛ばす起動方法があります。--permission-mode を渡せば、聞かずに進めるようにできます。grok には --permission-mode auto、muse には --yolo が同じ役割です。

Codex には、これにあたるものがありません。つまり止まるのを避ける設定が無いので、並列で動かす限り、誰かが必ず待っています。

見つけ方が無かった

止まっていることは、画面を見れば分かります。問題は、5枚の画面を順番に見ないと分からないことです。

tmux で分割していれば一度に見えますが、画面が小さくなります。9つ並べると、1つあたりの文字が読めません。かといって切り替えて回ると、1周するあいだに別のものが止まります。

通知を鳴らそうにも、鳴らす材料がありません。Codex がいつ止まったかを、外から知る手段が無かったからです。ターミナルの中に描かれた文字を、別のプログラムが読み取るしかなく、それは画面の見た目が変わるたびに壊れます。

Codex が外に知らせるようになりました

Codex 0.156 から、フックという仕組みが入りました。決められた出来事が起きたときに、こちらが指定したコマンドを実行してくれます。

その中に PermissionRequest があります。承認ダイアログを出したときに動きます。 MulmoTerminal で実際に測ったところ、ダイアログが出たときだけ動いて、ほかのツール呼び出しでは動きませんでした。つまりこれが、そのまま「いま人を待っている」という合図になります。

ここは道具によって事情が違います。GitHub Copilot の permissionRequest と Cursor の beforeShellExecution は、名前が似ていますがツールを呼ぶたびに動きます。承認を求めたかどうかに関係なく動くので、そのまま合図に使うと、全部のツール呼び出しが「待っている」と表示されてしまいます。これは何も表示しないより悪い状態です。

Codex のものは、ダイアログを出したときだけ動きます。

自分で組む場合

MulmoTerminal を使わなくても組めます。Codex の設定にフックを登録して、呼ばれたら自分のサーバーに知らせるようにすればよいだけです。

codex -c 'hooks.PermissionRequest=[{hooks=[{type="command",command="curl -s -X POST http://127.0.0.1:8080/waiting || true"}]}]'

受け取る側で、どのセッションから来たかを記録して、音を鳴らすなり画面に出すなりします。セッションを区別するために、環境変数でセッション名を渡しておくと楽です。

気をつける点が3つあります。

1つ目は、Codex が一度だけ確認してくることです。フックを登録すると「Hooks need review」というダイアログが出ます。ここで承認しないとフックは動きません。そしてこのダイアログの内容が変わるたびに、また聞かれます。登録するコマンドにセッションごとの値を直接書き込むと、新しいセッションを作るたびに確認を求められます。環境変数で渡して、コマンド自体は固定にするのがよいです。

2つ目は、サーバーが落ちていても失敗にしないことです。Codex はフックの出力を見て判断するので、エラーで終わると動作に影響します。|| true を付けておきます。

3つ目は、止まったことだけでは足りないことです。終わったことも知りたいので、別の仕組みが要ります。Codex は作業の記録を rollout というファイルに追記していくので、そこを読めば区切りが分かります。フックと違って、こちらは信頼の確認が要りません。

MulmoTerminal の場合

いま書いた仕組みが、最初から入っています。

npx mulmoterminal@latest

起動フォーム。エージェントを選び、作業ディレクトリを決め、必要なら worktree を切って始めます

打つとブラウザが開いて、格子状の画面が出ます。それぞれの枠が1つのセッションで、Codex でも Claude Code でも選べます。枠の色が、動いているか、人を待っているか、終わったかを表します。待ちになったときには、終わったときと違う音が鳴ります。

枠ごとに git の worktree が切られるので、同時に走らせても互いのファイルを踏みません。tmux が裏で動いているので、ブラウザを閉じても作業は続きます。

Windows では、このフックは登録しません。コマンドがシェルの展開と /dev/null に依存していて、Windows でどう動くかを測っていないからです。最初の指示を渡して起動する場合も登録しません。確認ダイアログが出ているところに指示が打ち込まれると、Enter が「Hooks を確認する」を選んでしまって、指示が消えるからです。

分かっていないこと

Codex の rollout には、ツールをいつ呼んだかも記録されている可能性がありますが、それが使える形で入っているかは測っていません。 Claude Code のほうは、どのツールをいつ呼んだかまで読めるので、そこは差があります。

Codex から読めるのは、いまのところ「始まった」「終わった」「人を待っている」の3つです。

まとめ

Codex を並列で動かすと止まるのは、安全のための仕組みがそのまま働いているからです。Claude Code のように承認を飛ばす方法が無いので、避けるのではなく、気づく方法を用意するほうが筋が通っています。

0.156からフックが入り、承認ダイアログを出したことを外に知らせられるようになりました。自分で組んでもよいですし、既に組んであるものを使ってもかまいません。どちらにしても、5枚の画面を順番に見て回る必要は、もう無くなりました。

この記事をシェア

関連記事

記事一覧に戻る