從寫程式碼,到創作下一幕

探索 字節跳動 - 火山方舟 的 AI 程式設計與影片創作活動。

Agent Plan & Coding Plan

一站體驗多款熱門模型,為 AI 程式設計與智能體開發提供更多選擇。新使用者可聯絡(微信: goo_lvyouyou)免費體驗 9.9 agent plan。

Seedance 2.5

讓創意,躍然成片。探索 30 秒影片、多模態參考與局部編輯,把腦海中的畫面變成下一支作品。

繁體中文

Hooks

Hooks

在 Codex 生命週期中執行確定性指令碼

Hooks 是 Codex 的可擴充性框架。你可以藉助它們在智能體迴圈期間執行指令碼或 MCP 工具,從而實現以下功能:

  • 將聊天傳送到自訂日誌記錄/分析引擎
  • 掃描團隊的提示詞,防止意外貼上 API key
  • 彙總聊天內容,自動建立持久記憶
  • 在一輪聊天停止時執行自訂驗證檢查,以強制執行標準
  • 在特定目錄中自訂提示方式

需要注意的執行時行為:

  • 來自多個檔案的所有匹配 hooks 都會執行。
  • 同一事件的多個匹配命令 hooks 會並發啟動, 因此一個 hook 無法阻止另一個匹配 hook 啟動。
  • 非託管 hooks 必須先經過審查並受信任,才能執行。

Hooks 會在對話的不同階段執行:

時機 Hooks
在一個輪次期間 PreToolUsePermissionRequestPostToolUsePreCompactPostCompactUserPromptSubmitSubagentStopStop
當你中斷活躍輪次時 Interrupt(不為子智能體執行)
當會話或子智能體啟動時 SessionStartSubagentStart
當主執行緒結束時 SessionEnd(不為子智能體執行)

Codex 在哪裡查詢 hooks

Codex 會在活躍設定層旁邊查詢以下任一形式的 hooks:

  • hooks.json
  • config.toml 內的內聯 [hooks]

已安裝的外掛也可以通過其外掛清單或預設的 hooks/hooks.json 檔案捆綁生命週期設定。 有關外掛打包規則,請參閱建置 外掛

實際使用中,最有用的四個位置是:

  • ~/.codex/hooks.json
  • ~/.codex/config.toml
  • <repo>/.codex/hooks.json
  • <repo>/.codex/config.toml

如果存在多個 hook 來源,Codex 會載入所有匹配的 hooks。 優先順序較高的設定層不會替換優先順序較低的 hooks。 如果同一層同時包含 hooks.json 和內聯 [hooks],Codex 會合並二者並在啟動時發出警告。每一層最好只使用一種表示方式。

Codex 還可以發現已啟用外掛中捆綁的 hooks。外掛捆綁的 hooks 會與其他 hook 來源一同載入,並採用與 其他非託管 hooks 相同的信任審查流程。

僅當專案 .codex/ 層受信任時,才會載入專案本機 hooks。在 不受信任的專案中,Codex 仍會從各自的活躍設定層載入使用者和系統 hooks。

審查和信任 hooks

Codex 會先列出已設定的 hooks,再決定哪些可以執行。在 非託管 hook 執行之前,Codex 要求你審查並信任其確切的 hook 定義。Codex 會針對 hook 當前的雜湊值記錄信任狀態,因此新增或 更改後的 hooks 會被標記為待審查,並在獲得信任前跳過。

在 CLI 中使用 /hooks 可檢查 hook 來源、審查新增或更改的 hooks、 信任 hooks,或停用單個非託管 hook。如果啟動時有 hooks 需要審查, Codex 會輸出警告,提示你開啟 /hooks

來自系統、MDM、雲端或 requirements.toml 來源的託管 hooks 會被標記為 託管項,根據策略受到信任,並且無法從使用者 hook 瀏覽器中停用。

對於已在 Codex 外部審查 hook 來源的一次性自動化任務,可傳入 --dangerously-bypass-hook-trust,從而在該次呼叫中執行已啟用的 hooks,且無需 持久儲存 hook 信任狀態。

設定結構

