钩子

钩子

了解 OpenAI Codex Hooks 的配置与使用方式,在智能体生命周期中运行确定性脚本,用于检查、审计、权限控制、通知和自动化收尾。

钩子#

Codex 中文站说明: 本页围绕“钩子”重新补充了中文使用场景和验证重点。界面名称可能随 Codex 版本更新,请以当前客户端为准。

在 Codex 生命周期中运行确定性的脚本

钩子是 Codex 的一套扩展框架。它允许你把自己的脚本插入智能体循环中,从而实现例如以下能力:

  • 把聊天发送到自定义日志或分析系统
  • 扫描团队提示词,阻止误粘贴 API key
  • 自动总结聊天,生成持久记忆
  • 在聊天轮次结束时运行自定义校验检查,强制执行团队标准
  • 当工作目录匹配特定路径时,动态调整提示词策略

需要留意这些运行时行为:

  • 来自多个文件的匹配钩子都会运行。
  • 对同一事件命中的多个命令型钩子会并发启动,因此一个钩子不能阻止其他已命中的钩子启动。
  • 非托管命令型钩子必须经过审核并被信任后才会运行。

Hooks 会在对话的不同阶段运行:

阶段Hooks
会话轮次期间PreToolUsePermissionRequestPostToolUsePreCompactPostCompactUserPromptSubmitSubagentStopStop
会话或子智能体启动时SessionStartSubagentStart
主对话线程结束时SessionEnd(不会为子智能体运行)

Codex 在哪里查找钩子#

Codex 会在当前激活配置层旁边查找以下任一形式的钩子配置:

  • hooks.json
  • config.toml 中的内联 [hooks]

已安装插件也可以通过插件 manifest 或默认的 hooks/hooks.json 文件打包生命周期配置。插件打包规则请参见构建插件

实际使用中,最常见也最有用的四个位置是:

  • ~/.codex/hooks.json
  • ~/.codex/config.toml
  • /.codex/hooks.json
  • /.codex/config.toml

如果存在多个钩子来源,Codex 会加载所有命中的钩子。高优先级配置层不会替换低优先级配置层里的钩子。如果同一配置层同时包含 hooks.json 和内联 [hooks],Codex 会合并它们,并在启动时给出警告。建议每个配置层只使用其中一种表示方式。

Codex 也可以发现已启用插件中打包的 hooks。插件打包的 hooks 会和其他 hook 来源一起加载,并使用和其他非托管 hooks 相同的信任审核流程。

项目本地钩子只会在项目 .codex/ 配置层受信任时加载。在不受信任的项目中,Codex 仍会加载用户层和系统层中各自激活的钩子。

审核并信任 hooks#

Codex 会在决定哪些 hooks 可以运行之前列出已配置 hooks。非托管 command hook 运行前,Codex 要求你审核并信任精确的 hook 定义。Codex 会把信任记录绑定到该 hook 当前 hash;新增或变更后的 hooks 会重新标记为待审核,并在被信任前跳过。

在 CLI 中使用 /hooks 可以检查 hook 来源、审核新增或已变更 hooks、信任 hooks,或禁用单个非托管 hook。如果启动时有 hooks 需要审核,Codex 会打印警告,提示你打开 /hooks

来自 system、MDM、cloud 或 requirements.toml 来源的 managed hooks 会被标记为托管,由策略信任,并且不能从用户 hook 浏览器中禁用。

对于已经在 Codex 外部审核 hook 来源的一次性自动化,可以传入 --dangerously-bypass-hook-trust,让已启用的 hooks 在本次调用中无需持久化 hook trust 也能运行。

配置结构#

Hooks 分成三层:

  • 事件名,例如 PreToolUsePostToolUsePreCompactSubagentStartStop
  • 决定该事件何时命中的 matcher 分组
  • 当 matcher 命中时实际执行的一个或多个钩子处理器
