Open Interpreter Hooks 生命周期钩子完全指南:事件、信任模型与源码级原理
Hooks 是 Open Interpreter 提供的一套轻量级生命周期钩子机制:在 Agent 会话启动、用户提交 Prompt、工具调用前后、上下文压缩等关键节点,执行确定性的外部命令脚本,用于策略检查、审计日志、Prompt 扫描、自定义上下文注入与事后校验。读完本文,你将掌握 Hooks 的启用方式、配置文件的放置规则、全部事件与 matcher 写法、JSON/TOML 声明格式,以及命令 Hook 与模型之间的输入输出协议,并从仓库源码理解其发现、信任与调度实现。
本指南以 docs/hooks.md 为纲,结合 Open Interpreter 仓库中 hooks 功能模块的 Rust 实现(codex-rs/hooks)展开,帮助你在真实项目中正确使用 Hooks 作为"护栏",而不是替代沙箱与审批。
Hooks 是什么:为 Agent 生命周期挂载确定性脚本
Hooks 让你围绕 Open Interpreter 的事件(events)运行确定性的命令(deterministic commands)。它非常适合但不限于以下四类诉求:
- 策略检查:在危险工具执行前按正则拦截或审批;
- 日志/审计:记录每一次工具调用、Prompt 提交与会话事件;
- Prompt 扫描:对即将发给模型的用户输入做敏感词、越狱检测;
- 自定义上下文注入 / 事后校验:把外部系统信息喂给模型,或在运行结束后做结果验证。
它的定位与 Sandbox 不同:文档明确指出 Hooks 是护栏(guardrails),不是沙箱(sandboxing)与审批(approvals)的替代品——真正要隔离环境,请配合仓库中的 Linux/macOS/Windows 沙箱能力使用。
默认开启与全局开关
Hooks 默认启用,对应配置项位于 config 的 [features] 段:
[features]
hooks = true
只有当你有意希望整个 Agent 生命周期不运行任何脚本时,才关闭它:
[features]
hooks = false
关闭后,仓库中 hooks 引擎将不再发现与派发任何钩子处理函数。
Hooks 存放在哪里:发现位置与叠加规则
Open Interpreter 会在当前生效的配置层(config layers)旁边发现 hooks。文档给出的候选位置与作用域如下:
| 位置 | 作用域 |
|---|---|
~/.openinterpreter/hooks.json |
用户级(User) |
~/.openinterpreter/config.toml |
用户级内联 hooks(User inline) |
.openinterpreter/hooks.json |
受信任项目(Trusted project) |
.openinterpreter/config.toml |
受信任项目内联 hooks(Trusted project inline) |
| 已启用的插件 | 插件自带 hooks(Plugin-bundled) |
关键语义:多个来源同时匹配时,它们会全部执行。更高优先级的配置层不会替换掉低优先级层的 hooks——Hooks 是"叠加"而非"覆盖"的。这一行为在源码中被精确实现:发现逻辑 discover_handlers 遍历 config_layer_stack.layers_low_to_high(),从低优先级层到高优先级层依次收集每个层级的 hooks 处理器,全部汇入同一个处理函数列表(见 codex-rs/hooks/src/engine/discovery.rs)。
另外从源码看,一个层内有两种声明载体(hooks.json 与 config.toml 内联),若同一层同时提供两者且都非空,引擎会给出类似 "loading hooks from both ... prefer a single representation for this layer" 的告警——因此建议同一配置层只选用其中一种表示形式,避免定义重复。
信任模型:非托管 Hook 必须先审查
Hooks 会执行任意命令,因此存在代码执行风险。Open Interpreter 的信任规则如下:
- 非托管的命令 hooks(non-managed command hooks)必须先经过人工审查并标记为受信任,才会被执行;
- 信任关系是基于 Hook 的精确定义(exact hook definition)记录的——即命令字符串、事件、matcher 等组成的完整定义。一旦 Hook 定义发生变化(哪怕只改了一个参数),就需要重新审查,旧信任不自动生效;
- 使用斜杠命令审查与开关:
/hooks
若存在已在外部完成 hooks 校验的自动化流水线,可以传入 --dangerously-bypass-hook-trust 跳过信任检查,但文档强调这应当极其罕见。对应到实现,HookDiscoveryPolicy 中有一个 bypass_hook_trust 开关,另有一个 allow_managed_hooks_only 策略(当配置层要求仅允许托管 hooks 时,非托管来源会被直接过滤),见 codex-rs/hooks/src/engine/discovery.rs。此外,与 hooks.json 并列的还有托管 hooks(managed hooks)概念,来自配置层的 managed_hooks 需求,它们以托管来源注入,不受"需手动信任"约束。
支持的事件(Events)
Hook 引擎在 Agent 生命周期的十个节点提供事件挂钩:
| 事件 | 触发时机 | matcher 目标 |
|---|---|---|
SessionStart |
会话启动、恢复(resume)、清空(clear)或压缩(compact)时 | startup|resume|clear|compact |
UserPromptSubmit |
用户 prompt 即将发送给模型时 | 无 / 全部 |
PreToolUse |
受支持的 shell、patch 或 MCP 工具运行之前 | 工具名 |
PermissionRequest |
审批弹窗显示之前 | 无 / 全部 |
PostToolUse |
受支持的 shell、patch 或 MCP 工具执行完毕之后 | 工具名 |
PreCompact |
上下文压缩开始之前 | manual|auto |
PostCompact |
上下文压缩完成之后 | manual|auto |
SubagentStart |
子代理(subagent)启动时 | agent_type |
SubagentStop |
子代理停止时 | agent_type |
Stop |
一轮对话(turn)即将结束时 | 无 / 全部 |
从源码结构看,每个事件都有对应的独立 Rust 模块实现事件特有的输入构造与结果聚合逻辑(见 codex-rs/hooks/src/events)。例如 SessionStart 的触发来源在源码中建模为枚举 SessionStartSource { Startup, Resume, Clear, Compact },其字符串形式正是 matcher 使用的 startup、resume、clear、compact(见 codex-rs/hooks/src/events/session_start.rs)。SessionStart 事件同样在 SubagentStart 时通过共享的 StartHookTarget 机制触发,说明子代理的启动本质上复用"会话类"事件管线。
声明 Hooks:JSON 与 TOML 两种形式
JSON 形式(hooks.json)
{
"hooks": {
"PreToolUse": [
{
"matcher": "^Bash$",
"hooks": [
{
"type": "command",
"command": "python3 .openinterpreter/hooks/pre_tool_use.py",
"timeout": 30,
"statusMessage": "Checking command"
}
]
}
]
}
}
TOML 形式(config.toml 内联)
[[hooks.PreToolUse]]
matcher = "^Bash$"
[[hooks.PreToolUse.hooks]]
type = "command"
command = "python3 .openinterpreter/hooks/pre_tool_use.py"
timeout = 30
statusMessage = "Checking command"
两种结构等价。结构层级为:hooks → 事件名 → matcher 分组 → hooks 列表。常用字段说明:
matcher:正则表达式,决定该组 hook 命中哪些目标(见下节);type:Hook 类型,command即执行外部命令行程序;command:要执行的命令行(支持带参数,如python3 ...);timeout:命令超时秒数,超时视为失败处理;statusMessage:hook 运行时在终端展示的状态提示,例如 "Checking command",让用户感知到有校验在发生。
多个来源全部执行
再次强调叠加语义:若用户级与项目级同时声明了同一事件下的 hooks,它们都会运行,不会因配置层优先级更高而吞掉低层级的 Hook。
Matcher 匹配规则
Matcher 是正则表达式,对每个事件匹配不同目标:
- 工具类事件(
PreToolUse、PostToolUse)匹配工具名。例如^Bash$只命中 shell 工具; SessionStart匹配startup|resume|clear|compact四种来源;- 压缩类事件(
PreCompact、PostCompact)匹配manual|auto,区分手工触发与自动压缩。
文档给出的 matcher 示例:
Bash
^apply_patch$
Edit|Write
mcp__filesystem__read_file
startup|resume
manual|auto
其中 Edit|Write 表示同时命中文件编辑与写入两类工具,mcp__filesystem__read_file 说明 MCP 工具按 mcp__<server>__<tool> 的命名规则匹配,因此你也可以针对某个 MCP 服务器的特定工具做精细拦截。从源码结构看,matcher 表达式在事件公共层会经过校验与模式编译处理(见 codex-rs/hooks/src/events/common.rs 中 matcher 相关逻辑,如 matcher_pattern_for_event 与 validate_matcher_pattern),非法正则不会被静默吞掉。
为什么 PreToolUse 能感知多个"别名"
在 pre_tool_use.rs 中,PreToolUseRequest 除了 tool_name 还带有 matcher_aliases: Vec<String>;派发前,引擎会对工具名与所有别名执行 matcher_inputs 展开(见同文件 preview/run 中 common::matcher_inputs),再进行 select_handlers_for_matcher_inputs 选择命中分组的 handler。这就是为什么同一工具可能被多组 matcher 同时命中——所有命中的分组都会执行。
Hook 输入与输出协议
命令型 Hook(type = "command")的运行协议是通过 stdin 接收一个 JSON 对象,通过 stdout 返回 JSON 结果(引擎侧通过输出解析器读取)。
输入:stdin 上的 JSON 对象
所有事件共享的基础字段包括:session_id、cwd、hook_event_name、model,以及各事件特有的字段。以仓库中自动生成的 pre-tool-use.command.input 校验模式(见 codex-rs/hooks/schema/generated/pre-tool-use.command.input.schema.json)为例,PreToolUse 事件的输入完整字段为:
- 通用字段:
session_id、turn_id、cwd、transcript_path、model、permission_mode、agent_id、agent_type; - 事件特有字段:
tool_name、tool_use_id、tool_input(工具调用的原始输入 JSON,schema 中该字段类型为true,即任意 JSON); hook_event_name为常量"PreToolUse";permission_mode是枚举:default、acceptEdits、plan、dontAsk、bypassPermissions,对应 Open Interpreter 的权限模式。
UserPromptSubmit 事件的输入则在此基础上携带 prompt 字段(用户原始输入文本),便于做 Prompt 扫描与改写(见 codex-rs/hooks/schema/generated/user-prompt-submit.command.input.schema.json)。
输出:阻止 / 补充上下文 / 改写输入
不同事件对输出能力的支持不同:
- 部分事件可以向模型追加可见上下文(additional context):将自定义信息注入后续对话;
- 部分事件可以阻止或拒绝一次工具调用(block/deny),例如
PreToolUse。
文档给出的"拒绝一次命令执行"输出示例:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Blocked by repository policy."
}
}
结合源码中自动生成的输出 schema(见 codex-rs/hooks/schema/generated/pre-tool-use.command.output.schema.json),PreToolUse 的完整输出契约实际上包括:
hookSpecificOutput.permissionDecision:allow/deny/ask——deny直接拦截工具执行;ask可把决策重新抛回审批流程;hookSpecificOutput.permissionDecisionReason:决策原因,将透传给模型与界面;hookSpecificOutput.additionalContext:追加给模型的可见上下文;hookSpecificOutput.updatedInput:改写后的工具入参;hookSpecificOutput.hookEventName:必填,用于区分输出归属的事件;- 顶层另有
decision(approve/block)、reason、continue(默认true,决定后续 hook 是否继续执行)、suppressOutput、systemMessage、stopReason等字段,供更精细地控制流程。
这类 JSON Schema 由仓库按事件逐一维护(见 codex-rs/hooks/schema/generated 目录下各 *.input.schema.json / *.output.schema.json),是编写 Hook 脚本时最权威的字段字典。
在引擎实现上,PreToolUse 事件运行时会聚合所有命中 handler 的结果:只要任一 handler 标记 should_block,该工具调用即被阻止,并携带首个阻断原因(见 codex-rs/hooks/src/events/pre_tool_use.rs)。这就是"多来源 hooks 全部执行、任一否决即拦截"的执行语义。
源码视角:Hooks 引擎的四个环节
仓库将 hooks 功能实现为独立的 Rust crate(见 codex-rs/hooks/Cargo.toml),整体可拆为四条链路:
- 发现(Discovery):
discover_handlers按配置层栈低到高遍历,加载每个层级的hooks.json与config.toml内联 hooks,追加托管 hooks 与插件 hooks(插件还会注入PLUGIN_ROOT、PLUGIN_DATA等环境变量供脚本使用),最终输出 handler 列表与展示条目,见 engine/discovery.rs。 - 调度(Dispatcher):
select_handlers_for_matcher_inputs等函数按事件名与 matcher 输入选出命中的 handler 集合,见 engine/dispatcher.rs。 - 执行(Command Runner):为每个命令 handler 创建进程、写入 stdin JSON、施加超时并收集 stdout/stderr 结果,见 engine/command_runner.rs。
- 输出解析(Output Parser)与 Schema 加载:解析命令 stdout 中的 JSON,并依据 schema_loader.rs 与 schema/generated 下的事件专属 schema 校验输入输出。
每个事件模块(events/pre_tool_use.rs、events/session_start.rs 等)都遵循同一模式:构造本事件请求 → 序列化输入 JSON → 派发执行 → 按事件语义聚合结果(阻断 / 补充上下文 / 改写输入 / 透传事件记录)。引擎侧同时维护 Hook 的运行状态(running/hook run summary),用于 /hooks 命令展示与状态管理,并在事件执行失败时以 FailedContinue / FailedAbort 语义区分"继续执行其余 hook"与"中止整个操作"。
端到端示例:用 PreToolUse 实现"仓库策略门禁"
把上述能力串成一个可直接上手的场景——禁止在项目仓库中运行 git push 之外的危险 shell 命令。假定这是受信任项目,将以下内容放入项目根的 .openinterpreter/hooks.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "^Bash$",
"hooks": [
{
"type": "command",
"command": "python3 .openinterpreter/hooks/policy_gate.py",
"timeout": 15,
"statusMessage": "Checking against repo policy"
}
]
}
]
}
}
对应脚本 .openinterpreter/hooks/policy_gate.py 的大致骨架:
#!/usr/bin/env python3
import json, re, sys
data = json.load(sys.stdin) # 从 stdin 读取输入 JSON
cmd = json.loads(data["tool_input"].get("command", "{}")) if isinstance(data.get("tool_input"), dict) else ""
blocked = ["rm -rf", "git reset --hard", "curl .*\\|.*sh"]
if any(re.search(p, cmd) for p in blocked):
print(json.dumps({
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Blocked by repository policy."
}
}))
else:
print(json.dumps({"hookSpecificOutput": {"hookEventName": "PreToolUse"}}))
脚本按上文的输出契约,在命中策略时返回 deny 及理由,Open Interpreter 随即阻止该 shell 调用;未命中则返回空决策放行。首次执行前记得通过 /hooks 审查并信任该命令 Hook——改动脚本或配置后需重新信任。更精细的做法:用 additionalContext 注入项目专属约束、用 updatedInput 改写工具入参、用 ask 把敏感操作交回审批而非直接放行。
边界与最佳实践
- Hooks ≠ 安全边界:它们运行在你的机器上、拥有与 Open Interpreter 进程相同的权限,应视为策略表达层。真正的隔离请依赖沙箱与权限审批体系。
- 命令型 Hook 需可信:
hooks.json/脚本若被第三方篡改,等于任意代码执行入口,务必保持项目钩子文件与脚本的只读与版本受控。 - 事件选择要克制:
PreToolUse/PostToolUse在每个工具调用时都会触发,耗时的 Hook(如网络请求)会拖慢 Agent;合理设置timeout,只在必要时挂载。 - matcher 越精确越好:能用
^Bash$、^apply_patch$就用精确锚定,避免宽泛正则在每个工具调用上都白跑一遍。 - JSON/TOML 选一种:同一配置层同时写两种内联表示会触发引擎告警,保持单一声明源。
- 信任随定义变化失效:任何对已信任 Hook 的修改都会使其回到"未信任"状态,自动化发布流程应主动配合
/hooks重新审查,或仅在可控环境中使用--dangerously-bypass-hook-trust。
结合 docs/hooks.md 与 codex-rs/hooks 模块,你现在应能从声明格式到事件协议、再到内部调度与信任语义,完整掌控 Open Interpreter 的 Hooks 机制,并将其作为"会话策略层"接入自己的日志、审计与安全流程。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00