factsCodexhooks

stable4 日前 · 2026-08-09

Hooks

概要

Codex の agentic loop に自前スクリプトを差し込む拡張フレームワーク。ログ収集、プロンプトの検査、ターン終了時の検証、ディレクトリごとのプロンプト調整などに使う。既定で有効。

仕様

実行時の挙動

  • 複数のファイルから一致した hook はすべて実行される
  • 同一イベントに一致する複数の command hook は並行して起動される。ある hook が別の hook の起動を止めることはできない
  • managed でない command hook は、実行前にレビューと信頼付与が必要

イベントの発火タイミング

タイミングイベント
ターン中PreToolUsePermissionRequestPostToolUsePreCompactPostCompactUserPromptSubmitSubagentStopStop
セッション/subagent の開始時SessionStartSubagentStart
メインスレッドの終了時SessionEnd(subagent では実行されない)

定義場所

有効な config レイヤーの隣にある次のいずれかの形式で発見される。

  • hooks.json
  • config.toml 内のインライン [hooks] テーブル

実際に使う主な場所:

  • ~/.codex/hooks.json

  • ~/.codex/config.toml

  • <repo>/.codex/hooks.json

  • <repo>/.codex/config.toml

  • 複数の hook ソースがある場合、一致するものをすべて読み込む。優先度の高い config レイヤーが低いレイヤーの hook を置き換えることはない

  • 同一レイヤーに hooks.json とインライン [hooks] の両方があると両者をマージし、起動時に警告する。1 レイヤーにつき 1 表現を推奨

  • project-local の hook は、プロジェクトの .codex/ レイヤーが trusted のときだけ読み込まれる。untrusted なプロジェクトでも user / system の hook はそれぞれの有効な config レイヤーから読み込まれる

  • 有効な plugin がバンドルする hook も、他のソースと並んで読み込まれる

レビューと信頼

  • managed でない command hook は、その定義そのものをレビューして信頼するまで実行されない
  • 信頼は hook の現在のハッシュに対して記録される。新規または変更された hook は review 対象としてマークされ、信頼するまでスキップされる
  • /hooks で hook ソースの確認、レビュー、信頼付与、managed でない hook の個別無効化を行う。起動時にレビュー待ちがあると /hooks を開くよう警告が出る
  • system / MDM / cloud / requirements.toml 由来の managed hook は managed かつポリシーで信頼済みとして扱われ、ユーザーの hook ブラウザからは無効化できない
  • --dangerously-bypass-hook-trust を渡すと、その呼び出しに限り永続的な信頼なしに有効な hook を実行する

設定の構造

3 段のネストで定義する。

  1. hook event(PreToolUsePostToolUsePreCompactSubagentStartStop など)
  2. そのイベントの発火条件を決める matcher group
  3. 一致したときに動く hook handler
フィールド説明
descriptionhooks.json ファイルのトップレベルの任意メタデータ。どの hook が動くかには影響しない
timeout秒。省略時はほとんどの hook で 600 秒。SessionEnd は既定 1 秒で、上限は 3
statusMessage任意。実行中に表示するメッセージ
additionalContextLimitcommand hook が additionalContext としてモデルへ送れる量のしきい値
commandWindowsWindows 専用のコマンド上書き(任意)。TOML では command_windows または commandWindows
asyncパースはされるが、非同期 command hook は未対応
  • 現時点で動く handler は type: "command" のみ。promptagent はパースされるがスキップされる
  • コマンドはセッションの cwd を作業ディレクトリとして実行される
  • repo-local の hook では、.codex/hooks/... のような相対パスではなく git root から解決することが推奨されている(サブディレクトリから起動されうるため)

無効化

config.toml で次のように設定する。

[features]
hooks = false
  • 正式なフィーチャーキーは hookscodex_hooksdeprecated なエイリアスとして今も動く
  • 管理者は requirements.toml[features].hooks = false で同様に強制的に無効化できる

requirements.toml による managed hook

  • エンタープライズの requirements は [hooks] 配下にインラインで hook を定義できる
  • ローカルで hook を無効化したユーザーに対しても managed hook を強制するには、requirements.toml[features].hooks = true[hooks] と併せて固定する
  • allow_managed_hooks_only = true で user / project / session / plugin の hook を無視し、管理者の managed hook だけを読み込む
  • managed_dir は macOS と Linux、windows_managed_dir は Windows で使われる
  • managed_dir 配下のスクリプト自体は Codex が配布しない。導入と更新は各社のツールで行う
  • managed hook のコマンドは、設定した managed ディレクトリ配下の絶対パスを使うべきとされている

