Claude Code、Codex、OpenCodeがあなたを待っていることを知る方法
Claude Codeは3つのフックで、あなたを待っていることを伝えます。AskUserQuestionに対するPreToolUse、permission_promptのNotification、そして最後のメッセージが質問で終わるStopです。誰も答えなかったあらゆる返答のあとに届くidle_promptは無視してください。Foxl CodeがリモートのClaude Code、Codex、OpenCode、Hermesのターミナルに使っている対応表と、各CLIが報告できないこと、そしてエージェントへの負担が小さく、うっかりモデルに話しかけることのないフックの書き方を紹介します。

このページの内容
Claude Codeのフックは、特定のイベントが起きたときに、あなたが設定したコマンドを実行します。そのうち3つが、Claude Codeがあなたを待っていることを教えてくれます。PreToolUseフックをAskUserQuestionツールに対して設定すると、質問ダイアログを開くときに発火します。Notificationフックのうち種類がpermission_promptのものは、権限のダイアログが数秒間開いたままになると発火します。Stopフックは毎回の返答の終わりに発火し、返答のテキストをlast_assistant_messageに載せているので、返答が質問で終わったかどうかを確かめられます。idle_promptは無視してください。これは質問のあとに限らず、誰も入力しなかったあらゆる返答の約1分後に届きます。
リモートのターミナルでコーディングエージェントを動かすFoxl Codeは、まさにこの3つを使って、リモートのClaude Codeターミナルが利用者を待っている状態だと判断します。v0.9.3-beta.5からは、同じ報告用のコマンドが、Codex、OpenCode、Hermesについても、それぞれのフックやプラグインを通じて読み取ります。以下では、CLIごとの対応表、それぞれの落とし穴、そしてエージェントへの負担をできるだけ小さくし、モデルのコンテキストにテキストを漏らさないフックの書き方を紹介します。実際のクラウドのターミナルから質問が報告された例はまだありません。何が未検証かは、最後のセクションに書いています。
ターミナルのエージェントが待っていることに、なぜ気づけないのか
リモートのターミナルでエージェントを動かす人は、いくつも同時に開いていながら、どれも見ていないことがあります。2026年10月21日、リモートのClaude Codeターミナルが「はい」か「いいえ」で答える質問をしてプロンプトで止まっていたのに、Foxl自身のAPIは、誰かを待っているタスクはないと答えていました。Foxl Codeのサイドバーも、人を待っているタスクを並べる「要対応」リストも、スマートフォンアプリも、何も知らせませんでした。この変更の前は、Foxl Codeのどこもその瞬間に耳を傾けていなかったのです。
画面を読めば解決しそうに見えますが、これは壊れやすい方法です。外から読む側にとって、考え中、完了、質問中の画面の違いはCLI自身が描く数文字にすぎず、どのリリースでも描き直される可能性があります。以前、私たちが同梱するCLIのバージョンを上げたとき、新しいビルドは入力チェックが待っていたものとは違う最初の画面を描き、リモートのCodexとOpenCodeのターミナルは10日間、入力を黙って無視していました。フックは、今何が起きたかをCLI自身が告げるもので、ペイロードも文書化されています。だから私たちはフックに耳を傾けます。
「あなたを待っています」を意味するClaude Codeのフックは?
私たちのクラウドイメージは、Claude Code 2.1.296に固定しています。以下で「パッケージから読み取り」としている詳細は、動いているターミナルではなく、そのバージョンのnpmパッケージから得たものです。
| フック | 意味 | 私たちの扱い |
|---|---|---|
PreToolUse、matcherはAskUserQuestion | 質問ダイアログが開こうとしている。tool_inputに質問と選択肢が入っている | 選択肢つきの質問 |
Notification、matcherはpermission_prompt | 権限のダイアログが、キー入力のないまま約6秒開いている(パッケージから読み取り) | 権限のリクエスト |
Stop | 返答が終わった。last_assistant_messageがそのテキスト | テキストが?で終われば質問、それ以外はターンの終わり |
UserPromptSubmit、PostToolUse、PostToolUseFailure、SessionEnd | 人が入力した、承認したツールが実行されたか失敗した、CLIが終了した | 回答済み |
Notification、typeはidle_prompt | "Claude finished responding about 60 seconds ago and you haven't typed since"(Claudeが約60秒前に返答を終え、それ以降入力がない) | 無視 |
idle_promptの行は、多くの設定がつまずくところです。メッセージはまさに求めているものに読めますが、誰も入力しなかったあらゆる返答のあとに届くので、これを質問として扱うと、ほぼ毎ターン通知が出てしまいます(Foxlの場合は「要対応」の項目とスマートフォンへの通知)。私たちはNotificationフックをpermission_promptのmatcherだけで登録し、スクリプトでも種類を再確認しています。Stopの判定では、末尾の空白、Markdownの強調、バッククォート、閉じ括弧、引用符を取り除いてから確かめ、CJKの入力方式で入力される全角の?も受け付けます。
Claude Codeの現在のドキュメントには、専用のPermissionRequestイベントや、ここに挙げた以外の通知の種類も載っています。2.1.296にこの新しいイベントがあるかどうかは確認していません。permission_promptは現在の一覧にもまだあり、6秒の待ち時間のおかげで、画面の前にいる人が答えたダイアログは除外されます。既存のフックが引き続き動くように、Claude Codeのユーザーレベルの設定ファイルで、同じイベントにすでに設定されているフックのあとに追加します。
{
"hooks": {
"PreToolUse": [{ "matcher": "AskUserQuestion",
"hooks": [{ "type": "command", "command": "report-prompt", "timeout": 10 }] }],
"Notification": [{ "matcher": "permission_prompt",
"hooks": [{ "type": "command", "command": "report-prompt", "timeout": 10 }] }],
"Stop": [{ "hooks": [{ "type": "command", "command": "report-prompt", "timeout": 10 }] }]
}
}これらはすべて1つの小さなスクリプト、つまり報告用コマンド(上のreport-prompt)を呼び出し、このコマンドはタスクの認証情報を環境変数から読み込みます。人が答えたことを意味するイベント、つまりUserPromptSubmitなどの「閉じる」イベントも同じように登録しますが、後述するガードを挟みます。
エージェントへの負担をできるだけ小さくするフックの書き方は?
報告用のフックはエージェント自身のループの中で動くので、フックのミスはすべてエージェントの問題になります。最終的に5つのルールに落ち着きました。どれも、ドキュメントか2.1.296のパッケージから得たものです。
- stdoutには何も出力しない。ほとんどのイベントでは、Claude Codeはフックのstdoutをログに残すだけですが、
UserPromptSubmitなどいくつかのイベントでは、"Claude Code adds plain-text stdout as context that Claude can see and act on."(プレーンテキストのstdoutを、Claudeが参照して行動に使えるコンテキストとして追加する)とされています。報告用スクリプトが出す状態の1行が、プロンプトの一部になってしまうのです。 - 常にexit 0で終わる。exit 2はブロックできるイベントでその操作をブロックし、それ以外の0以外のコードはエラーの通知を表示します。私たちのスクリプトでは、ネットワークの失敗はstderrに1行出すだけで、ほかには何も起こしません。
- 同期で、短いタイムアウトで実行する。フックは
"async": trueで実行することもできますが、固定しているビルドでは非同期フックが終わるたびにターミナルに1行表示されるため、ツール呼び出しのたびにフックが動くとノイズになります。私たちのフックはtimeout: 10の同期実行で、スクリプトはリクエストに3秒を与え、その少しあとに自分で終了します。Claude Codeでの実際のコストは、各返答の終わりにNode.jsの起動1回とリクエスト1回で、Foxlのサーバーに届かないときでも最大で約3秒です。 - 頻繁なイベントは、シェルでふるいにかける。
PostToolUseはツール呼び出しのたびに発火します。報告用コマンドは、開いているプロンプトを報告するときにマーカーファイルを作ります。「閉じる」フックはそのファイルがあるときだけNode.jsを起動し、なければstdinを読み捨てて、CLIがパイプの破損に出くわさないようにします。
何も開いていないあいだは、ツール呼び出し1回につきif [ -e /tmp/foxl-agent-prompt/open ]; then exec report-prompt; else cat >/dev/null; fitest -eが1回走るだけです。 - 認証情報をコマンドラインに出さない。フックはCLIの環境を引き継ぐので、トークンは環境変数から読み込み、
psに表示されることはありません。
Codex、OpenCode、Hermesはどう伝えるのか
拡張ポイントはCLIごとに異なり、私たちはそれぞれを、イメージに固定しているリリースから読み取りました。Codexには、Claude Codeのフック形式を受け付けるフックエンジンがあります。OpenCodeとHermes(Nous ResearchのエージェントCLI)は、ターミナルUIでシェルのフックを実行しません。代わりにプラグインを読み込むので、私たちのプラグインが正規化したイベントを同じ報告用コマンドに渡します。AWSのコーディングCLIであるKiroには、聞き取れるイベントがありません。
| CLI(固定バージョン) | 質問 | 回答 | 報告されないもの |
|---|---|---|---|
Codex 0.162.1、システムレベルのhooks.json | PermissionRequest、Stop(last_assistant_messageが?で終わるもの) | UserPromptSubmit、PostToolUse、Interrupt、SessionEnd | Planモードの質問ダイアログ |
| OpenCode 1.19.0、サーバープラグイン | question.asked、permission.asked、session.statusがidleで返答が?で終わるもの | question.repliedまたはrejected、permission.replied、session.statusがbusy | - |
| Hermes 0.19.0、Pythonプラグイン | pre_tool_call(clarifyのもの)、pre_approval_request、post_llm_call(?で終わるもの) | post_tool_call(clarifyのもの)、post_approval_response、pre_llm_call、中断されたon_session_end | - |
| Kiro 2.29.1 | なし | - | すべて。質問や承認のイベントがなく、Stopには返答のテキストが含まれない |
Codex。Codexは、あなた自身の設定にあるフックを実行前にレビューします。新しいフックや変更されたフックは、"are marked for review and skipped until trusted."(レビュー対象として印がつき、信頼されるまでスキップされる)とされています。システムレベルの設定に置く管理フックはポリシーによって信頼されるので、私たちはその方法でインストールしています。報告用コマンド自体は、Foxl Codeがプロンプトの報告を求めたターミナルにだけインストールされます。0.162.1で測ったところ、非対話のcodex execも管理フックを実行し、ツール呼び出しごとにフックについての2行を出力に書き込むため、Foxl Codeがcodex execで始める実行ではフックをオフにしています。0.162.1のソースを読むと、CodexのターミナルUIは300 msより長く動くフックを表示するので、報告用コマンドはプロンプトがあるかどうかを判断してマーカーファイルを書き、ネットワークリクエストは切り離した自分自身のコピーに任せます。
CodexのPlanモードの質問ダイアログは、あえて報告していません。そのPreToolUseフックは、Codexがその質問を許可するかどうかを決める前に発火し、Planモード以外ではCodexが質問を拒否するからです。0.162.1で測ったところ、フックは質問とともに発火し、そのあとCodexは"request_user_input is unavailable in Default mode"と答えました。Foxl CodeのターミナルはDefaultモードで始まるので、このフックを報告すると、誰にも尋ねられていない質問をスマートフォンに通知することになります。その代わり、Planモードで動くCodexのターミナルでは、質問ダイアログが「要対応」に載りません。
OpenCode。私たちのプラグインは、OpenCodeのイベントバスを聞いています。質問のイベントはOpenCodeのプラグインドキュメントのイベント一覧には載っておらず、v1.19.0のスキーマのソースにあります。私たちが読んだのはそちらです。idleの状態でターンが終わり、最後の返答が?で終わっていれば、そのターンを質問とみなします。質問や権限のダイアログが開いているあいだは状態の変化を無視するので、ダイアログの前後でエージェントがbusyやidleになっても、ダイアログは閉じません。サブエージェントのセッションからのイベントはスキップします。
Hermes。名前に反して、0.19.0のHermesのon_session_endは、毎ターンの終わり、返答の直後に発火します。私たちのプラグインがこれを「閉じる」として扱っていたときは、そのターンで尋ねたばかりの質問を取り下げていました。12件の質問のうち7件はすぐに閉じられ、1件は質問が自分の「閉じる」よりあとにサーバーに届いたため、閉じるものが何も残らないまま開きっぱなしになりました。今は中断されたセッション終了だけを「閉じる」として数え、報告はHermesが出した順に1つずつ送ります。
Kiroは対象外です。フックに質問や承認のイベントがなく、停止時のペイロードにも返答のテキストが含まれないからです。フックでは、プロンプトを開くことも、質問と回答を見分けることもできません。唯一のシグナルは非公開の形式で書かれた内部のセッションファイルで、私たちはそれを解析しないことにしました。
Foxlが知ったあとはどうなるのか
すべての報告は、そのタスク自身の認証情報で認証されてFoxl Codeのサーバーの1つのエンドポイントに届き、エージェントのほかの質問と同じ「要対応」リストの項目を開いたり閉じたりします。タスクには、図のように回答待ちの印がつきます。