json
{
"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"
}
]
}
],
"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,大多数 hooks 会使用 600 秒。
  • SessionEnd 默认使用 1 秒,最大支持 3 秒。
  • statusMessage 是可选的。
  • commandWindows 是可选的 Windows 专用命令覆盖。在 TOML 中可以使用 command_windowscommandWindows
  • Codex 会解析 async 选项,但目前还不支持异步命令型钩子。
  • 目前只有 type: "command" 的处理器会运行。promptagent 处理器会被解析,但会被跳过。
  • 命令会以当前会话的 cwd 作为工作目录运行。
  • 对仓库级钩子,优先使用基于 Git 根目录解析的路径,而不是 .codex/hooks/... 这类相对路径。Codex 可能从子目录启动,基于 Git 根目录的写法更稳定。

config.toml 中等价的内联 TOML 写法如下:

toml
[[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"

关闭钩子#

Hooks 默认启用。若要在 config.toml 中关闭,请设置:

toml
[features]
hooks = false

请把 hooks 作为标准功能键。codex_hooks 仍可作为已弃用别名使用。管理员也可以在 requirements.toml 中通过 [features].hooks = false 强制关闭钩子。

来自 requirements.toml 的托管钩子#

企业托管的 requirements 也可以在 [hooks] 下内联定义钩子。当管理员希望强制执行钩子配置,同时通过 MDM 或其他设备管理系统分发实际脚本时,这种方式很有用。若要即使用户在本地关闭 hooks 也强制执行托管 hooks,请在 requirements.toml 中把 [features].hooks = true[hooks] 一起固定下来。若要忽略用户、项目、会话和插件 hooks,同时仍允许管理员托管 hooks,请设置 allow_managed_hooks_only = true

toml
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 会跳过来自用户、项目、会话和插件来源的 hooks,但仍会加载 requirements.toml 和其他托管配置层中的托管 hooks。

插件打包的 hooks#

当插件启用后,Codex 可以把该插件里的生命周期 hooks 与用户、项目和托管 hooks 一起加载。

默认情况下,Codex 会在插件根目录中查找 hooks/hooks.json。插件 manifest 可以通过 .codex-plugin/plugin.json 中的 hooks 条目覆盖这个默认位置。manifest 条目可以是一个 ./ 前缀路径、./ 前缀路径数组、内联 hooks 对象,或内联 hooks 对象数组。

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

Manifest hook 路径会相对于插件根目录解析,并且必须留在该根目录内。如果 manifest 定义了 hooks,Codex 会使用这些 manifest 条目,而不是默认的 hooks/hooks.json

Plugin hook 命令会收到这些环境变量:

  • PLUGIN_ROOT 是 Codex 专用扩展,指向已安装插件根目录。
  • PLUGIN_DATA 是 Codex 专用扩展,指向插件的可写数据目录。
  • 为了兼容现有 plugin hooks,Codex 还会设置 CLAUDE_PLUGIN_ROOTCLAUDE_PLUGIN_DATA

Plugin hooks 使用和其他 hooks 相同的事件 schema。安装或启用插件并不会自动信任它的 hooks;Codex 会跳过 plugin-bundled hooks,直到你审核并信任当前 hook 定义。

匹配器模式#

matcher 字段是一个正则表达式字符串,用来过滤 hook 何时触发。使用 "*""",或完全省略 matcher,都表示匹配该事件的所有支持触发。

当前只有部分 Codex 事件真正会使用 matcher

事件matcher 过滤的对象说明
PermissionRequest工具名支持 Bashapply_patch* 和 MCP tool names。
PostToolUse工具名参见工具覆盖范围
PostCompactcompact 触发源值为 manualauto
PreCompactcompact 触发源值为 manualauto
PreToolUse工具名参见工具覆盖范围
SessionEnd结束原因当前只有 other
SessionStart启动来源值为 startupresumeclearcompact
SubagentStart子智能体类型值取决于启动的子智能体。
SubagentStop子智能体类型值取决于停止的子智能体。
UserPromptSubmit不支持该事件中配置的 matcher 会被忽略。
Stop不支持该事件中配置的 matcher 会被忽略。
  • apply_patchmatcher 值也可以使用 EditWrite

示例:

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

工具覆盖范围#

PreToolUsePostToolUse 不只能够观察 shell 与 MCP 调用。大多数本地 function tools 使用同一条 hook 路径,因此你可以匹配工具名、检查其 JSON 参数,并通过 PreToolUse 阻止或改写调用。

工具路径PreToolUsePostToolUse说明
Shell 命令Bash 匹配。
Unified exec(exec_commandBash 匹配。命令结束时,后续一次 write_stdin 轮询可能会送达原命令的 PostToolUse
apply_patch可用 apply_patchEditWrite 匹配。
MCP tools匹配 MCP tool name,例如 mcpfilesystemread_file
其他本地 function tools匹配 function tool name,例如 update_planspawn_agent 也会匹配 Agent
WebSearch 等托管工具这些工具不使用本地 function-tool hook 路径。

write_stdin 是已有 unified-exec 会话的传输通道。它向已通过 PreToolUse 的命令发送输入或轮询状态时,不会再次运行 PreToolUse

某些专用工具路径可以选择不使用默认 hook 路径。请把工具 hooks 视为有用的护栏,而不是完整的强制边界。

通用输入字段#

每个命令型钩子都会通过 stdin 收到一个 JSON 对象。

这些共享字段通常最常用:

字段类型含义
session_idstring当前 Codex 会话 ID。子智能体 hooks 使用父会话 ID。
transcript_path`string \null`会话 transcript 文件路径;如果不存在则为 null
cwdstring当前会话的工作目录。
hook_event_namestring当前 hook 事件名。
modelstringCodex 扩展字段。当前激活模型的 slug。

按会话轮次作用域运行的 hooks 会在各自的事件专属字段表里额外列出 turn_id

SessionStartPreToolUsePermissionRequestPostToolUseUserPromptSubmitSubagentStartSubagentStopStop 也会包含 permission_mode,表示当前权限模式,值可能是 defaultacceptEditsplandontAskbypassPermissions

transcript_path 只是为了方便指向聊天 transcript;transcript 格式不是 hooks 的稳定接口,未来可能变化。

如果你需要完整的当前线格式,请参见 Schema 定义

通用输出字段#

SessionStartPreCompactPostCompactUserPromptSubmitSubagentStopStop 支持以下共享 JSON 字段。SubagentStartsystemMessage 和 hook-specific context 接受相同结构,但 continue: false 不会阻止子智能体启动:

json
{
"continue": true,
"stopReason": "optional",
"systemMessage": "optional",
"suppressOutput": false
}
字段作用
continue若为 false,表示该次 hook 运行被标记为停止。
stopReason记录为停止原因。
systemMessage作为警告显示在界面或事件流中。
suppressOutput当前会被解析,但尚未真正实现。

退出码为 0 且没有任何输出,会被视为成功,Codex 会继续执行。

PreToolUsePermissionRequest 支持 systemMessage,但当前不支持 continuestopReasonsuppressOutput。如果 PreToolUse hook 返回了这些不支持的字段,Codex 会把这次 hook 运行标记为失败、报告错误,并继续执行工具调用。

PostToolUse 支持 systemMessagecontinue: falsestopReasonsuppressOutput 虽然会被解析,但当前仍未真正支持。

超长 hook 输出#

Codex 会把每一条模型可见 hook 输出限制在大约 2,500 tokens。如果 hook 返回更多内容,Codex 会把完整文本保存到 /hook_outputs//.txt,并把包含文件路径的首尾预览交给模型。如果文件无法写入,模型仍会收到截断后的预览。

该限制适用于来自 SessionStartSubagentStartPreToolUsePostToolUseUserPromptSubmit 的额外上下文,来自 PostToolUse 的反馈,以及来自 StopSubagentStop 的继续提示。限制按每一条额外上下文或继续提示分别计算;对 PostToolUse 反馈,Codex 会先合并所有匹配 hooks 的反馈,再对合并后的消息应用限制。

由于过长输出可能写入磁盘,请避免在 hook 输出中返回 secrets 或其他敏感数据。

Hooks#

SessionStart#

这个事件中的 matcher 会作用在 source 上。

通用输入字段 外,还会额外提供:

字段类型含义
sourcestring会话启动方式:startupresumeclearcompact

写到 stdout 的纯文本会被追加为额外的 开发者上下文。

如果向 stdout 输出 JSON,则支持 通用输出字段,以及下面这个该事件专属结构:

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

其中 additionalContext 会被加入为额外的 开发者上下文。

SessionEnd#

SessionEnd 允许你在会话结束时运行命令,例如保存最终笔记或清理文件。它会在以下情况下为主对话线程运行:归档或删除仍处于打开状态的对话、Codex 正常关闭,或对话已空闲且在所有已连接客户端中均未打开达 30 分钟。它不会为子智能体运行。

切换到其他对话或调用 thread/unsubscribe 不会立即结束会话,因此也不会立即运行 SessionEnd。Hook 运行期间仍可读取会话 transcript。

该事件的 matcher 会过滤 reason。目前 reason 始终为 other。你可以省略 matcher,或使用 other 来匹配每个 SessionEnd 事件。

通用输入字段外,还会额外提供:

字段类型含义
reasonstring会话结束原因:other

例如,SessionEnd 命令会收到:

json
{
"session_id": "thr_123",
"transcript_path": "/workspace/.codex/rollout.jsonl",
"cwd": "/workspace",
"hook_event_name": "SessionEnd",
"reason": "other"
}

SessionEnd hooks 只提供通知性质的结果。它们的输出不会引导 Codex,也不会让对话线程保持打开。如果命令超时或以错误退出,Codex 会把它报告为 hook failure。

SubagentStart#

这个事件中的 matcher 会作用在 agent_type 上。

通用输入字段 外,还会额外提供:

字段类型含义
turn_idstringCodex 扩展字段。当前激活会话轮次的 ID。
agent_idstring子智能体标识。
agent_typestring子智能体类型或配置档案。
permission_modestring当前权限模式。

写到 stdout 的纯文本会被追加为该子智能体的额外开发者上下文。

如果向 stdout 输出 JSON,则支持 systemMessage 和下面这个事件专属结构:

json
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Review the repository test conventions first."
}
}

其中 additionalContext 会被加入为该子智能体的额外开发者上下文。continue: false 会为了兼容而解析,但不会阻止子智能体启动。

PreToolUse#

PreToolUse 可以拦截 Bash、通过 apply_patch 完成的文件编辑、MCP tool calls 和其他本地 function tools。支持的路径与例外请参见工具覆盖范围

matcher 会作用在 tool_name 和 matcher aliases 上。对于通过 apply_patch 完成的文件编辑,matcher 值可以使用 apply_patchEditWrite;hook input 中仍会报告 tool_name: "apply_patch"

通用输入字段 外,还会额外提供:

字段类型含义
turn_idstringCodex 扩展字段。当前激活会话轮次的 ID。
tool_namestring标准 hook 工具名,例如 Bashapply_patch,或 mcpfsread 这类 MCP 名称。
tool_use_idstring本次调用对应的 tool-call id。
tool_inputJSON value工具专属输入。Bashapply_patch 使用 tool_input.command,MCP 与其他本地 function tools 会发送各自的参数。

写到 stdout 的纯文本会被忽略。

如果向 stdout 输出 JSON,可以使用 systemMessage,也可以通过下面这个事件专属结构阻止 Bash 命令执行:

json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by hook."
}
}