plugin がバンドルする hook

  • 既定では plugin root 内の hooks/hooks.json を探す。.codex-plugin/plugin.jsonhooks エントリでこの既定を上書きできる
  • マニフェストの hooks./ 始まりのパス、そのパスの配列、インラインの hooks オブジェクト、またはその配列を受け付ける
  • マニフェストのパスは plugin root からの相対で解決され、root の外に出てはならない。マニフェストが hooks を定義すると、既定の hooks/hooks.json の代わりにそれが使われる
  • plugin hook のコマンドが受け取る環境変数
    • PLUGIN_ROOT(Codex 独自の拡張): インストール済み plugin root
    • PLUGIN_DATA(Codex 独自の拡張): plugin の書き込み可能データディレクトリ
    • 既存の plugin hook との互換のため CLAUDE_PLUGIN_ROOTCLAUDE_PLUGIN_DATA も設定される
  • plugin をインストール・有効化しても、その hook が自動的に信頼されることはない

matcher

matcher は正規表現の文字列。"*"""、または省略で、そのイベントのすべてに一致する。

イベントmatcher が絞るもの備考
PermissionRequestツール名Bashapply_patch、MCP ツール名に対応
PostToolUseツール名ツール対応範囲は下記
PostCompactcompaction のトリガーmanual / auto
PreCompactcompaction のトリガーmanual / auto
PreToolUseツール名ツール対応範囲は下記
SessionEnd終了理由現時点では other のみ
SessionStart開始のソースstartup / resume / clear / compact
SubagentStartsubagent の種別起動する subagent による
SubagentStopsubagent の種別停止する subagent による
UserPromptSubmit非対応設定しても無視される
Stop非対応設定しても無視される
  • apply_patch に対しては EditWrite も matcher 値として使える

ツールの対応範囲

