フックは Codex の機能を拡張する仕組みです。エージェントの処理ループ内でスクリプトや MCP ツールを実行し、たとえば次のような処理を組み込めます。
- チャットを独自のログ収集・分析エンジンに送信
- チームのプロンプトをスキャンし、誤って API キーを貼り付けたプロンプトの送信をブロック
- チャットを要約し、永続的なメモリを自動で作成
- チャットのターンが停止したときに独自の検証を実行し、基準への準拠を徹底
- 特定のディレクトリで作業するときのプロンプトをカスタマイズ
フックは次のように実行されます。
- 複数のファイルに条件に一致するフックがある場合は、すべて実行されます。
- 同じイベントに一致するコマンドフックが複数ある場合は、並行して起動します。あるフックが、同じイベントに一致する別のフックの起動を妨げることはできません。
- 管理対象外のフックは、実行前に定義を確認し、信頼する必要があります。
会話中にフックが実行されるタイミングは次のとおりです。
| タイミング | フック |
|---|---|
| ターンの進行中 | PreToolUse、PermissionRequest、PostToolUse、PreCompact、PostCompact、UserPromptSubmit、SubagentStop、Stop |
| モデルへのリクエストを試行するたび | PreModelRequest、PostModelRequest |
| 進行中のターンを中断したとき | Interrupt(サブエージェントでは実行されません) |
| セッションまたはサブエージェントの開始時 | SessionStart、SubagentStart |
| メインスレッドが終了したとき | SessionEnd(サブエージェントでは実行されません) |
Codex がフックを探す場所
Codex は、有効な各設定レイヤーで次の形式のフックを探します。
hooks.json- インラインの
[hooks]テーブル(config.toml内)
インストール済みのプラグインには、プラグインマニフェストまたはデフォルトの hooks/hooks.json ファイルを使ってライフサイクル設定を同梱できます。プラグインのパッケージ化に関するルールは「プラグインの作成」を参照してください。
よく使う設定場所は次の 4 つです。
~/.codex/hooks.json~/.codex/config.toml<repo>/.codex/hooks.json<repo>/.codex/config.toml
フックの定義元が複数ある場合、Codex は条件に一致するフックをすべて読み込みます。優先順位の高い設定レイヤーが、優先順位の低いレイヤーのフックを置き換えることはありません。同じレイヤーに hooks.json とインラインの [hooks] が両方ある場合、Codex は両方の定義を統合し、起動時に警告を表示します。レイヤーごとにどちらか一方の形式を使うことをおすすめします。
Codex は、有効なプラグインに同梱されたフックも検出します。これらのフックは他の定義元のフックと一緒に読み込まれます。定義を確認して信頼する手順は、他の管理対象外のフックと同じです。
プロジェクトローカルのフックは、プロジェクトの .codex/ レイヤーが信頼されている場合にのみ読み込まれます。信頼されていないプロジェクトでも、Codex はユーザーとシステムのフックを、それぞれの有効な設定レイヤーから読み込みます。
フックの確認と信頼設定
Codex は設定済みのフックを一覧にしてから、実行可能なフックを判定します。管理対象外のフックを実行するには、実際に使われるフック定義を確認し、信頼する必要があります。Codex は信頼設定をフックの現在のハッシュに紐付けて記録します。そのため、新規または変更済みのフックは要確認となり、信頼されるまで実行をスキップします。
CLI で /hooks を使うと、フックの定義元の確認、新規または変更済みのフックのレビュー、信頼設定、管理対象外のフックの個別無効化ができます。起動時に確認が必要なフックがある場合、Codex は /hooks を開くよう警告を表示します。
システム、MDM、クラウド、または requirements.toml で管理されているフックは、管理対象として表示され、ポリシーに基づいて信頼されます。ユーザー向けのフック一覧から無効にすることはできません。
単発のオートメーションでフックの定義元を Codex の外部ですでに検証している場合は、--dangerously-bypass-hook-trust を指定できます。その実行に限り、保存済みの信頼設定がなくても有効なフックが実行されます。
設定の構造
フックの設定は次の 3 階層で構成されます。
PreToolUse、PostToolUse、PreCompact、SubagentStart、Stopなどのフックイベント- そのイベントの照合条件を決めるマッチャーグループ
- マッチャーグループの条件に一致したときに実行する 1 つ以上のフックハンドラー
{
"description": "Optional lifecycle hooks for this workspace.",
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume",
"hooks": [
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_start.py",
"statusMessage": "Loading session notes",
"additionalContextLimit": 5000
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_end.py",
"timeout": 3
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py\"",
"statusMessage": "Checking Bash command"
}
]
}
],
"PermissionRequest": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/permission_request.py\"",
"statusMessage": "Checking approval request"
}
]
}
],
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use_review.py\"",
"statusMessage": "Reviewing Bash output"
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/user_prompt_submit_data_flywheel.py\""
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 \"$(git rev-parse --show-toplevel)/.codex/hooks/stop_continue.py\"",
"timeout": 30
}
]
}
]
}
}
設定時の注意点は次のとおりです。
descriptionはhooks.jsonファイルのトップレベルに指定できる任意のメタデータです。実行されるフックには影響しません。timeoutの単位は秒です。timeoutを省略すると、ほとんどのフックで600秒が使われます。SessionEndとInterruptはデフォルトが1秒で、最大3秒まで設定できます。
statusMessageは省略できます。additionalContextLimitは、コマンドフックがモデルに直接送れるadditionalContextの量を指定します。この量を超えると、Codex は全文をディスクに保存し、短いプレビューをモデルに送ります。「大きなフック出力」を参照してください。commandWindowsを指定すると、Windows でのみコマンドを上書きできます。TOML ではcommand_windowsまたはcommandWindowsを使います。asyncをtrueに設定すると、コマンドフックをバックグラウンドで実行できます。commandとmcp_toolのハンドラーに対応しています。promptとagentのハンドラーは解析されますが、実行はスキップされます。- コマンドはセッションの
cwdを作業ディレクトリとして実行されます。 - リポジトリローカルのフックでは、
.codex/hooks/...のような相対パスを直接使うよりも、Git のルートを基準にパスを解決することをおすすめします。Codex をサブディレクトリから起動しても、フックの場所を正しく特定できます。
config.toml にインライン TOML で記述する場合の例です。
[[hooks.SessionStart]]
matcher = "^compact$"
[[hooks.SessionStart.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/session_start.py"'
additionalContextLimit = 5000
[[hooks.PreToolUse]]
matcher = "^Bash$"
[[hooks.PreToolUse.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/pre_tool_use_policy.py"'
timeout = 30
statusMessage = "Checking Bash command"
[[hooks.PostToolUse]]
matcher = "^Bash$"
[[hooks.PostToolUse.hooks]]
type = "command"
command = '/usr/bin/python3 "$(git rev-parse --show-toplevel)/.codex/hooks/post_tool_use_review.py"'
timeout = 30
statusMessage = "Reviewing Bash output"
MCP ツールフック
MCP ツールフックを使うと、ライフサイクルイベントに応じて、接続済みの MCP サーバーのツールを呼び出せます。フックは構造化された引数をツールに直接送ります。信頼設定の確認手順と出力仕様はコマンドフックと同じです。
MCP ツールフックの設定
次のフックは、Codex がファイルに書き込んだりファイルを編集したりした後で、scanner MCP サーバーに各パッチのスキャンを依頼します。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "mcp_tool",
"server": "scanner",
"tool": "scan_patch",
"input": { "patch": "${tool_input.command}" },
"timeout": 30,
"statusMessage": "Scanning edited files"
}
]
}
]
}
}
| フィールド | 説明 |
|---|---|
type |
mcp_tool を指定します。 |
server |
接続済みの MCP サーバーの名前です。必須です。 |
tool |
そのサーバーが公開するツールの名前です。必須です。 |
input |
引数のテンプレートを含む任意の JSON オブジェクトです。デフォルトは {} です。 |
timeout |
実行時間の上限を秒単位で指定します。省略すると 600 秒になります。 |
statusMessage |
フックの実行中に表示する任意のメッセージです。 |
フックイベントの値を使った引数の展開
${field.nested} のようにドットで区切って、フックイベントのフィールドを参照します。値全体がプレースホルダーの場合は、元の JSON 型が保持されます。文字列の一部にプレースホルダーがある場合は、テキストとして展開されます。Codex はオブジェクトと配列を再帰的に展開します。
イベントに {"tool_input":{"file_path":"src/main.rs","count":3}} が含まれている場合の引数テンプレートの例です。
{
"path": "${tool_input.file_path}",
"count": "${tool_input.count}",
"message": "Scanning ${tool_input.file_path}"
}
このテンプレートは次のように展開されます。
{
"path": "src/main.rs",
"count": 3,
"message": "Scanning src/main.rs"
}
実行とライフサイクル
- フックは既存の MCP 接続を使います。サーバーの起動や再接続は行いません。
- ツールがブロックの判断を返すと、フックは操作をブロックできます。エラーが発生した場合、サーバーが見つからない場合、ツールを利用できない場合は、操作はブロックされません。
- MCP ツールフックは同期的に実行されます。ツールの承認を求めたり、他のフックを起動したりすることはありません。
- フックとサーバーのタイムアウトのうち、短い方が適用されます。MCP の入力要求への応答を待つ時間は、タイムアウトに含まれません。
SessionStartフックは MCP サーバーの準備が整う前に実行されることがあります。その場合もセッションをブロックしません。SessionEndは MCP ツールフックに対応していません。
フックの無効化
フックはデフォルトで有効です。無効にするには、config.toml に次の設定を追加します。
[features]
hooks = false
機能キーには hooks を使います。codex_hooks も別名として使えますが、非推奨です。管理者は同様に requirements.toml で [features].hooks = false を設定して、フックを強制的に無効にできます。
requirements.toml によるフックの管理
タスクの実行を制御する環境に合わせてフックを選んでください。
クラウドオーケストレーションで使えるフック
管理ポリシーとリモートフックが有効なワークスペースでは、ローカルコンピューターへのアクセスが有効な Work クラウドと dot は、対応するタスクイベントやツールイベントの発生時に MCP サービスを呼び出せます。これらの呼び出しには、ワークスペース管理者が設定した mcp_tool ハンドラーを使います。設定場所は Agent Security です。ローカルコンピューターへのアクセスがない Work クラウドや個人アカウントでは、これらのエンタープライズ向けフックは使われません。
クラウドでオーケストレーションを行う場合、接続先のコンピューターでツールを実行するときも、使えるのはグローバル MCP フックのみです。コマンド、プロンプト、エージェントの各ハンドラー、ローカル設定・プラグイン・ローカルディレクトリで定義したフック、環境単位のフック、SessionEnd の MCP フックには対応していません。オーケストレーションと実行の両方をローカルで行う場合、ローカルのみの Work および Codex スレッドでは、従来から対応しているフックを引き続き使えます。
対応するフックが明示的に拒否を返すと、操作をブロックできます。PreToolUse でエラーやタイムアウトが発生したり、不正な形式の応答が返ったりした場合は、ツールがそのまま実行されることがあります。MCP フックで記録できるのは監査証跡の一部です。導入時の確認事項と監査できる範囲は「フックとネットワークの互換性の確認」を参照してください。
ローカルの Codex で使う管理対象フック
ローカルの Codex で使うフックは、[hooks] テーブルに定義します。このテーブルは requirements.toml に記述します。ローカルでフックを無効にしたユーザーにも管理対象フックを適用するには、[features].hooks = true を requirements.toml に固定し、同じファイルに [hooks] を定義します。管理者が管理するフックを許可しつつ、ユーザー、プロジェクト、セッション、プラグインで定義したフックを無視するには、allow_managed_hooks_only = true を設定します。
allow_managed_hooks_only = true
[features]
hooks = true
[hooks]
managed_dir = "/enterprise/hooks"
windows_managed_dir = 'C:\enterprise\hooks'
[[hooks.PreToolUse]]
matcher = "^Bash$"
[[hooks.PreToolUse.hooks]]
type = "command"
command = "python3 /enterprise/hooks/pre_tool_use_policy.py"
command_windows = 'py -3 C:\enterprise\hooks\pre_tool_use_policy.py'
timeout = 30
statusMessage = "Checking managed Bash command"
管理対象フックの注意点は次のとおりです。
managed_dirは macOS と Linux で使われます。windows_managed_dirは Windows で使われます。- Codex は
managed_dir内のスクリプトを配布しません。企業の管理ツールで別途インストールし、更新する必要があります。 - 管理対象フックのコマンドでは、設定した管理ディレクトリ内のスクリプトを絶対パスで指定してください。
allow_managed_hooks_only = trueを設定すると、ユーザー、プロジェクト、セッション、プラグインで定義したフックはスキップされます。requirements.tomlなどの管理対象の設定レイヤーで定義したフックは引き続き読み込まれます。
プラグインに同梱するフック
プラグインを有効にすると、Codex はそのプラグインのライフサイクルフックを、ユーザー、プロジェクト、管理対象の各フックと一緒に読み込めます。
デフォルトでは、Codex はプラグインのルートディレクトリ内で hooks/hooks.json を探します。プラグインマニフェストの hooks エントリを .codex-plugin/plugin.json に定義すると、このデフォルトを上書きできます。エントリには、./ で始まるパス、./ で始まるパスの配列、インラインのフックオブジェクト、またはインラインのフックオブジェクトの配列を指定できます。
{
"name": "repo-policy",
"hooks": "./hooks/hooks.json"
}
マニフェスト内のフックのパスは、プラグインのルートディレクトリを基準に解決されます。ルートの外を指すことはできません。マニフェストに hooks が定義されている場合、Codex はデフォルトの hooks/hooks.json の代わりに、マニフェストのエントリを使います。
プラグインのフックコマンドでは、次の環境変数を利用できます。
PLUGIN_ROOTは Codex 独自の拡張で、インストール済みプラグインのルートディレクトリを指します。PLUGIN_DATAは Codex 独自の拡張で、プラグインが書き込めるデータディレクトリを指します。- 既存のプラグインフックとの互換性を保つため、Codex は
CLAUDE_PLUGIN_ROOTとCLAUDE_PLUGIN_DATAも設定します。
プラグインのフックは、他のフックと同じイベントスキーマを使います。実行前にフックを確認し、信頼するように設定してください。CLI では /hooks を開きます。デスクトップアプリでは、コンポーザーでフックを確認を選択するか、設定 > フックを開きます。プラグインの更新で同梱スクリプトが変更された場合、フック定義に変更がなくても、Codex は再度確認を求めます。
マッチャーパターン
matcher フィールドは、フックの実行条件を絞り込む正規表現文字列です。対応するイベントが発生するたびに一致させるには、"*" または "" を指定するか、matcher を省略します。
現在、Codex のイベントのうち matcher を使うのは一部だけです。
| イベント | matcher の対象 |
備考 |
|---|---|---|
PermissionRequest |
ツール名 | Bash、apply_patch*、MCP ツール名などに対応しています。 |
PostToolUse |
ツール名 | 「対応ツール」を参照してください。 |
PostCompact |
コンパクションのトリガー | 値は manual または auto です。 |
PreModelRequest、PostModelRequest |
非対応 | どちらもモデルへのリクエストを試行するたびに実行されます。 |
PreCompact |
コンパクションのトリガー | 値は manual または auto です。 |
PreToolUse |
ツール名 | 「対応ツール」を参照してください。 |
SessionEnd |
終了理由 | 現在は other のみです。 |
SessionStart |
開始のきっかけ | 値は startup、resume、clear、compact、fork です。 |
SubagentStart |
サブエージェントの種類 | 開始するサブエージェントによって値が決まります。 |
SubagentStop |
サブエージェントの種類 | 停止するサブエージェントによって値が決まります。 |
UserPromptSubmit |
非対応 | このイベントでは、設定した matcher は無視されます。 |
Stop |
非対応 | このイベントでは、設定した matcher は無視されます。 |
Interrupt |
非対応 | このイベントでは、設定した matcher は無視されます。 |
* apply_patch の場合、matcher の値には Edit または Write も使えます。
パターンの例を示します。
Bash^apply_patch$Edit|Writemcp__filesystem__read_filemcp__filesystem__.*startup|resume|clear|compact|forkmanual|auto
対応ツール
PreToolUse と PostToolUse は、シェルや MCP 以外の呼び出しも検出できます。ほとんどのローカル関数ツールは同じフック処理を経由するため、ツール名との照合や JSON 引数の確認ができます。PreToolUse では呼び出しのブロックや書き換えもできます。
| ツールの実行経路 | PreToolUse |
PostToolUse |
備考 |
|---|---|---|---|
| シェルコマンド | 対応 | 対応 | Bash に一致します。 |
統合実行(exec_command) |
対応 | 対応 | Bash に一致します。その後の write_stdin によるポーリングで、元のコマンドの完了時にそのコマンドの PostToolUse が通知されることがあります。 |
apply_patch |
対応 | 対応 | apply_patch、Edit、Write に一致します。 |
| MCP ツール | 対応 | 対応 | mcp__filesystem__read_file などの MCP ツール名に一致します。 |
| その他のローカル関数ツール | 対応 | 対応 | update_plan などの関数ツール名に一致します。spawn_agent は Agent にも一致します。 |
WebSearch などのホスト型ツール |
非対応 | 非対応 | ローカル関数ツールのフック処理を経由しません。 |
write_stdin は既存の統合実行セッションと通信するためのツールです。PreToolUse を通過したコマンドに入力を送信したり、そのコマンドをポーリングしたりしても、PreToolUse は再実行されません。
一部の特殊なツールでは、デフォルトのフック処理を経由しない場合があります。ツールフックは操作を制限する手段の一つですが、すべての実行経路に制限を強制できるわけではありません。
共通の入力フィールド
各コマンドフックは stdin で 1 つの JSON オブジェクトを受け取ります。
よく使う共通フィールドは次のとおりです。
| フィールド | 型 | 説明 |
|---|---|---|
session_id |
string |
現在の Codex セッションの ID です。サブエージェントのフックでは親セッションの ID を使います。 |
transcript_path |
string | null |
セッションの会話記録ファイルがある場合は、そのパスです。 |
cwd |
string |
セッションの作業ディレクトリです。 |
hook_event_name |
string |
現在のフックイベント名です。 |
model |
string |
Codex 独自の拡張です。使用中のモデルのスラッグを示します。 |
ターン単位で実行されるフックでは、Codex 独自の拡張である turn_id をイベント別の表に記載しています。
SessionStart、PreToolUse、PermissionRequest、PostToolUse、UserPromptSubmit、SubagentStart、SubagentStop、Stop、Interrupt には permission_mode も含まれます。現在の権限モードを default、acceptEdits、plan、dontAsk、bypassPermissions のいずれかで示します。
transcript_path を使うとチャットの会話記録を参照できます。ただし、会話記録の形式はフック向けの安定したインターフェースではなく、今後変更される可能性があります。
通信時のデータ形式の詳細は「スキーマ」を参照してください。
共通の出力フィールド
SessionStart、PreCompact、PostCompact、UserPromptSubmit、SubagentStop、Stop は、次の共通 JSON フィールドに対応しています。SubagentStart でも systemMessage とフック固有のコンテキストに同じ形式を使えますが、continue: false を返してもサブエージェントは停止しません。
{
"continue": true,
"stopReason": "optional",
"systemMessage": "optional",
"suppressOutput": false
}
| フィールド | 動作 |
|---|---|
continue |
false の場合、そのフックの実行を停止済みとして記録します。 |
stopReason |
停止理由として記録されます。 |
systemMessage |
UI またはイベントストリームに警告として表示されます。 |
suppressOutput |
現在は解析のみ行い、機能はまだ実装されていません。 |
出力なしで終了コード 0 を返すと成功として扱われ、Codex は処理を続行します。
PreToolUse と PermissionRequest は systemMessage に対応していますが、現時点では continue、stopReason、suppressOutput には対応していません。PreToolUse フックがこれらの非対応フィールドを返すと、Codex はそのフックの実行を失敗として記録し、エラーを報告してツール呼び出しを続行します。
PostToolUse は systemMessage、continue: false、stopReason に対応しています。suppressOutput は解析されますが、このイベントでは現時点でサポートされていません。
大きなフック出力
デフォルトでは、Codex がモデルに渡すフック出力は、メッセージごとに約 2,500 トークンまでです。出力が上限を超えると、Codex は全文を <temp_dir>/hook_outputs/<session_id>/<uuid>.txt に保存し、テキストの先頭と末尾を抜粋したプレビューと保存先のパスをモデルに渡します。この動作をスピリングと呼びます。上限を超えた出力をディスクに保存し、モデルに渡す内容を短いプレビューに置き換える仕組みです。ファイルに書き込めない場合でも、モデルには短縮したプレビューが渡されます。
フックやプラグインから渡すコンテキストは簡潔にしてください。複数のフックやプラグインのコンテキストが積み重なると、モデルの性能が低下することがあります。additionalContextLimit を引き上げると、このリスクが高まります。フック自体が出力量を厳密に制限している場合を除き、上限を 0 に設定しないでください。1 つのフックでコンテキストウィンドウ全体を使い切るおそれがあります。
additionalContext を返すコマンドフックでは、ハンドラーに additionalContextLimit を設定して、目安となるトークン数のしきい値を変更できます。
{
"type": "command",
"command": "python3 ~/.codex/hooks/session_start.py",
"additionalContextLimit": 5000
}
additionalContextLimit を省略すると、デフォルトのしきい値である 2500 トークンが使われます。しきい値を変更するには正の整数を指定します。0 を指定すると、ハンドラーの追加コンテキストの全文がモデルに直接渡されます。Codex は一致するハンドラーごとに個別に判定します。追加コンテキストを生成できないイベントでは、Codex は additionalContextLimit を無視し、設定に関する警告を表示します。
この設定は additionalContext にのみ適用されます。ツールのフィードバックと続行用のプロンプトにはデフォルトの上限が適用されます。
上限を超えた出力はディスクに保存されることがあるため、フックの出力にシークレットやその他の機密データを含めないでください。
フックのバックグラウンド実行
デフォルトでは、Codex はコマンドフックの完了を待ってから、フックを起動した操作を続行します。async を true に設定すると、Codex が操作を続行する間、コマンドフックがバックグラウンドで実行されます。
バックグラウンドフックの設定
"async": true を hooks.json のコマンドハンドラーに追加します。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 ~/.codex/hooks/post_tool_use.py",
"async": true,
"timeout": 120
}
]
}
]
}
}
config.toml のインラインフックでは、async = true を設定します。
[[hooks.PostToolUse]]
matcher = "Bash"
[[hooks.PostToolUse.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/post_tool_use.py"
async = true
timeout = 120
バックグラウンドフックの入力、マッチャー、信頼設定の確認、タイムアウト、大きな出力の処理は、同期コマンドフックと同じです。他のコマンドフックと同様に、timeout の単位は秒で、デフォルトは 600 です。Interrupt フックのタイムアウトは、バックグラウンド実行時もデフォルトで 1 秒、最大で 3 秒です。
バックグラウンドフックの動作
バックグラウンドフックが完了すると、Codex は対応する形式の情報出力を、会話中の次の安全なタイミングで渡します。
- ターンが進行中の場合は、現在のモデルリクエストとツール呼び出しが完了するまで待ち、そのターンの次のモデルリクエストで出力を利用できるようにします。
- ターンが進行中でない場合は、ユーザーが次のターンを開始するまで待ちます。バックグラウンドフックの完了によって新しいターンが始まることはありません。
イベント別の JSON 出力形式は同期フックと同じです。Codex は additionalContext をモデルのコンテキストに追加し、systemMessage を警告として表示します。
バックグラウンドフックでは、起動元の操作をブロックしたり、承認したり、書き換えたりすることはできません。その他の方法でその操作を制御することもできません。ツールポリシーの適用、権限の判断、プロンプトの拒否、ターンの続行には同期フックを使ってください。
制限事項
- Codex がセッションごとに並行して実行できるバックグラウンドフックは最大 8 個です。それを超えるフックは、実行中のフックが完了するまで待機します。
- 条件に一致した呼び出しはそれぞれ独立して実行されます。バックグラウンドフックの完了順は起動順と異なる場合があります。
- セッションが終了すると、Codex は未完了のバックグラウンドフックをキャンセルし、まだ渡していない出力を破棄します。
SessionEndフックは常に同期的に実行されます。
フック
SessionStart
このイベントでは、matcher は source に適用されます。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
source |
string |
セッションの開始方法です。startup、resume、clear、compact、fork のいずれかです。 |
フォークしたスレッドでは source: "fork" が使われます。履歴を指定してスレッドを再開した場合は、引き続き source: "resume" が使われます。
stdout に出力したプレーンテキストは、開発者コンテキストに追加されます。
stdout に出力する JSON では、共通の出力フィールドと次のフック固有の形式を使えます。
{
"hookSpecificOutput": {
"hookEventName": "SessionStart",
"additionalContext": "Load the workspace conventions before editing."
}
}
この additionalContext のテキストは、開発者コンテキストに追加されます。
Codex がルートセッションのコンパクションを行った後、SessionStart フックのうち source: "compact" に一致するものが、次のモデルリクエストの前に実行されます。ターンの途中で自動コンパクションが行われた場合も同様です。Codex は次のユーザーターンを待たず、直後の続行処理にフックの追加コンテキストを渡します。フックが continue: false を返すと、Codex は次のモデルリクエストを送信せずにターンを終了します。
SessionEnd
SessionEnd を使うと、セッションの終了時にコマンドを実行して、最後のメモを保存したり、ファイルを整理したりできます。開いている会話をアーカイブまたは削除したとき、Codex が正常に終了したとき、あるいは会話がアイドル状態で、接続中のどのクライアントでも開かれていない状態が 30 分続いたときに、メインスレッドで実行されます。サブエージェントでは実行されません。
別の会話に切り替えたり thread/unsubscribe を呼び出したりしても、セッションはすぐには終了しないため、SessionEnd もすぐには実行されません。フックは実行中もセッションの会話記録を読み取れます。
このイベントでは、matcher は reason に適用されます。現在、reason は常に other です。matcher を省略するか other を指定すると、すべての SessionEnd イベントで実行されます。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
reason |
string |
セッションの終了理由です。値は other です。 |
たとえば、SessionEnd のコマンドは次の入力を受け取ります。
{
"session_id": "thr_123",
"transcript_path": "/workspace/.codex/rollout.jsonl",
"cwd": "/workspace",
"hook_event_name": "SessionEnd",
"reason": "other"
}
SessionEnd フックは、async が true でも常に同期的に実行されます。出力は参考情報として扱われ、Codex の動作を変えたり、スレッドを開いたままにしたりすることはできません。コマンドがタイムアウトするかエラーで終了すると、Codex はフックの失敗として報告します。
SubagentStart
このイベントでは、matcher は agent_type に適用されます。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
turn_id |
string |
Codex 独自の拡張です。進行中の Codex ターンの ID を示します。 |
agent_id |
string |
サブエージェントの識別子です。 |
agent_type |
string |
サブエージェントの種類またはプロファイルです。 |
permission_mode |
string |
現在の権限モードです。 |
stdout に出力したプレーンテキストは、サブエージェントの開発者コンテキストに追加されます。
stdout に出力する JSON では、systemMessage と次のフック固有の形式を使えます。
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Review the repository test conventions first."
}
}
この additionalContext のテキストは、サブエージェントの開発者コンテキストに追加されます。continue: false は互換性のために解析されますが、サブエージェントの起動を止めることはできません。
PreToolUse
PreToolUse は、Bash、apply_patch によるファイル編集、MCP ツールの呼び出し、その他のローカル関数ツールの実行に先立って処理に介入できます。対応する実行経路と例外は「対応ツール」を参照してください。
matcher は tool_name とマッチャー用の別名に適用されます。apply_patch によるファイル編集では、matcher の値に apply_patch、Edit、Write を使えます。どれを使っても、フックの入力には tool_name: "apply_patch" が含まれます。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
turn_id |
string |
Codex 独自の拡張です。進行中の Codex ターンの ID を示します。 |
tool_name |
string |
フックで使う正式なツール名です。Bash、apply_patch、mcp__fs__read のような MCP ツール名などがあります。 |
tool_use_id |
string |
今回のツール呼び出しの ID です。 |
tool_input |
JSON value |
ツール固有の入力です。Bash と apply_patch は tool_input.command を使います。MCP ツールやその他のローカル関数ツールは引数を送ります。 |
stdout に出力したプレーンテキストは無視されます。
stdout に出力する JSON では systemMessage を使えます。対応するツール呼び出しを拒否するには、次のフック固有の形式で返します。
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by hook."
}
}
Codex は、ブロックを指定する次の旧形式にも対応しています。
{
"decision": "block",
"reason": "Destructive command blocked by hook."
}
終了コード 2 を使い、ブロックの理由を stderr に書き込むこともできます。
呼び出しをブロックせずにモデルにコンテキストを追加するには、hookSpecificOutput.additionalContext を返します。
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "The pending command touches generated files."
}
}
対応するツール呼び出しをブロックせずに書き換えるには、permissionDecision: "allow" とともに updatedInput を返します。
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"updatedInput": {
"command": "echo rewritten"
}
}
}
Bash コマンドと apply_patch の場合、updatedInput には文字列型の command フィールドが必要です。MCP ツールやその他のローカル関数ツールの場合、updatedInput には置き換え後の引数オブジェクトを指定します。updatedInput は permissionDecision: "allow" と組み合わせた場合にのみ返してください。それ以外の形式で updatedInput を返すとエラーが報告されます。
permissionDecision: "ask"、旧形式の decision: "approve"、continue: false、stopReason、suppressOutput は解析されますが、まだサポートされていません。これらを返すと、Codex はフックの実行を失敗として記録し、エラーを報告してツール呼び出しを続行します。
PermissionRequest
PermissionRequest は、シェルの権限昇格や管理対象ネットワークへのアクセスなどについて、Codex が承認を求める直前に実行されます。リクエストを許可または拒否することも、判断を見送って通常の承認プロンプトに進むこともできます。承認が不要なコマンドでは実行されません。
matcher は tool_name とマッチャー用の別名に適用されます。現在の正式な値には Bash、apply_patch、mcp__server__tool のような MCP ツール名があります。apply_patch は Edit と Write にも一致します。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
turn_id |
string |
Codex 独自の拡張です。進行中の Codex ターンの ID を示します。 |
tool_name |
string |
フックで使う正式なツール名です。Bash、apply_patch、mcp__fs__read のような MCP ツール名などがあります。 |
tool_input |
JSON value |
ツール固有の入力です。Bash と apply_patch は tool_input.command を使います。MCP ツールはすべての引数を送ります。 |
tool_input.description |
string | null |
Codex が用意できる場合は、承認を求める理由を人が読める形で示します。 |
stdout に出力したプレーンテキストは無視されます。
ツールの入力には、人が読める説明が含まれる場合があります。ただし、すべてのツールに tool_input.description フィールドがあることを前提にしないでください。
リクエストを承認するには、次のように返します。
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow"
}
}
}
リクエストを拒否するには、次のように返します。
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "deny",
"message": "Blocked by repository policy."
}
}
}
一致する複数のフックが判断を返した場合、1 つでも deny があれば拒否が優先されます。拒否がなく、いずれかが allow を返した場合は、承認プロンプトを表示せずにリクエストを続行します。一致するフックがどれも判断を返さない場合は、Codex の通常の承認フローに進みます。
updatedInput、updatedPermissions、interrupt を PermissionRequest で返さないでください。これらは将来の機能向けに予約されたフィールドで、現在は返すとリクエストが拒否されます。
PostToolUse
PostToolUse は、Bash、apply_patch、MCP ツールの呼び出し、その他のローカル関数ツールなど、対応するツールが出力を返した後に実行されます。Bash の場合、コマンドがゼロ以外のステータスで終了しても実行されます。すでに実行したツールの副作用を取り消すことはできません。対応する実行経路と例外は「対応ツール」を参照してください。
matcher は tool_name とマッチャー用の別名に適用されます。apply_patch によるファイル編集では、matcher の値に apply_patch、Edit、Write を使えます。どれを使っても、フックの入力には tool_name: "apply_patch" が含まれます。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
turn_id |
string |
Codex 独自の拡張です。進行中の Codex ターンの ID を示します。 |
tool_name |
string |
フックで使う正式なツール名です。Bash、apply_patch、mcp__fs__read のような MCP ツール名などがあります。 |
tool_use_id |
string |
今回のツール呼び出しの ID です。 |
tool_input |
JSON value |
ツール固有の入力です。Bash と apply_patch は tool_input.command を使います。MCP ツールやその他のローカル関数ツールは引数を送ります。 |
tool_response |
JSON value |
ツール固有の出力です。MCP ツールは MCP 呼び出しの結果を送ります。その他のローカル関数ツールは通常、モデルに渡す出力を送ります。 |
stdout に出力したプレーンテキストは無視されます。
stdout に出力する JSON では systemMessage を使えます。このフック固有の出力形式は次のとおりです。
{
"decision": "block",
"reason": "The Bash output needs review before continuing.",
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "The command updated generated files."
}
}
この additionalContext のテキストは、開発者コンテキストに追加されます。
このイベントで decision: "block" を返しても、完了した Bash コマンドの実行は取り消されません。Codex はフィードバックを記録し、ツールの結果をそのフィードバックで置き換えて、フックが返したメッセージからモデルの処理を続行します。
終了コード 2 を使い、フィードバックの理由を stderr に書き込むこともできます。
コマンドの実行後に、元のツール結果に対する通常の処理を止めるには、continue: false を返します。Codex はツール結果をフックのフィードバックまたは停止理由のテキストで置き換え、そこから処理を続行します。
updatedMCPToolOutput と suppressOutput は解析されますが、まだサポートされていません。これらを返すと、Codex はフックの実行を失敗として記録し、エラーを報告して、ツール結果に対する通常の処理を続行します。
コードモードでのツール呼び出し
モデルがコードモードで JavaScript からツールを呼び出すと、フックの判断はそのネストされた呼び出しに適用されます。PreToolUse はツールの実行前に呼び出しを止めたり、入力を書き換えたりできます。PostToolUse でブロックしてもツールの副作用は取り消せませんが、元の結果が実行中のスクリプトに渡るのを防げます。
| フックの結果 | コードモードでの動作 |
|---|---|
PreToolUse がブロック |
ツールが実行される前に、ツール呼び出しの Promise が拒否されます。 |
PreToolUse が updatedInput を返す |
ツールは書き換え後の入力で実行され、Promise はその結果で解決されます。 |
PostToolUse が decision: "block" を返すか、終了コード 2 で終了 |
ツールの実行後、フックが示した理由で Promise が拒否されます。 |
PostToolUse が continue: false を返す |
Codex はモデルに渡す結果にフックのフィードバックを使いますが、ネストされたツール呼び出しの Promise は拒否しません。 |
PreModelRequest と PostModelRequest
これらのフックを使うと、同じターン内での再試行も含め、モデルへのリクエストを試行ごとに記録できます。PreModelRequest は各試行の前に実行されます。PostModelRequest はその試行の結果を報告します。どちらのフックもモデルと turn_id を受け取ります。agent_id と agent_type も、取得できる場合は渡されます。フックの出力は診断専用です。モデルのコンテキストを変更したり、リクエストをブロックしたりすることはできません。
PostModelRequest には、さらに次の 3 つのフィールドがあります。
| フィールド | 説明 |
|---|---|
status |
completed、failed、cancelled のいずれかです。 |
error |
エラーメッセージです。取得できない場合は null です。 |
token_usage |
その試行で使用したトークン数です。取得できない場合は null です。 |
PreCompact
PreCompact は、Codex がチャットのコンパクションを行う前に実行されます。matcher は trigger に適用されます。値は manual または auto です。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
turn_id |
string |
Codex 独自の拡張です。進行中の Codex ターンの ID を示します。 |
trigger |
string |
コンパクションのきっかけです。値は manual または auto です。 |
stdout に出力したプレーンテキストは無視されます。
stdout に出力する JSON では、共通の出力フィールドを使えます。一致する PreCompact フックが continue: false を返すと、Codex はコンパクションの前に停止します。
PostCompact
PostCompact は、Codex がチャットのコンパクションを行った後に実行されます。matcher は trigger に適用されます。値は manual または auto です。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
turn_id |
string |
Codex 独自の拡張です。進行中の Codex ターンの ID を示します。 |
trigger |
string |
コンパクションのきっかけです。値は manual または auto です。 |
stdout に出力したプレーンテキストは無視されます。
stdout に出力する JSON では、共通の出力フィールドを使えます。一致する PostCompact フックが continue: false を返すと、Codex はコンパクションの後に停止します。
UserPromptSubmit
現在、このイベントでは matcher は使われません。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
turn_id |
string |
Codex 独自の拡張です。進行中の Codex ターンの ID を示します。 |
prompt |
string |
送信直前のユーザープロンプトです。 |
stdout に出力したプレーンテキストは、開発者コンテキストに追加されます。
stdout に出力する JSON では、共通の出力フィールドと次のフック固有の形式を使えます。
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "Ask for a clearer reproduction before editing files."
}
}
この additionalContext のテキストは、開発者コンテキストに追加されます。
プロンプトをブロックするには、次のように返します。
{
"decision": "block",
"reason": "Ask for confirmation before doing that."
}
終了コード 2 を使い、ブロックの理由を stderr に書き込むこともできます。
SubagentStop
このイベントでは、matcher は agent_type に適用されます。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
turn_id |
string |
Codex 独自の拡張です。進行中の Codex ターンの ID を示します。 |
agent_id |
string |
サブエージェントの識別子です。 |
agent_type |
string |
サブエージェントの種類またはプロファイルです。 |
agent_transcript_path |
string | null |
サブエージェントの会話記録ファイルがある場合は、そのパスです。 |
stop_hook_active |
boolean |
このサブエージェントがすでに続行されたかどうかを示します。 |
last_assistant_message |
string | null |
サブエージェントの直近のアシスタントメッセージがある場合は、その内容です。 |
SubagentStop フックの stdout 出力は、終了コード 0 を返す場合は JSON 形式である必要があります。このイベントではプレーンテキスト出力は無効です。
stdout に出力する JSON では、共通の出力フィールドを使えます。サブエージェントの処理を続行するよう Codex に求めるには、次のように返します。
{
"decision": "block",
"reason": "Run one more focused pass inside the subagent."
}
終了コード 2 を使い、続行する理由を stderr に書き込むこともできます。
一致する SubagentStop フックのいずれかが continue: false を返した場合は、他の一致する SubagentStop フックが続行を求めても、停止が優先されます。
Stop
現在、このイベントでは matcher は使われません。
共通の入力フィールドに加え、次のフィールドがあります。
| フィールド | 型 | 説明 |
|---|---|---|
turn_id |
string |
Codex 独自の拡張です。進行中の Codex ターンの ID を示します。 |
stop_hook_active |
boolean |
このターンが Stop によってすでに続行されたかどうかを示します。 |
last_assistant_message |
string | null |
直近のアシスタントメッセージがある場合は、その内容です。 |
Stop フックの stdout 出力は、終了コード 0 を返す場合は JSON 形式である必要があります。このイベントではプレーンテキスト出力は無効です。
stdout に出力する JSON では、共通の出力フィールドを使えます。Codex に処理を続行させるには、次のように返します。
{
"decision": "block",
"reason": "Run one more pass over the failing tests."
}
終了コード 2 を使い、続行する理由を stderr に書き込むこともできます。
このイベントで decision: "block" を返すと、ターンは拒否されず、Codex は処理を続行します。指定した reason を本文にして、新しいユーザープロンプトとして扱われる続行用のプロンプトが自動的に作成されます。
一致する Stop フックのいずれかが continue: false を返した場合は、他の一致する Stop フックが続行を求めても、停止が優先されます。
Interrupt
Interrupt は、メインスレッドで進行中のターンを中断したときに実行されます。中断を記録したり、フックが開始した作業を後片付けしたりするために使えます。アイドル状態のスレッドやサブエージェントでは実行されず、設定した matcher は無視されます。
このイベントには、共通の入力フィールドに加え、中断したターンの ID を示す turn_id と permission_mode が含まれます。
コマンドフックのタイムアウトはデフォルトで 1 秒です。設定できる範囲は 1 秒から 3 秒までです。フックの出力によって中断を阻止したり、ターンを再開したりすることはできません。出力なしで終了コード 0 を返すか、JSON を返してください。警告を表示するには、JSON に任意の systemMessage を含めます。このイベントではプレーンテキスト出力は無効です。
{ "systemMessage": "Saved the interrupted turn to the local audit log." }
スキーマ
リンク先の main ブランチのスキーマには、現在のリリースに含まれていないフックフィールドがある場合があります。リリース版の動作は、このページを参照してください。
現在の通信データ形式を正確に確認するには、Codex の GitHub リポジトリにある生成済みスキーマを参照してください。