Codex 也接受旧版阻止格式:

json
{
"decision": "block",
"reason": "Destructive command blocked by hook."
}

你也可以直接使用退出码 2,并把阻止原因写到 stderr

如需在不阻止调用的情况下追加模型可见上下文,请返回 hookSpecificOutput.additionalContext

json
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "The pending command touches generated files."
}
}

若要在不阻止调用的情况下改写受支持的工具调用,请返回 permissionDecision: "allow" 并附带 updatedInput

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

对于 Bash 命令和 apply_patchupdatedInput 必须包含字符串类型的 command 字段。对于 MCP 与其他本地 function tools,updatedInput 是替换后的参数对象。只应在 permissionDecision: "allow" 时返回 updatedInput;其他 updatedInput 形态会被报告为错误。

permissionDecision: "ask"、旧版 decision: "approve"continue: falsestopReasonsuppressOutput 虽然会被解析,但目前尚未支持。Codex 会把这次 hook 运行标记为失败、报告错误,并继续执行工具调用。

PermissionRequest#

PermissionRequest 会在 Codex 即将请求审批时运行,例如 shell 提权或托管网络审批。它可以允许请求、拒绝请求,或者不做决定并让常规审批提示继续显示。它不会在不需要审批的命令上运行。

matcher 会作用在 tool_name 和 matcher aliases 上。当前标准值包括 Bashapply_patch,以及 mcpservertool 这类 MCP tool names;apply_patch 也会匹配 EditWrite