Hooks 分為三個層級:

  • Hook 事件,例如 PreToolUsePostToolUsePreCompactSubagentStartStop
  • 用於決定該事件何時匹配的匹配器組
  • 匹配器組命中時執行的一個或多個 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
          }
        ]
      }
    ],
    "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
          }
        ]
      }
    ]
  }
}

注意:

  • descriptionhooks.json 檔案的可選頂層後設資料。它 不會改變要執行哪些 hooks。
  • timeout 的單位為秒。
  • 如果省略 timeout,Codex 會對大多數 hooks 使用 600 秒。
    • SessionEndInterrupt 預設使用 1 秒,最大支援 3 秒。
  • statusMessage 是可選的。
  • additionalContextLimit 設定命令 hook 可向模型傳送多少 additionalContext, 超出後 Codex 會將完整文本儲存到磁碟,並改為傳送較短的 預覽。請參閱大型 hook 輸出
  • commandWindows 是僅適用於 Windows 的可選命令覆蓋項。在 TOML 中,請使用 command_windowscommandWindows
  • async 設為 true,可在後台執行命令 hook
  • 支援 commandmcp_tool 處理程序。promptagent 處理程序會被解析,但會跳過執行。
  • 命令會以會話的 cwd 作為工作目錄執行。
  • 對於儲存庫本機 hooks,建議從 git 根目錄解析路徑,而不是使用 .codex/hooks/... 之類的相對路徑。Codex 可能從 子目錄啟動,而基於 git 根目錄的路徑可以保持 hook 位置穩定。

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 工具 hooks

MCP 工具 hook 允許生命週期事件呼叫已連線 MCP 伺服器上的工具。它會將結構化參數直接傳送給該工具,並採用與命令 hook 相同的信任審查和輸出約定。

設定 MCP 工具 hook

此 hook 會要求 scanner MCP server 在 Codex 寫入或 編輯檔案後掃描每個補丁:

{
  "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 server 的名稱,必填。
tool 該伺服器所公開工具的名稱,必填。
input 可選的參數模板 JSON 物件。預設為 {}
timeout 可選的活躍執行超時時間,單位為秒。預設為 600
statusMessage Hook 執行時顯示的可選訊息。

根據 hook 事件展開參數

使用 ${field.nested} 讀取 hook 事件中的點號分隔欄位。如果佔位符 填充整個值,則會保留其 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"
}

執行和生命週期

  • Hooks 使用現有 MCP 連線,不會啟動或重新連線伺服器。
  • 當工具傳回阻止決定時,hook 可以阻止操作。 錯誤、伺服器缺失和工具不可用不會阻止操作。
  • MCP 工具 hooks 會同步執行。它們不會請求工具核准,也不會觸發 其他 hooks。
  • 以 hook 或伺服器中較短的超時時間為準。等待 MCP 引導回應所用的時間不計入超時。
  • SessionStart hooks 可能在 MCP server 準備就緒前執行。如果發生這種情況, 它們不會阻止會話。
  • SessionEnd 不支援 MCP 工具 hooks。

關閉 hooks

Hooks 預設啟用。要在 config.toml 中將其關閉,請設定:

[features]
hooks = false

請使用 hooks 作為規範功能鍵。codex_hooks 作為 已棄用的別名仍然有效。管理員可以在 requirements.toml 中使用 [features].hooks = false, 以相同方式強制關閉 hooks。

來自 requirements.toml 的託管 hooks

企業託管要求也可以在 [hooks] 下以內聯方式定義 hooks。 當管理員希望強制執行 hook 設定,同時通過 MDM 或其他裝置管理系統 分發實際指令碼時,這種方式非常有用。即使使用者已在本機停用 hooks, 如需強制執行託管 hooks,請在 requirements.toml 中將 [features].hooks = true[hooks] 一同固定。若要忽略 使用者、專案、會話和外掛 hooks,同時仍允許管理員 託管的 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"