ツール経路PreToolUsePostToolUse備考
shell コマンド対応対応Bash として一致させる
unified exec(exec_command対応対応Bash として一致。後続の write_stdin のポーリングが、元コマンド完了時の PostToolUse を届けることがある
apply_patch対応対応apply_patch / Edit / Write
MCP ツール対応対応mcp__filesystem__read_file のようなツール名
その他のローカル function tool対応対応update_plan などの関数名。spawn_agentAgent にも一致する
WebSearch などの hosted tool非対応非対応ローカル function-tool の hook 経路を通らない
  • write_stdin は既存の unified-exec セッションへの転送であり、既に PreToolUse を通ったコマンドに入力を送る/ポーリングするときは PreToolUse を再発火しない
  • 一部の特殊なツール経路は既定の hook 経路をオプトアウトできる。ツール hook は有用なガードレールであって完全な強制境界ではないと明記されている

共通の入力フィールド

command hook は JSON オブジェクト 1 個を stdin で受け取る。

フィールド意味
session_idstring現在のセッション ID。subagent の hook は親セッションの ID
transcript_pathstring | nullセッションのトランスクリプトファイルのパス
cwdstringセッションの作業ディレクトリ
hook_event_namestring発火したイベント名
modelstringCodex 独自の拡張。有効なモデル slug
  • ターンにスコープされる hook は turn_id(Codex 独自の拡張)をイベント固有のフィールドとして持つ
  • SessionStartPreToolUsePermissionRequestPostToolUseUserPromptSubmitSubagentStartSubagentStopStoppermission_mode も含む(default / acceptEdits / plan / dontAsk / bypassPermissions
  • transcript_path は利便性のためのもので、トランスクリプト形式は hook にとって安定インターフェースではなく変わりうる

共通の出力フィールド

SessionStartPreCompactPostCompactUserPromptSubmitSubagentStopStop が対応する。SubagentStartsystemMessage と hook 固有コンテキストについて同じ形を受け付けるが、continue: false で subagent を止めることはできない。

フィールド効果
continuefalse でその hook run を stopped として記録する
stopReason停止理由として記録される
systemMessageUI またはイベントストリームに警告として表示される
suppressOutputパースはされるが未実装
  • 出力なしの exit 0 は成功として扱われ、Codex は続行する
  • PreToolUsePermissionRequestsystemMessage に対応するが、continue / stopReason / suppressOutput現時点では非対応PreToolUse hook がこれらを返すと、その hook run を失敗としてマークしエラーを報告したうえでツール呼び出しを続行する
  • PostToolUsesystemMessagecontinue: falsestopReason に対応する。suppressOutput はパースされるが非対応

大きな hook 出力(spilling)

  • 既定では、モデルから見える hook 出力メッセージ 1 件を約 2,500 トークンに制限する
  • 超えた場合は全文を <temp_dir>/hook_outputs/<session_id>/<uuid>.txt に保存し、モデルには先頭と末尾のプレビューと保存先パスを渡す。ファイルを書けない場合もモデルには切り詰めたプレビューが届く
  • additionalContextLimit を handler に設定するとしきい値を変えられる。省略時は既定の 2500 トークン。正の整数で任意のしきい値、0 でハンドラの additional context をそのままモデルへ渡す
  • Codex は一致した handler ごとに独立して評価する。additional context を出せないイベントでは additionalContextLimit を無視し設定警告を報告する
  • このしきい値は additionalContext にのみ適用される。ツールのフィードバックと継続プロンプトは既定の制限のまま
  • 出力がディスクに書かれうるため、hook 出力に秘密情報を含めないこと

イベント別の入出力

SessionStart

  • matchersource に適用される。sourcestartup / resume / clear / compact
  • stdout のプレーンテキストは追加の developer context として渡される
  • JSON では共通出力フィールドに加え hookSpecificOutput.additionalContext が使える
  • root セッションの compaction 後、source: "compact" に一致する SessionStart hook は次のモデルリクエストの前に走る。ターンの途中の自動 compaction でも同様で、追加コンテキストは後のユーザーターンを待たずその継続に届く。continue: false を返すと、次のモデルリクエストを送らずにターンを終える

SessionEnd

  • メインスレッドについて、開いている会話をアーカイブ/削除したとき、Codex が正常終了したとき、会話がアイドルで 30 分どのクライアントからも開かれていないときに実行される。subagent では実行されない
  • 会話を切り替えたり thread/unsubscribe を呼んだりしてもすぐにはセッションが終わらないため、即座には実行されない
  • matcherreason を絞る。現時点では reason は常に other
  • advisory(助言的)であり、出力が Codex を誘導したりスレッドを開いたままにしたりはしない。タイムアウトやエラー終了は hook failure として報告される

SubagentStart

  • matcheragent_type に適用される
  • 追加フィールド: turn_idagent_idagent_typepermission_mode
  • stdout のプレーンテキストは subagent 向けの追加 developer context になる
  • continue: false は互換のためパースされるが、subagent の起動を止めない

PreToolUse

  • 追加フィールド: turn_idtool_nametool_use_idtool_input
  • matchertool_name とそのエイリアスに適用される。apply_patch 経由のファイル編集では apply_patch / Edit / Write が使えるが、hook 入力の tool_nameapply_patch のまま
  • stdout のプレーンテキストは無視される
  • 拒否は hookSpecificOutput.permissionDecision: "deny"permissionDecisionReason。旧来の {"decision": "block", "reason": ...} も受け付ける。exit code 2stderr への理由出力でも拒否できる
  • ブロックせずコンテキストを足すには hookSpecificOutput.additionalContext
  • 書き換えは permissionDecision: "allow"updatedInput を併せて返す。Bashapply_patch では updatedInput に文字列の command が必要。MCP など他のローカル function tool では置き換え後の引数オブジェクト。updatedInput"allow" とのみ併用し、それ以外の形はエラーとして報告される
  • permissionDecision: "ask"、旧来の decision: "approve"continue: falsestopReasonsuppressOutputパースされるが未対応。hook run を失敗としてマークし、エラーを報告してツール呼び出しを続行する

PermissionRequest

  • Codex が承認を求めようとするとき(shell の escalation や managed-network の承認など)に走る。承認不要のコマンドでは走らない
  • 許可・拒否・判断の見送り(通常の承認プロンプトに任せる)ができる
  • 追加フィールド: turn_idtool_nametool_inputtool_input.descriptionstring | null。Codex が持つときだけの人間可読な承認理由)
  • 承認は hookSpecificOutput.decision.behavior: "allow"、拒否は "deny"message
  • 複数の hook が決定を返した場合、deny が優先される。deny が無く allow があれば承認プロンプトを出さずに進む。どの hook も決めなければ通常の承認フローになる
  • updatedInput / updatedPermissions / interrupt は返してはならない。将来のために予約されており、現時点では fail closed になる

PostToolUse

  • 対応ツールが出力を出した後に走る。Bash では非ゼロ終了のコマンドの後にも走る。既に実行されたツールの副作用は取り消せない
  • 追加フィールド: turn_idtool_nametool_use_idtool_inputtool_response
  • stdout のプレーンテキストは無視される
  • decision: "block"reasonhookSpecificOutput.additionalContext が使える。exit code 2stderr でも同じ
  • このイベントの decision: "block" は完了済みの Bash コマンドを取り消さない。フィードバックを記録し、ツール結果をそのフィードバックに置き換えてモデルを続行させる
  • continue: false を返すと、元のツール結果の通常処理を止めてフィードバックまたは stop テキストから続行する
  • updatedMCPToolOutputsuppressOutputパースされるが未対応。hook run を失敗としてマークし、ツール結果の通常処理を続ける

code mode(モデルが JavaScript からツールを呼ぶ経路)での挙動:

hook の結果code mode から見える挙動
PreToolUse がブロックツール実行前に promise が reject される
PreToolUseupdatedInput を返す書き換え後の入力でツールが走り、その結果で promise が resolve する
PostToolUsedecision: "block" または exit 2ツールは走り、その後 hook の理由で promise が reject される
PostToolUsecontinue: falseモデルから見える結果には hook のフィードバックを使うが、ネストしたツールの promise は reject しない

PreCompact / PostCompact

  • matchertriggermanual / auto)に適用される
  • 追加フィールド: turn_idtrigger
  • stdout のプレーンテキストは無視される
  • PreCompactcontinue: false を返すと compaction の前に停止する。PostCompactcontinue: false は compaction の後に停止する