通用输入字段 外,还会额外提供:

字段类型含义
turn_idstringCodex 扩展字段。当前激活会话轮次的 ID。
tool_namestring标准 hook 工具名,例如 Bashapply_patch,或 mcpfsread 这类 MCP 名称。
tool_inputJSON value工具专属输入。Bashapply_patch 使用 tool_input.command,MCP tools 会发送所有参数。
tool_input.description`string \null`Codex 提供时的人类可读审批原因。

写到 stdout 的纯文本会被忽略。

某些工具输入可能包含人类可读的说明,但不要假设每个工具都会提供 tool_input.description 字段。

如需批准请求,请返回:

json
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "allow"
}
}
}

如需拒绝请求,请返回:

json
{
"hookSpecificOutput": {
"hookEventName": "PermissionRequest",
"decision": {
"behavior": "deny",
"message": "Blocked by repository policy."
}
}
}

如果多个命中的 hook 都返回了 decision,任意 deny 都会优先生效。否则,一个 allow 会让请求继续执行,并且不再显示审批提示。如果没有命中的 hook 做出决定,Codex 会使用正常审批流程。

不要为 PermissionRequest 返回 updatedInputupdatedPermissionsinterrupt;这些字段预留给未来行为,目前会按关闭失败处理。

PostToolUse#