託管 hooks 的注意事項:

  • managed_dir 用於 macOS 和 Linux。
  • windows_managed_dir 用於 Windows。
  • Codex 不會分發 managed_dir 中的指令碼;你的企業 工具必須單獨安裝和更新這些指令碼。
  • 託管 hook 命令應使用所設定託管目錄下指令碼的絕對路徑。
  • allow_managed_hooks_only = true 會跳過來自使用者、專案、會話和 外掛來源的 hooks,但仍會載入來自 requirements.toml 和 其他託管設定層的託管 hooks。

外掛捆綁的 hooks

啟用外掛後,Codex 可以載入該外掛中的生命週期 hooks, 並與使用者、專案和託管 hooks 一同執行。

預設情況下,Codex 會在外掛根目錄中查詢 hooks/hooks.json。外掛 清單可以使用 .codex-plugin/plugin.json 中的 hooks 條目替代該預設設定。 清單條目可以是以 ./ 為字首的路徑、以 ./ 為字首的路徑陣列、 內聯 hooks 物件,或內聯 hooks 物件陣列。

{
  "name": "repo-policy",
  "hooks": "./hooks/hooks.json"
}

清單 hook 路徑相對於外掛根目錄解析,且必須位於 該根目錄之內。如果清單定義了 hooks,Codex 將使用這些清單 條目,而不是預設的 hooks/hooks.json

外掛 hook 命令會收到以下環境變數:

  • PLUGIN_ROOT 是 Codex 專用擴充套件,指向已安裝的 外掛根目錄。
  • PLUGIN_DATA 是 Codex 專用擴充套件,指向外掛的 可寫資料目錄。
  • Codex 還會設定 CLAUDE_PLUGIN_ROOTCLAUDE_PLUGIN_DATA,以便 與現有外掛 hooks 保持相容。

外掛 hooks 與其他 hooks 使用相同的事件架構。安裝或啟用 外掛並不會自動信任其 hooks;在你審查並信任當前 hook 定義前, Codex 會跳過外掛捆綁的 hooks。

匹配器模式

matcher 欄位是一個正規表示式字串,用於篩選 hooks 何時觸發。使用 "*""",或完全省略 matcher,即可匹配受支援事件的每次 出現。

目前只有部分 Codex 事件會採用 matcher

事件 matcher 的篩選物件 備註
PermissionRequest 工具名稱 支援 Bashapply_patch* 和 MCP 工具名稱
PostToolUse 工具名稱 請參閱工具覆蓋範圍
PostCompact 壓縮觸發方式 值為 manualauto
PreCompact 壓縮觸發方式 值為 manualauto
PreToolUse 工具名稱 請參閱工具覆蓋範圍
SessionEnd 結束原因 當前僅支援 other
SessionStart 啟動來源 值為 startupresumeclearcompact
SubagentStart 子智能體類型 值取決於所啟動的子智能體
SubagentStop 子智能體類型 值取決於所停止的子智能體
UserPromptSubmit 不支援 為此事件設定的任何 matcher 都會被忽略
Stop 不支援 為此事件設定的任何 matcher 都會被忽略
Interrupt 不支援 為此事件設定的任何 matcher 都會被忽略

*對於 apply_patchmatcher 值也可以使用 EditWrite

範例:

  • Bash
  • ^apply_patch$
  • Edit|Write
  • mcp__filesystem__read_file
  • mcp__filesystem__.*
  • startup|resume|clear|compact
  • manual|auto

工具覆蓋範圍

PreToolUsePostToolUse 可以觀察 shell 和 MCP 呼叫之外的操作。大多數 本機函式工具都使用相同的 hook 路徑,因此你可以匹配其工具名稱、 檢查其 JSON 參數,並通過 PreToolUse 阻止或重寫呼叫。