返答の終わりにある質問には、「要対応」やスマートフォンから答えられます。Foxlは回答をそのタスクのターミナルに1行で入力し、その1秒後にEnterキーを別に送ります。Enterを含む1つのかたまりはペーストとして扱われ、送信されないからです。質問や権限のダイアログについては、FoxlはターミナルUIが期待するキー操作を推測しません。代わりに「要対応」のカードが選択肢を並べ、ターミナルで答えるよう案内し、ターミナルを開くボタンを表示します。ターミナルで答えると、同じフックを通じてカードが閉じます。
スマートフォンに通知するのは、見落とされうるプロンプトだけです。Foxlが知ってから15秒たっても開いたままの質問や権限のダイアログは、通知を送ります。ターミナルを見ている人なら数秒で答えるからです。Claude Codeの権限のダイアログは開いてから約6秒後に報告されるので、通知は約21秒後になります。質問で終わる返答は「要対応」に表示されますが、通知はしません。質問で終わる返答は多いからです。2026年10月21日の質問はこの種類だったので、今なら「要対応」とタスクには表示されますが、スマートフォンは鳴りません。

まだ検証されていないこと
テストでは、実際の報告用コマンドを固定した各CLIのペイロードで動かし、プラグインを固定したイベント形式でNode.jsとPythonの上で動かし、サーバーのエンドポイントをCloudflareのランタイムのローカルコピーで動かしました。まだ行っていないのは次のことです。
- 実際のクラウドのターミナルからの本物の質問。2026年10月23日の時点で、本番のテーブルにはそうしたプロンプトが1件もないため、実際のターミナルでのエンドツーエンドの確認はまだ済んでいません。
- これらのフックを実行するClaude Code。6秒の遅延や非同期フックの1行を含むClaude Codeの詳細は、2.1.296のパッケージから読み取ったもので、動いているターミナルで確認したものではありません。そのビルドをこれらのフックに対して実行するテストはありますが、まだ実行していません。
- ほかのCLIのターミナル。OpenCodeが質問のイベントをまさにその名前で届けることを含め、Codex、OpenCode、Hermesのいくつかの詳細はソースから読み取ったものです。実際に実行したのは
codex execだけです。
自分でもターミナルでエージェントを動かしているなら、コピーすべきはClaude Codeのフックの表です。3つのフックを自分に届く手段につなぎ、idle_promptは無視し、何も出力せず、exit 0で終わり、通知を送る前に数秒待つこと。Foxl Codeのターミナル側については、すべてのキー入力が別のマシンに届いていた理由についての記事で、そもそも入力がどうやってリモートのエージェントに届くのかを解説しています。