PostToolUse 会在受支持工具产生输出后运行,包括 Bash、apply_patch、MCP tool calls 和其他本地 function tools。对 Bash 来说,命令以非零状态退出后也会运行。它无法撤销已经执行过的工具副作用。支持的路径与例外请参见工具覆盖范围

matcher 会作用在 tool_name 和 matcher aliases 上。对于通过 apply_patch 完成的文件编辑,matcher 值可以使用 apply_patchEditWrite;hook input 中仍会报告 tool_name: "apply_patch"

通用输入字段 外,还会额外提供:

字段类型含义
turn_idstringCodex 扩展字段。当前激活会话轮次的 ID。
tool_namestring标准 hook 工具名,例如 Bashapply_patch,或 mcpfsread 这类 MCP 名称。
tool_use_idstring本次调用对应的 tool-call id。
tool_inputJSON value工具专属输入。Bashapply_patch 使用 tool_input.command,MCP 与其他本地 function tools 会发送各自的参数。
tool_responseJSON value工具专属输出。MCP tools 会发送 MCP 调用结果;其他本地 function tools 通常发送模型可见输出。

写到 stdout 的纯文本会被忽略。

如果向 stdout 输出 JSON,可以使用 systemMessage,并支持下面这个事件专属结构:

json
{
"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 运行标记为失败、报告错误,并继续正常处理工具结果。

来自 code mode 的工具调用#

模型通过 code mode 在 JavaScript 中调用工具时,hook decision 会应用到该嵌套调用。PreToolUse 可以在工具运行前阻止调用或改写输入。阻止型 PostToolUse 无法撤销工具副作用,但可以阻止原始结果送达正在运行的脚本。

Hook 结果Code mode 收到的行为
PreToolUse 阻止调用工具运行前,tool promise 会 reject。
PreToolUse 返回 updatedInput工具使用改写后的输入运行,promise 以该结果 resolve。
PostToolUse 返回 decision: "block" 或以退出码 2 结束工具先运行,随后 promise 会以 hook 原因 reject。
PostToolUse 返回 continue: falseCodex 使用 hook 反馈作为模型可见结果,但不会 reject 嵌套 tool promise。

PreCompact#

PreCompact 会在 Codex 压缩对话之前运行。matcher 会作用在 trigger 上,取值为 manualauto

通用输入字段 外,还会额外提供:

字段类型含义
turn_idstringCodex 扩展字段。当前激活会话轮次的 ID。
triggerstring触发压缩的来源:manualauto

写到 stdout 的纯文本会被忽略。

写到 stdout 的 JSON 支持通用输出字段。如果匹配的 PreCompact hook 返回 continue: false,Codex 会在压缩前停止。

PostCompact#

PostCompact 会在 Codex 压缩对话之后运行。matcher 会作用在 trigger 上,取值为 manualauto

通用输入字段 外,还会额外提供:

字段类型含义
turn_idstringCodex 扩展字段。当前激活会话轮次的 ID。
triggerstring触发压缩的来源:manualauto

写到 stdout 的纯文本会被忽略。

写到 stdout 的 JSON 支持通用输出字段。如果匹配的 PostCompact hook 返回 continue: false,Codex 会在压缩后停止。

UserPromptSubmit#

matcher 当前对这个事件不起作用。

通用输入字段 外,还会额外提供:

字段类型含义
turn_idstringCodex 扩展字段。当前激活会话轮次的 ID。
promptstring即将发送的用户提示词。

写到 stdout 的纯文本会被加入为额外的开发者上下文。

如果向 stdout 输出 JSON,则支持 通用输出字段 和下面这个事件专属结构:

json
{
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "Ask for a clearer reproduction before editing files."
}
}