工具路徑 PreToolUse PostToolUse 備註
Shell 命令 匹配為 Bash
統一執行(exec_command 匹配為 Bash。後續 write_stdin 輪詢可在原始命令完成時傳遞其 PostToolUse
apply_patch 匹配為 apply_patchEditWrite
MCP 工具 匹配 MCP 工具名稱,例如 mcp__filesystem__read_file
其他本機函式工具 匹配函式工具名稱,例如 update_planspawn_agent 也會匹配 Agent
託管工具,例如 WebSearch 這些工具不使用本機函式工具 hook 路徑。

write_stdin 是現有統一執行會話的傳輸機制。它在傳送輸入或輪詢 已通過 PreToolUse 的命令時,不會再次執行 PreToolUse

某些專用工具路徑可以選擇不使用預設 hook 路徑。請將工具 hooks 視為實用的防護機制,而不是完整的強制執行邊界。

通用輸入欄位

每個命令 hook 都會在 stdin 上接收一個 JSON 物件。

以下是通常會用到的共享欄位:

欄位 類型 含義
session_id string 當前 Codex 會話 ID。子智能體 hooks 使用父會話 ID。
transcript_path string | null 會話轉錄檔案的路徑(如果有)
cwd string 會話的工作目錄
hook_event_name string 當前 hook 事件名稱
model string Codex 專用擴充套件。活躍模型 slug

輪次範圍的 hooks 會在其事件專用表中將 turn_id 列為 Codex 專用擴充套件。

SessionStartPreToolUsePermissionRequestPostToolUseUserPromptSubmitSubagentStartSubagentStopStopInterrupt 還會包含 permission_mode,用於描述當前權限模式,其值為 defaultacceptEditsplandontAskbypassPermissions

為了方便使用,transcript_path 指向聊天轉錄,但 轉錄格式並非 hooks 的穩定介面,可能會隨時間變化。

如需完整的線上格式,請參閱架構

通用輸出欄位

SessionStartPreCompactPostCompactUserPromptSubmitSubagentStopStop 支援以下共享 JSON 欄位。SubagentStartsystemMessage 和 hook 專用上下文接受相同的結構,但 continue: false 不會停止子智能體:

{
  "continue": true,
  "stopReason": "optional",
  "systemMessage": "optional",
  "suppressOutput": false
}
欄位 效果
continue 如果為 false,將該次 hook 執行標記為已停止
stopReason 記錄為停止原因
systemMessage 在 UI 或事件流中顯示為警告
suppressOutput 目前會被解析,但尚未實現

退出碼為 0 且沒有輸出時會被視為成功,Codex 將繼續執行。

PreToolUsePermissionRequest 支援 systemMessage,但目前這些事件不支援 continuestopReasonsuppressOutput。 如果 PreToolUse hook 傳回其中一個不受支援的欄位,Codex 會將 該次 hook 執行標記為失敗、報告錯誤,然後繼續工具呼叫。

PostToolUse 支援 systemMessagecontinue: falsestopReasonsuppressOutput 會被解析,但目前不支援用於該事件。

大型 hook 輸出

預設情況下,Codex 會將每條模型可見的 hook 輸出訊息限制在約 2,500 個 token。如果 hook 傳回的內容更多,Codex 會將完整文本儲存到 <temp_dir>/hook_outputs/<session_id>/<uuid>.txt 下,並向模型提供包含已儲存檔案路徑的 首尾預覽。此行為稱為 溢位:Codex 將過大的輸出儲存到磁碟,並替換為 模型可見的較短預覽。如果檔案無法寫入,模型仍會 收到截斷後的預覽。

對於任何傳回 additionalContext 的命令 hook,可在處理程序上設定 additionalContextLimit,以自訂大致的 token 閾值:

{
  "type": "command",
  "command": "python3 ~/.codex/hooks/session_start.py",
  "additionalContextLimit": 5000
}

省略 additionalContextLimit 即可使用預設的 2500 token 閾值。使用 正整數可選擇其他閾值,使用 0 則可將處理程序的 完整附加上下文直接傳給模型。Codex 會單獨評估每個 匹配的處理程序。對於無法生成附加 上下文的事件,Codex 會忽略 additionalContextLimit 並報告設定 警告。

該設定僅適用於 additionalContext。工具回饋和續接 提示仍使用預設限制。

由於過大的輸出可能會寫入磁碟,請避免在 hook 輸出中傳回金鑰或 其他敏感資料。

在後台執行 hooks

預設情況下,Codex 會等待命令 hook 完成,再繼續執行 觸發它的操作。將 async 設為 true,即可在 Codex 繼續執行的同時, 在後台執行命令 hook。

設定後台 hook

hooks.json 的命令處理程序中新增 "async": true

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ~/.codex/hooks/post_tool_use.py",
            "async": true,
            "timeout": 120
          }
        ]
      }
    ]
  }
}

