钩子
Codex 中文站说明: 本页围绕“钩子”重新补充了中文使用场景和验证重点。界面名称可能随 Codex 版本更新,请以当前客户端为准。
在 Codex 生命周期中运行确定性的脚本
钩子是 Codex 的一套扩展框架。它允许你把自己的脚本插入智能体循环中,从而实现例如以下能力:
- 把聊天发送到自定义日志或分析系统
- 扫描团队提示词,阻止误粘贴 API key
- 自动总结聊天,生成持久记忆
- 在聊天轮次结束时运行自定义校验检查,强制执行团队标准
- 当工作目录匹配特定路径时,动态调整提示词策略
需要留意这些运行时行为:
- 来自多个文件的匹配钩子都会运行。
- 对同一事件命中的多个命令型钩子会并发启动,因此一个钩子不能阻止其他已命中的钩子启动。
- 非托管命令型钩子必须经过审核并被信任后才会运行。
Hooks 会在对话的不同阶段运行:
| 阶段 | Hooks |
|---|---|
| 会话轮次期间 | PreToolUse、PermissionRequest、PostToolUse、PreCompact、PostCompact、UserPromptSubmit、SubagentStop、Stop |
| 会话或子智能体启动时 | SessionStart、SubagentStart |
| 主对话线程结束时 | SessionEnd(不会为子智能体运行) |
Codex 在哪里查找钩子
Codex 会在当前激活配置层旁边查找以下任一形式的钩子配置:
hooks.jsonconfig.toml中的内联[hooks]表
已安装插件也可以通过插件 manifest 或默认的 hooks/hooks.json 文件打包生命周期配置。插件打包规则请参见构建插件。
实际使用中,最常见也最有用的四个位置是:
~/.codex/hooks.json~/.codex/config.toml<repo>/.codex/hooks.json<repo>/.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 分成三层:
- 事件名,例如
PreToolUse、PostToolUse、PreCompact、SubagentStart或Stop - 决定该事件何时命中的 matcher 分组
- 当 matcher 命中时实际执行的一个或多个钩子处理器
{
"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
}
]
}
]
}
}说明:
description是hooks.json可选的顶层元数据,不会改变哪些 hooks 会运行。timeout的单位是秒。- 如果省略
timeout,大多数 hooks 会使用600秒。 SessionEnd默认使用1秒,最大支持3秒。statusMessage是可选的。commandWindows是可选的 Windows 专用命令覆盖。在 TOML 中可以使用command_windows或commandWindows。- Codex 会解析
async选项,但目前还不支持异步命令型钩子。 - 目前只有
type: "command"的处理器会运行。prompt和agent处理器会被解析,但会被跳过。 - 命令会以当前会话的
cwd作为工作目录运行。 - 对仓库级钩子,优先使用基于 Git 根目录解析的路径,而不是
.codex/hooks/...这类相对路径。Codex 可能从子目录启动,基于 Git 根目录的写法更稳定。
config.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 中关闭,请设置:
[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。
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 对象数组。
{
"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_ROOT和CLAUDE_PLUGIN_DATA。
Plugin hooks 使用和其他 hooks 相同的事件 schema。安装或启用插件并不会自动信任它的 hooks;Codex 会跳过 plugin-bundled hooks,直到你审核并信任当前 hook 定义。
匹配器模式
matcher 字段是一个正则表达式字符串,用来过滤 hook 何时触发。使用 "*"、"",或完全省略 matcher,都表示匹配该事件的所有支持触发。
当前只有部分 Codex 事件真正会使用 matcher:
| 事件 | matcher 过滤的对象 | 说明 |
|---|---|---|
PermissionRequest | 工具名 | 支持 Bash、apply_patch* 和 MCP tool names。 |
PostToolUse | 工具名 | 参见工具覆盖范围。 |
PostCompact | compact 触发源 | 值为 manual 或 auto。 |
PreCompact | compact 触发源 | 值为 manual 或 auto。 |
PreToolUse | 工具名 | 参见工具覆盖范围。 |
SessionEnd | 结束原因 | 当前只有 other。 |
SessionStart | 启动来源 | 值为 startup、resume、clear 和 compact。 |
SubagentStart | 子智能体类型 | 值取决于启动的子智能体。 |
SubagentStop | 子智能体类型 | 值取决于停止的子智能体。 |
UserPromptSubmit | 不支持 | 该事件中配置的 matcher 会被忽略。 |
Stop | 不支持 | 该事件中配置的 matcher 会被忽略。 |
- 对
apply_patch,matcher值也可以使用Edit或Write。
示例:
Bash^apply_patch$Edit|Writemcp__filesystem__read_filemcp__filesystem__.*startup|resume|clear|compactmanual|auto
工具覆盖范围
PreToolUse 和 PostToolUse 不只能够观察 shell 与 MCP 调用。大多数本地 function tools 使用同一条 hook 路径,因此你可以匹配工具名、检查其 JSON 参数,并通过 PreToolUse 阻止或改写调用。
| 工具路径 | PreToolUse | PostToolUse | 说明 |
|---|---|---|---|
| Shell 命令 | 是 | 是 | 以 Bash 匹配。 |
Unified exec(exec_command) | 是 | 是 | 以 Bash 匹配。命令结束时,后续一次 write_stdin 轮询可能会送达原命令的 PostToolUse。 |
apply_patch | 是 | 是 | 可用 apply_patch、Edit 或 Write 匹配。 |
| MCP tools | 是 | 是 | 匹配 MCP tool name,例如 mcp__filesystem__read_file。 |
| 其他本地 function tools | 是 | 是 | 匹配 function tool name,例如 update_plan;spawn_agent 也会匹配 Agent。 |
WebSearch 等托管工具 | 否 | 否 | 这些工具不使用本地 function-tool hook 路径。 |
write_stdin 是已有 unified-exec 会话的传输通道。它向已通过 PreToolUse 的命令发送输入或轮询状态时,不会再次运行 PreToolUse。
某些专用工具路径可以选择不使用默认 hook 路径。请把工具 hooks 视为有用的护栏,而不是完整的强制边界。
通用输入字段
每个命令型钩子都会通过 stdin 收到一个 JSON 对象。
这些共享字段通常最常用:
| 字段 | 类型 | 含义 |
|---|---|---|
session_id | string | 当前 Codex 会话 ID。子智能体 hooks 使用父会话 ID。 |
transcript_path | string | null | 会话 transcript 文件路径;如果不存在则为 null。 |
cwd | string | 当前会话的工作目录。 |
hook_event_name | string | 当前 hook 事件名。 |
model | string | Codex 扩展字段。当前激活模型的 slug。 |
按会话轮次作用域运行的 hooks 会在各自的事件专属字段表里额外列出 turn_id。
SessionStart、PreToolUse、PermissionRequest、PostToolUse、UserPromptSubmit、SubagentStart、SubagentStop 和 Stop 也会包含 permission_mode,表示当前权限模式,值可能是 default、acceptEdits、plan、dontAsk 或 bypassPermissions。
transcript_path 只是为了方便指向聊天 transcript;transcript 格式不是 hooks 的稳定接口,未来可能变化。
如果你需要完整的当前线格式,请参见 Schema 定义。
通用输出字段
SessionStart、PreCompact、PostCompact、UserPromptSubmit、SubagentStop 和 Stop 支持以下共享 JSON 字段。SubagentStart 对 systemMessage 和 hook-specific context 接受相同结构,但 continue: false 不会阻止子智能体启动:
{
"continue": true,
"stopReason": "optional",
"systemMessage": "optional",
"suppressOutput": false
}| 字段 | 作用 |
|---|---|
continue | 若为 false,表示该次 hook 运行被标记为停止。 |
stopReason | 记录为停止原因。 |
systemMessage | 作为警告显示在界面或事件流中。 |
suppressOutput | 当前会被解析,但尚未真正实现。 |
退出码为 0 且没有任何输出,会被视为成功,Codex 会继续执行。
PreToolUse 和 PermissionRequest 支持 systemMessage,但当前不支持 continue、stopReason 和 suppressOutput。如果 PreToolUse hook 返回了这些不支持的字段,Codex 会把这次 hook 运行标记为失败、报告错误,并继续执行工具调用。
PostToolUse 支持 systemMessage、continue: false 和 stopReason。suppressOutput 虽然会被解析,但当前仍未真正支持。
超长 hook 输出
Codex 会把每一条模型可见 hook 输出限制在大约 2,500 tokens。如果 hook 返回更多内容,Codex 会把完整文本保存到 <temp_dir>/hook_outputs/<session_id>/<uuid>.txt,并把包含文件路径的首尾预览交给模型。如果文件无法写入,模型仍会收到截断后的预览。
该限制适用于来自 SessionStart、SubagentStart、PreToolUse、PostToolUse 和 UserPromptSubmit 的额外上下文,来自 PostToolUse 的反馈,以及来自 Stop 和 SubagentStop 的继续提示。限制按每一条额外上下文或继续提示分别计算;对 PostToolUse 反馈,Codex 会先合并所有匹配 hooks 的反馈,再对合并后的消息应用限制。
由于过长输出可能写入磁盘,请避免在 hook 输出中返回 secrets 或其他敏感数据。
Hooks
SessionStart
这个事件中的 matcher 会作用在 source 上。
除 通用输入字段 外,还会额外提供:
| 字段 | 类型 | 含义 |
|---|---|---|
source | string | 会话启动方式:startup、resume、clear 或 compact。 |
写到 stdout 的纯文本会被追加为额外的 开发者上下文。
如果向 stdout 输出 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 事件。
除通用输入字段外,还会额外提供:
| 字段 | 类型 | 含义 |
|---|---|---|
reason | string | 会话结束原因:other。 |
例如,SessionEnd 命令会收到:
{
"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_id | string | 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 tool calls 和其他本地 function tools。支持的路径与例外请参见工具覆盖范围。
matcher 会作用在 tool_name 和 matcher aliases 上。对于通过 apply_patch 完成的文件编辑,matcher 值可以使用 apply_patch、Edit 或 Write;hook input 中仍会报告 tool_name: "apply_patch"。
除 通用输入字段 外,还会额外提供:
| 字段 | 类型 | 含义 |
|---|---|---|
turn_id | string | Codex 扩展字段。当前激活会话轮次的 ID。 |
tool_name | string | 标准 hook 工具名,例如 Bash、apply_patch,或 mcp__fs__read 这类 MCP 名称。 |
tool_use_id | string | 本次调用对应的 tool-call id。 |
tool_input | JSON value | 工具专属输入。Bash 和 apply_patch 使用 tool_input.command,MCP 与其他本地 function tools 会发送各自的参数。 |
写到 stdout 的纯文本会被忽略。
如果向 stdout 输出 JSON,可以使用 systemMessage,也可以通过下面这个事件专属结构阻止 Bash 命令执行:
{
"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 与其他本地 function tools,updatedInput 是替换后的参数对象。只应在 permissionDecision: "allow" 时返回 updatedInput;其他 updatedInput 形态会被报告为错误。
permissionDecision: "ask"、旧版 decision: "approve"、continue: false、stopReason 和 suppressOutput 虽然会被解析,但目前尚未支持。Codex 会把这次 hook 运行标记为失败、报告错误,并继续执行工具调用。
PermissionRequest
PermissionRequest 会在 Codex 即将请求审批时运行,例如 shell 提权或托管网络审批。它可以允许请求、拒绝请求,或者不做决定并让常规审批提示继续显示。它不会在不需要审批的命令上运行。
matcher 会作用在 tool_name 和 matcher aliases 上。当前标准值包括 Bash、apply_patch,以及 mcp__server__tool 这类 MCP tool names;apply_patch 也会匹配 Edit 和 Write。
除 通用输入字段 外,还会额外提供:
| 字段 | 类型 | 含义 |
|---|---|---|
turn_id | string | Codex 扩展字段。当前激活会话轮次的 ID。 |
tool_name | string | 标准 hook 工具名,例如 Bash、apply_patch,或 mcp__fs__read 这类 MCP 名称。 |
tool_input | JSON value | 工具专属输入。Bash 和 apply_patch 使用 tool_input.command,MCP tools 会发送所有参数。 |
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."
}
}
}如果多个命中的 hook 都返回了 decision,任意 deny 都会优先生效。否则,一个 allow 会让请求继续执行,并且不再显示审批提示。如果没有命中的 hook 做出决定,Codex 会使用正常审批流程。
不要为 PermissionRequest 返回 updatedInput、updatedPermissions 或 interrupt;这些字段预留给未来行为,目前会按关闭失败处理。
PostToolUse
PostToolUse 会在受支持工具产生输出后运行,包括 Bash、apply_patch、MCP tool calls 和其他本地 function tools。对 Bash 来说,命令以非零状态退出后也会运行。它无法撤销已经执行过的工具副作用。支持的路径与例外请参见工具覆盖范围。
matcher 会作用在 tool_name 和 matcher aliases 上。对于通过 apply_patch 完成的文件编辑,matcher 值可以使用 apply_patch、Edit 或 Write;hook input 中仍会报告 tool_name: "apply_patch"。
除 通用输入字段 外,还会额外提供:
| 字段 | 类型 | 含义 |
|---|---|---|
turn_id | string | Codex 扩展字段。当前激活会话轮次的 ID。 |
tool_name | string | 标准 hook 工具名,例如 Bash、apply_patch,或 mcp__fs__read 这类 MCP 名称。 |
tool_use_id | string | 本次调用对应的 tool-call id。 |
tool_input | JSON value | 工具专属输入。Bash 和 apply_patch 使用 tool_input.command,MCP 与其他本地 function tools 会发送各自的参数。 |
tool_response | JSON value | 工具专属输出。MCP tools 会发送 MCP 调用结果;其他本地 function tools 通常发送模型可见输出。 |
写到 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 会记录这条反馈,用该反馈替换原始工具结果,并从 hook 提供的消息继续驱动模型。
你也可以使用退出码 2,并把反馈原因写到 stderr。
如果你想在命令已经执行后,阻止对原始工具结果的正常处理,可以返回 continue: false。Codex 会用你的反馈或停止文本替换原始工具结果,然后从那里继续。
updatedMCPToolOutput 和 suppressOutput 会被解析,但当前尚未真正支持。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: false | Codex 使用 hook 反馈作为模型可见结果,但不会 reject 嵌套 tool promise。 |
PreCompact
PreCompact 会在 Codex 压缩对话之前运行。matcher 会作用在 trigger 上,取值为 manual 或 auto。
除 通用输入字段 外,还会额外提供:
| 字段 | 类型 | 含义 |
|---|---|---|
turn_id | string | Codex 扩展字段。当前激活会话轮次的 ID。 |
trigger | string | 触发压缩的来源:manual 或 auto。 |
写到 stdout 的纯文本会被忽略。
写到 stdout 的 JSON 支持通用输出字段。如果匹配的 PreCompact hook 返回 continue: false,Codex 会在压缩前停止。
PostCompact
PostCompact 会在 Codex 压缩对话之后运行。matcher 会作用在 trigger 上,取值为 manual 或 auto。
除 通用输入字段 外,还会额外提供:
| 字段 | 类型 | 含义 |
|---|---|---|
turn_id | string | Codex 扩展字段。当前激活会话轮次的 ID。 |
trigger | string | 触发压缩的来源:manual 或 auto。 |
写到 stdout 的纯文本会被忽略。
写到 stdout 的 JSON 支持通用输出字段。如果匹配的 PostCompact hook 返回 continue: false,Codex 会在压缩后停止。
UserPromptSubmit
matcher 当前对这个事件不起作用。
除 通用输入字段 外,还会额外提供:
| 字段 | 类型 | 含义 |
|---|---|---|
turn_id | string | 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 扩展字段。当前激活会话轮次的 ID。 |
agent_id | string | 子智能体标识。 |
agent_type | string | 子智能体类型或配置档案。 |
agent_transcript_path | string | null | 子智能体 transcript 文件路径;如果不存在则为 null。 |
stop_hook_active | boolean | 这个子智能体是否已经被继续过。 |
last_assistant_message | string | null | 最新子智能体 assistant 消息;如果不可用则为 null。 |
SubagentStop 在退出码为 0 时需要向 stdout 输出 JSON。对于这个事件,纯文本输出是无效的。
输出 JSON 时,支持通用输出字段。如果你想让 Codex 继续子智能体流程,可返回:
{
"decision": "block",
"reason": "Run one more focused pass inside the subagent."
}你也可以使用退出码 2,并把继续执行的原因写到 stderr。
如果有任意一个匹配的 SubagentStop hook 返回 continue: false,它会优先于其他匹配 SubagentStop hooks 的 continuation 决策生效。
Stop
matcher 当前对这个事件不起作用。
除 通用输入字段 外,还会额外提供:
| 字段 | 类型 | 含义 |
|---|---|---|
turn_id | string | Codex 扩展字段。当前激活会话轮次的 ID。 |
stop_hook_active | boolean | 当前这个会话轮次是否已经被 Stop 继续过一次。 |
last_assistant_message | string | null | 最新 assistant 消息文本;如果不可用则为 null。 |
Stop 要求在退出码为 0 时向 stdout 输出 JSON。对于这个事件,纯文本输出是无效的。
输出 JSON 时,支持 通用输出字段。如果你想让 Codex 继续运行,可返回:
{
"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 当前说明为准。