其中 additionalContext 会被加入为额外的 开发者上下文。

如果你想阻止这条提示词,可返回:

json
{
"decision": "block",
"reason": "Ask for confirmation before doing that."
}

你也可以使用退出码 2,并把阻止原因写到 stderr

SubagentStop#

这个事件中的 matcher 会作用在 agent_type 上。

通用输入字段 外,还会额外提供:

字段类型含义
turn_idstringCodex 扩展字段。当前激活会话轮次的 ID。
agent_idstring子智能体标识。
agent_typestring子智能体类型或配置档案。
agent_transcript_path`string \null`子智能体 transcript 文件路径;如果不存在则为 null
stop_hook_activeboolean这个子智能体是否已经被继续过。
last_assistant_message`string \null`最新子智能体 assistant 消息;如果不可用则为 null

SubagentStop 在退出码为 0 时需要向 stdout 输出 JSON。对于这个事件,纯文本输出是无效的。

输出 JSON 时,支持通用输出字段。如果你想让 Codex 继续子智能体流程,可返回:

json
{
"decision": "block",
"reason": "Run one more focused pass inside the subagent."
}

你也可以使用退出码 2,并把继续执行的原因写到 stderr

如果有任意一个匹配的 SubagentStop hook 返回 continue: false,它会优先于其他匹配 SubagentStop hooks 的 continuation 决策生效。

Stop#

matcher 当前对这个事件不起作用。

通用输入字段 外,还会额外提供:

字段类型含义
turn_idstringCodex 扩展字段。当前激活会话轮次的 ID。
stop_hook_activeboolean当前这个会话轮次是否已经被 Stop 继续过一次。
last_assistant_message`string \null`最新 assistant 消息文本;如果不可用则为 null

Stop 要求在退出码为 0 时向 stdout 输出 JSON。对于这个事件,纯文本输出是无效的。

输出 JSON 时,支持 通用输出字段。如果你想让 Codex 继续运行,可返回:

json
{
"decision": "block",
"reason": "Run one more pass over the failing tests."
}

你也可以使用退出码 2,并把继续执行的原因写到 stderr

对这个事件来说,decision: "block" 并不会拒绝当前会话轮次。相反,它会告诉 Codex 继续,并自动创建一条继续执行提示词,把你的 reason 当作新的用户提示词发送下去。

如果有任意一个命中的 Stop hook 返回 continue: false,它会优先于其他 Stop hooks 的 continuation 决策生效。

Schema 定义#

链接指向的 main 分支 schema 可能包含当前版本尚未提供的 hook 字段。请以本页说明作为当前版本的行为参考。

如果你需要当前精确的线格式,请查看 Codex GitHub 仓库 中生成的 schema。

本站实践建议#

使用“钩子”扩展 Codex 时,只启用当前任务需要的能力,并检查其可访问的数据与可执行操作。团队共享前应先完成权限和失败场景测试。

Codex API 与国内使用#

在实践“钩子”相关功能时,如需为 Codex 配置 OpenAI-compatible API,可以前往 APIBest 获取 API Key。第三方服务的模型映射、价格、额度和数据处理方式以 APIBest 当前说明为准。