對於 config.toml 中的內聯 hook,請設定 async = true

[[hooks.PostToolUse]]
matcher = "Bash"

[[hooks.PostToolUse.hooks]]
type = "command"
command = "python3 ~/.codex/hooks/post_tool_use.py"
async = true
timeout = 120

後台 hooks 與同步命令 hooks 使用相同的輸入、matcher、信任審查、超時和 大型輸出處理方式。與其他命令 hooks 一樣,timeout 以秒為單位,預設值為 600Interrupt hooks 的預設超時時間為一秒,上限為三秒, 在後台執行時也是如此。

後台 hooks 的執行方式

後台 hook 完成後,Codex 會在對話中的下一個安全時機傳遞 受支援的資訊性輸出:

  • 如果一輪對話正在進行,Codex 會等待當前模型請求和工具呼叫 完成,然後讓該輸出可供本輪中的下一次模型請求使用。
  • 如果當前沒有進行中的輪次,Codex 會等到下一個使用者輪次。後台 hook 完成不會啟動新的輪次。

請使用與同步 hook 相同的事件專用 JSON 輸出。Codex 會將 additionalContext 新增到模型上下文,並將 systemMessage 顯示為 警告。

限制

  • Codex 在每個會話中最多並發運行八個後台 hooks。其他 hooks 會等待執行中的 hook 完成。
  • 每次匹配的呼叫都會獨立執行,後台 hooks 完成的 順序可能與啟動順序不同。
  • 會話結束時,Codex 會取消尚未完成的後台 hooks,並丟棄 尚未傳遞的輸出。
  • SessionEnd hooks 始終同步執行。

Hooks

SessionStart

此事件會將 matcher 應用於 source

通用輸入欄位外,還包含以下欄位:

欄位 類型 含義
source string 會話的啟動方式:startupresumeclearcompact

stdout 上的純文本會被新增為額外的開發者上下文。

stdout 上的 JSON 支援通用輸出欄位以及以下 hook 專用結構:

{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "Load the workspace conventions before editing."
  }
}

其中的 additionalContext 文本會被新增為額外的開發者上下文。

Codex 壓縮根會話後,匹配 source: "compact"SessionStart hooks 會在下一次模型請求前執行。這也適用於 在一輪對話中途發生自動壓縮的情況:Codex 會將 hook 的 附加上下文傳遞給緊隨其後的續接過程,而不是等待 後續使用者輪次。如果 hook 傳回 continue: false,Codex 會結束該輪, 不再傳送模型請求。

SessionEnd

SessionEnd 允許你在會話結束時執行命令,例如儲存最終 備註或清理檔案。它會在以下情況下為主執行緒執行:你歸檔或 刪除仍處於開啟狀態的對話、Codex 正常關閉,或某個 對話已閒置 30 分鐘且未在任何已連線的客戶端中開啟。 它不會為子智能體執行。

切換到其他對話或呼叫 thread/unsubscribe 不會立即結束 會話,因此不會立即執行 SessionEnd。Hook 在執行時 仍可讀取會話轉錄。

此事件使用 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 hooks 始終同步執行,即使 asynctrue。它們 僅提供建議,因此其輸出不會引導 Codex,也不會讓執行緒保持開啟。如果 命令超時或以錯誤退出,Codex 會將其報告為 hook 失敗。

SubagentStart

此事件會將 matcher 應用於 agent_type

通用輸入欄位外,還包含以下欄位:

欄位 類型 含義
turn_id string Codex 專用擴充套件。活躍的 Codex 輪次 ID
agent_id string 子智能體識別符
agent_type string 子智能體類型或設定檔
permission_mode string 當前權限模式

stdout 上的純文本會被新增為子智能體的額外開發者上下文。

stdout 上的 JSON 支援 systemMessage 以及以下 hook 專用結構:

{
  "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_patchEditWrite;hook 輸入 仍會報告 tool_name: "apply_patch"

通用輸入欄位外,還包含以下欄位:

欄位 類型 含義
turn_id string Codex 專用擴充套件。活躍的 Codex 輪次 ID
tool_name string 規範 hook 工具名稱,例如 Bashapply_patch,或 mcp__fs__read 之類的 MCP 名稱
tool_use_id string 此次呼叫的工具呼叫 ID
tool_input JSON value 工具專用輸入。Bashapply_patch 使用 tool_input.command。MCP 和其他本機函式工具會傳送其參數。

stdout 上的純文本會被忽略。

stdout 上的 JSON 可以使用 systemMessage。要拒絕受支援的工具呼叫,請傳回 以下 hook 專用結構:

{
  "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."
  }
}

要在不阻止操作的情況下重寫受支援的工具呼叫,請傳回 包含 updatedInputpermissionDecision: "allow"

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow",
    "updatedInput": {
      "command": "echo rewritten"
    }
  }
}

對於 Bash 命令和 apply_patchupdatedInput 必須包含字串 command 欄位。對於 MCP 和其他本機函式工具,updatedInput 是 替代參數物件。僅將 updatedInputpermissionDecision: "allow" 一同傳回;其他 updatedInput 結構會被報告為 錯誤。

permissionDecision: "ask"、舊版 decision: "approve"continue: falsestopReasonsuppressOutput 會被解析,但尚不受支援。Codex 會將 該次 hook 執行標記為失敗、報告錯誤,然後繼續工具呼叫。

PermissionRequest

當 Codex 即將請求核准時(例如 shell 權限提升或託管網路核准), PermissionRequest 會執行。它可以允許請求、拒絕請求, 也可以不作決定,讓正常的核准提示繼續出現。 對於無需核准的命令,它不會執行。

matcher 會應用於 tool_name 及匹配器別名。目前的規範 值包括 Bashapply_patchmcp__server__tool 等 MCP 工具名稱; apply_patch 也會匹配 EditWrite

通用輸入欄位外,還包含以下欄位:

欄位 類型 含義
turn_id string Codex 專用擴充套件。活躍的 Codex 輪次 ID
tool_name string 規範 hook 工具名稱,例如 Bashapply_patch,或 mcp__fs__read 之類的 MCP 名稱
tool_input JSON value 工具專用輸入。Bashapply_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."
    }
  }
}

如果多個匹配 hooks 傳回決定,則任何 deny 都優先。否則, allow 會讓請求繼續,而不顯示核准提示。如果沒有 匹配的 hook 作出決定,Codex 會使用正常的核准流程。

請勿為 PermissionRequest 傳回 updatedInputupdatedPermissionsinterrupt; 這些欄位為未來行為預留,目前會以封閉方式失敗。

PostToolUse

PostToolUse 會在受支援的工具產生輸出後執行,包括 Bash、 apply_patch、MCP 工具呼叫及其他本機函式工具。對於 Bash, 它也會在命令以非零狀態退出後執行。它無法撤銷 已執行工具產生的副作用。有關受支援的路徑和例外情況, 請參閱工具覆蓋範圍

matcher 會應用於 tool_name 及匹配器別名。對於通過 apply_patch 進行的檔案編輯,matcher 值可以使用 apply_patchEditWrite;hook 輸入 仍會報告 tool_name: "apply_patch"

通用輸入欄位外,還包含以下欄位:

欄位 類型 含義
turn_id string Codex 專用擴充套件。活躍的 Codex 輪次 ID
tool_name string 規範 hook 工具名稱,例如 Bashapply_patch,或 mcp__fs__read 之類的 MCP 名稱
tool_use_id string 此次呼叫的工具呼叫 ID
tool_input JSON value 工具專用輸入。Bashapply_patch 使用 tool_input.command。MCP 和其他本機函式工具會傳送其參數。
tool_response JSON value 工具專用輸出。MCP 工具會傳送 MCP 呼叫結果。其他本機函式工具通常會傳送面向模型的輸出。

stdout 上的純文本會被忽略。

stdout 上的 JSON 可以使用 systemMessage 及以下 hook 專用結構:

{
  "decision": "block",
  "reason": "The Bash output needs review before continuing.",
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "The command updated generated files."
  }
}

其中的 additionalContext 文本會被新增為額外的開發者上下文。

對於此事件,decision: "block" 不會撤銷已完成的 Bash 命令。 相反,Codex 會記錄回饋、用該回饋替換工具結果, 並從 hook 提供的訊息處繼續執行模型。

你也可以使用退出碼 2,並將回饋原因寫入 stderr

要在命令已經執行後停止對原始工具結果的正常處理, 請傳回 continue: false。Codex 會用你的回饋或停止文本替換工具結果, 然後從此處繼續。

updatedMCPToolOutputsuppressOutput 會被解析,但尚不受支援。 Codex 會將該次 hook 執行標記為失敗、報告錯誤,然後繼續 正常處理工具結果。

程式碼模式中的工具呼叫

當模型在程式碼模式下通過 JavaScript 呼叫工具時,hook 決定會應用於 該巢狀呼叫。PreToolUse 可以在工具執行前將其停止或重寫 其輸入。具有阻止作用的 PostToolUse 無法撤銷工具的副作用,但可以 阻止原始結果到達正在執行的指令碼。

Hook 結果 程式碼模式看到的內容
PreToolUse 阻止 工具 promise 會在工具執行前被拒絕。
PreToolUse 傳回 updatedInput 工具使用重寫後的輸入執行,promise 以該結果兌現。
PostToolUse 傳回 decision: "block" 或以程式碼 2 退出 工具先執行,然後 promise 會以 hook 原因為由被拒絕。
PostToolUse 傳回 continue: false Codex 將 hook 回饋用作模型可見結果,但不會拒絕巢狀工具 promise。

PreCompact

PreCompact 會在 Codex 壓縮聊天前執行。matcher 會應用於 trigger,其值為 manualauto

通用輸入欄位外,還包含以下欄位:

欄位 類型 含義
turn_id string Codex 專用擴充套件。活躍的 Codex 輪次 ID
trigger string 壓縮的觸發方式:manualauto

stdout 上的純文本會被忽略。

stdout 上的 JSON 支援通用輸出欄位。如果匹配的 PreCompact hook 傳回 continue: false,Codex 會在壓縮前停止。

PostCompact

PostCompact 會在 Codex 壓縮聊天后執行。matcher 會應用於 trigger,其值為 manualauto

通用輸入欄位外,還包含以下欄位:

欄位 類型 含義
turn_id string Codex 專用擴充套件。活躍的 Codex 輪次 ID
trigger string 壓縮的觸發方式:manualauto

stdout 上的純文本會被忽略。

stdout 上的 JSON 支援通用輸出欄位。如果匹配的 PostCompact hook 傳回 continue: false,Codex 會在壓縮後停止。

UserPromptSubmit

matcher 目前不用於此事件。

通用輸入欄位外,還包含以下欄位:

欄位 類型 含義
turn_id string Codex 專用擴充套件。活躍的 Codex 輪次 ID
prompt string 即將傳送的使用者提示詞

stdout 上的純文本會被新增為額外的開發者上下文。

stdout 上的 JSON 支援通用輸出欄位以及 以下 hook 專用結構:

{
  "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 退出 0 時,要求在 stdout 上輸出 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 退出 0 時,要求在 stdout 上輸出 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 會執行。可使用它 記錄中斷,或清理由鉤子啟動的工作。它不會針對空閒執行緒或子智能體執行, 並且會忽略任何已設定的 matcher

通用輸入欄位外,該事件還包括 turn_id(被中斷輪次的 id)和 permission_mode

命令鉤子的預設超時時間為一秒。設定的超時時間 僅限一至三秒。鉤子輸出無法阻止 中斷或重新啟動輪次。以 0 退出且不輸出任何內容,或者傳回包含 可選 systemMessage 的 JSON 以顯示警告。純文本輸出對此事件無效。

{ "systemMessage": "Saved the interrupted turn to the local audit log." }

架構

如果需要當前準確的線上格式,請參閱 Codex GitHub 儲存庫中生成的架構。

純文本別名

  • string | null