UserPromptSubmit

  • matcher は使われない
  • 追加フィールド: turn_idprompt
  • stdout のプレーンテキストは追加の developer context になる
  • hookSpecificOutput.additionalContext でコンテキストを足せる
  • {"decision": "block", "reason": ...} または exit code 2 + stderr でプロンプトをブロックできる

SubagentStop

  • matcheragent_type に適用される
  • 追加フィールド: turn_idagent_idagent_typeagent_transcript_pathstop_hook_activelast_assistant_message
  • exit 0 のとき JSON を要求する。プレーンテキスト出力はこのイベントでは不正
  • {"decision": "block", "reason": ...} または exit code 2 で subagent の継続を求める
  • いずれかの SubagentStop hook が continue: false を返すと、他の hook の継続決定より優先される

Stop

  • matcher は使われない
  • 追加フィールド: turn_idstop_hook_activelast_assistant_message
  • exit 0 のとき JSON を要求する。プレーンテキスト出力は不正
  • decision: "block" はターンを拒否するのではなく、reason をプロンプト文とする新しい継続プロンプトを自動生成して Codex を続行させる
  • いずれかの Stop hook が continue: false を返すと、他の hook の継続決定より優先される

設定

{
  "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
          }
        ]
      }
    ],
    "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"
          }
        ]
      }
    ]
  }
}
[[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"
allow_managed_hooks_only = true

[features]
hooks = true

[hooks]
managed_dir = "/enterprise/hooks"
windows_managed_dir = 'C:\enterprise\hooks'

制約・注意点

  • ツール hook は完全な強制境界ではない。一部の特殊なツール経路は hook 経路をオプトアウトできる
  • hook 出力はディスクに書かれることがあるため、秘密情報を返さない
  • hook と plugin からのコンテキストは累積し、モデル性能を落としうる。additionalContextLimit を上げるとそのリスクが増える。0 はハンドラ側で厳密な出力上限を持つ場合を除いて避ける
  • 公式ドキュメントの Schemas 節は、GitHub の main ブランチの生成スキーマにリリース版に無い hook フィールドが含まれうると注意している。リリース時の挙動はドキュメント本文が基準

関連

  • facts/codex/subagents.md
  • facts/codex/plugins.md
  • facts/codex/permissions.md
  • facts/codex/configuration-reference.md
  • facts/codex/config-basics.md