什么是 OpenClaw 挂钩? (以及为什么它们改变了你与人工智能代理的合作方式)
如果您曾经见过 AI 代理覆盖一个它不应该触及的文件,或者希望它在每次代码更改后自动运行您的测试套件 - OpenClaw 挂钩就是答案。它们让您能够在关键时刻拦截、反应和控制代理行为。
钩子是 在 OpenClaw 网关内运行的小型事件驱动脚本 在代理生命周期的特定点。将它们视为人工智能代理的中间件 - 它们位于代理与其调用的工具之间,为您提供可编程拦截层。
有两种不同的类型:
- 内部挂钩 — 执行的脚本 里面 网关进程本身。他们可以直接访问会话状态、工具调用元数据和代理的工作上下文。零网络开销。
- 网络钩子 — 当生命周期事件发生时触发到外部端点的 HTTP 回调。网关发送POST请求;您的服务器处理逻辑。
实际差异:内部挂钩用于快速、同步护栏和本地自动化。 Webhooks 适用于任何需要到达计算机外部的事物 - Slack 通知、CI 系统、日志平台。
内部 Hook 与 Webhooks — 您需要哪一个?
| 因素 | 内钩 | 网络钩子 |
|---|---|---|
| 执行地点 | 网关进程内部 | 外部 HTTP 服务器 |
| 延迟 | 接近零(同步) | 网络往返 |
| 会话状态访问 | 直接的 | 仅序列化有效负载 |
| 最适合 | 文件保护、自动格式化、本地脚本 | Slack 警报、审核日志记录、外部 API |
| 设置复杂性 | 低——只是一个目录+处理文件 | 中 — 需要一个正在运行的 HTTP 端点 |
| 阻止代理执行 | 是(PreToolUse 挂钩可以中止) | 通常是异步/非阻塞 |
决策规则: 如果你的钩子需要 防止 一个动作或 读取本地会话数据,使用内部挂钩。如果需要的话 通知外部系统 并且不需要阻止代理,使用 webhook。
OpenClaw Hook Discovery 的工作原理
网关使用 自动目录扫描 发现钩子。启动时,它会扫描配置的钩子目录并加载它找到的任何有效的钩子包。
激活钩子之前有两个重要的先决条件:
- 挂钩必须是 明确启用 — 仅一个钩子目录是不够的
- 至少 必须配置一个钩子条目 在您的网关设置中
这是一个常见的混淆点。您可以在正确的目录中拥有一个完美编写的挂钩,但如果网关没有被告知激活挂钩,它会默默地忽略它们。
每个钩子包只需要两个文件:
HOOK.md— 元数据文件,声明钩子的名称、版本、描述、生命周期事件订阅以及任何所需的权限handler.ts(或handler.js) — 包含事件触发时运行的实际逻辑的实现文件
HOOK.md 文件是网关在发现过程中首先读取的文件。如果格式错误或缺少必填字段,则挂钩将不会加载 - 没有错误,只是沉默。这是“我的钩子不起作用”报告的最常见原因。
每个开发人员都应该了解的四个生命周期事件
| 事件 | 当它着火时 | 常用 |
|---|---|---|
| 预工具使用 | 前 代理调用任何工具 | 阻止危险操作,验证输入 |
| 后期工具使用 | 后 工具调用完成 | 运行测试、格式化代码、记录结果 |
| 停止 | 当代理会话结束时 | 发送通知、刷新日志、清理 |
| 会话开始 | 当新的代理会话开始时 | 加载上下文、设置护栏、预热状态 |
预工具使用 是最强大的——这是唯一可以做到的事件 中止 执行之前的工具调用。如果您的挂钩在 PreToolUse 期间返回拒绝信号,则代理永远不会调用该工具。
后期工具使用 是自动化的主力。文件写好了吗?运行你的 linter。测试修改了?执行套件。代码已提交?触发构建。
分步:从头开始编写您的第一个自定义 Hook
大多数文档都会向您显示命令。这向您展示了从无到有的完整路径。
目标: 每次写入文件后自动运行 ESLint。
第 1 步 — 创建钩子目录
mkdir -p .OpenClaw/hooks/auto-lint
步骤 2 — 写入 HOOK.md 元数据
# auto-lint
**Version:** 1.0.0
**Event:** PostToolUse
**Description:** Runs ESLint on any file written by the agent
**Tools:** write_file, edit_file
Tools 字段将您的挂钩范围限定为特定工具调用。没有它,钩子就会启动 每一个 PostToolUse 事件 — 通常不是您想要的。
第 3 步 — 实施 handler.ts
import { PostToolUseEvent } from "@OpenClaw/sdk";
import { execSync } from "child_process";
export default function handler(event: PostToolUseEvent) {
const filePath = event.toolResult?.path;
if (!filePath) return;
try {
execSync(`npx eslint --fix "${filePath}"`, { stdio: "inherit" });
} catch (err) {
console.error(`[auto-lint] ESLint failed on ${filePath}`);
}
}
第 4 步 — 通过 CLI 启用
OpenClaw hooks enable auto-lint
第 5 步 — 验证其已加载
OpenClaw hooks list
您应该看到 auto-lint 的状态为 enabled。启动一个会话,写入一个文件,然后观察 linter 的触发。
用于 Hook 处理程序的 JavaScript 与 TypeScript — 2026 年选择什么
SDK 附带完整的 TypeScript 类型,从 2026 SDK 版本开始, TypeScript 是推荐的默认值 用于新钩子。
| 因素 | 打字稿 | JavaScript |
|---|---|---|
| 类型安全 | 完整 — 输入事件形状 | 无——运行时惊喜 |
| 编译步骤 | 必需(tsc 或 esbuild) | 没有任何 |
| SDK兼容性 | 一流的支持 | 支持但不支持自动完成 |
| 最适合 | 任何将被维护或共享的钩子 | 快速一次性脚本 |
如果您正在编写一个钩子,您将致力于版本控制或与团队共享,请使用 TypeScript。对于一次性的本地护栏,纯 JavaScript 就可以了——只需将其命名为 handler.js 并跳过编译步骤。
OpenClaw Hooks CLI 参考
| 命令 | 旗帜 | 它的作用 |
|---|---|---|
| 开爪钩列表 | --json |
列出所有已发现的挂钩及其状态 |
| OpenClaw hooks 检查 |
— | 显示 HOOK.md + 当前配置的完整元数据 |
| OpenClaw hooks 启用 <名称> | — | 激活当前项目的挂钩 |
| OpenClaw hooks 禁用 <名称> | — | 停用而不删除 |
| OpenClaw hooks 安装 |
--yes、--dry-run |
从注册表安装钩子包 |
| 开爪钩更新 | --all、--dry-run |
更新已安装的钩子包 |
管理 Hook Pack — 安装、更新和 --dry-run 工作流程
Hook 包将多个相关的 hook 捆绑为一个可安装单元。安装工作流程验证 完整性哈希 在将任何内容写入磁盘之前。
# Preview what would be installed without committing
OpenClaw hooks install productivity-pack --dry-run
# Install non-interactively (for CI environments)
OpenClaw hooks install productivity-pack --yes
# Update all installed packs
OpenClaw hooks update --all
--dry-run 标志未得到充分利用。在任何 install 或 update 之前运行它,以准确查看哪些文件会发生更改。在 CI 管道中,在实际安装之前的单独验证步骤中将 --yes 与 --dry-run 配对。
捆绑 Hook 参考:OpenClaw 附带什么
| 钩 | 默认状态 | 它的作用 | 最佳使用时间 |
|---|---|---|---|
| 会话内存 | 启用 | 跨会话保留关键上下文 | 具有重复任务的长期运行项目 |
| 附加捆绑钩子因网关版本而异 | — | 运行 OpenClaw hooks list --builtin 查看你的 |
— |
运行 OpenClaw hooks inspect session-memory 以查看其完整配置选项。大多数捆绑的钩子都附带合理的默认值,但会公开配置字段以进行自定义。
真实世界的 Hook 用例(带有工作示例)
1. 文件保护护栏(PreToolUse)
防止代理接触您的 .env 文件:
import { PreToolUseEvent } from "@OpenClaw/sdk";
export default function handler(event: PreToolUseEvent) {
const target = event.toolInput?.path ?? "";
if (target.includes(".env")) {
return { abort: true, reason: "Modification of .env files is blocked by policy." };
}
}
将其放入 .OpenClaw/hooks/protect-env/ 中,并与订阅 PreToolUse 的匹配 HOOK.md 范围为 write_file 和 edit_file。代理在其上下文中收到拒绝原因,并且不会重试。
2. 会话停止时的 Slack 通知
import { StopEvent } from "@OpenClaw/sdk";
export default async function handler(event: StopEvent) {
await fetch(process.env.SLACK_WEBHOOK_URL!, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
text: `OpenClaw session ended. Files modified: ${event.session.filesModified ?? 0}`
})
});
}
将此挂钩订阅 Stop 事件。每个会话结束都会触发一条带有摘要的 Slack 消息。不需要外部服务器——网关进程直接发出出站请求。
3. 自动格式化+PostToolUse测试
import { PostToolUseEvent } from "@OpenClaw/sdk";
import { execSync } from "child_process";
export default function handler(event: PostToolUseEvent) {
const file = event.toolResult?.path;
if (!file?.endsWith(".ts")) return;
execSync(`prettier --write "${file}"`);
execSync("npm test -- --passWithNoTests", { stdio: "inherit" });
}
在每个 TypeScript 文件写入、格式化、然后运行测试套件后都会触发此事件。大型项目速度缓慢 - 使用 HOOK.md 中的 Tools 字段严格限制其范围。
团队的钩子——在共享项目中加强护栏
将 .OpenClaw/hooks/ 目录提交给版本控制。每个自动克隆存储库的开发人员都具有相同的钩子配置。
- 将关键挂钩锁定到项目配置中的
enabled— 防止队友意外禁用文件防护 - 使用
HOOK.md描述来记录意图 — 将它们视为代码注释,队友会阅读它们 - 范围挂钩工具级粒度 - 宽钩会减慢所有代理交互,产生摩擦,导致队友禁用它们
- 在 monorepos 中,父目录中的钩子适用于所有嵌套项目,除非在子目录级别覆盖
CI/CD 集成 — 以非交互方式运行 OpenClaw Hooks
在 GitHub Actions 或任何无头环境中,交互式确认提示将挂起您的管道。使用 --yes 跳过它:
- name: Install hooks non-interactively
run: OpenClaw hooks install qa-pack --yes
- name: Run OpenClaw session
env:
OpenClaw_HOOKS_ENABLED: "true"
SLACK_WEBHOOK_URL: secrets.SLACK_WEBHOOK_URL
run: OpenClaw run --task "audit dependencies" --yes
将 OpenClaw_HOOKS_ENABLED=true 设置为环境变量以激活钩子而无需交互确认。这会覆盖 CI 模式中“至少配置一个条目”的要求。
Hook 安全性:运行的内容、可以访问的内容以及如何保持安全
这是大多数文档完全跳过的部分 - 如果您要安装社区挂钩包,这是最重要的部分。
哪些钩子可以访问: Hook 脚本继承 Gateway进程的全部权限。如果网关以您的用户帐户运行,您的挂钩可以读取该帐户可以读取的任何文件、发出网络请求、执行子进程以及访问包括机密在内的环境变量。
未经审核的钩子包的风险: 恶意钩子包可能会泄露您的 .env、您的 SSH 密钥或您的 API 令牌,同时看起来会执行一些良性的操作,例如“格式化代码”。
钩包审核清单
在安装任何第三方包之前运行此操作:
- ☐阅读完整的
HOOK.md— 声明的权限是否符合规定的目的? - ☐读取
handler.ts/js的每一行 — 查找fetch()、execSync、process.env访问 - ☐检查 npm 出处是否包是由注册表分发的 (
npm info <pack> --json | grep provenance) - ☐验证发布者的身份 - 这是已知的维护者还是新帐户?
- ☐首先运行
--dry-run并查看文件清单 - ☐在未先完成上述步骤的情况下,切勿安装带有
--yes的钩子包
OpenClaw hooks inspect 命令显示已安装挂钩的完整源路径 - 使用它在更新后重新审查处理程序代码。
OpenClaw 钩子不触发时的故障排除
根本没有发现钩子
- 验证目录位于扫描的挂钩路径内:
OpenClaw hooks list --verbose - 确认
HOOK.md存在且有效 — 缺少必填字段会自动跳过钩子 - 检查是否全局启用了钩子并且至少配置了一个条目
胡克被发现但未开火
- 运行
OpenClaw hooks inspect <name>— 验证HOOK.md中的Event字段与您期望的生命周期事件匹配 - 检查
Tools范围 - 如果您的范围为write_file但代理正在调用create_file,则挂钩不会触发 - 确认挂钩状态显示
enabled,而不是loaded(已加载意味着已发现但未处于活动状态)
钩子触发但处理程序错误保持沉默
- 添加显式
try/catch块并在处理程序中记录console.error - 网关日志写入
~/.OpenClaw/logs/— 检查最新会话日志中是否有[hook]前缀行 - 使用
OpenClaw hooks inspect <name> --logs来显示最后的执行输出
Hook 减慢了每个特工的动作
- 使用
OpenClaw hooks list --timing进行分析以查看每个钩子的执行时间 - 将同步
execSync调用移至异步,其中结果不需要阻止代理 - 将范围挂钩到特定工具,而不是订阅所有
PostToolUse事件
使用 EasyClaw 进一步提升您的 AI 代理工作流程
OpenClaw 挂钩让您可以在代理级别进行控制。 EasyClaw 为您提供了这种控制权,以及为需要可靠性、隐私和速度而不依赖于云的开发人员和内容团队构建的完整桌面本机环境。
- ✓ 完全在您自己的机器上运行钩子、代理和自动化——没有数据离开您的环境
- ✓ 与现有开发工具链的本机集成 — linter、测试运行器、格式化程序、CI 管道
- ✓ 可视化挂钩管理 — 启用、禁用和检查挂钩,无需记住 CLI 标志
- ✓ 团队就绪:从一个仪表板共享挂钩配置、锁定护栏和审核会话日志
常见问题解答
问:挂钩可以完全阻止代理执行工具调用吗?
答:是的 - 只有 PreToolUse 挂钩可以中止工具调用。从处理程序返回 { abort: true, reason: "..." } ,网关会阻止该工具执行。代理在其上下文中接收原因字符串。 PostToolUse、Stop 和 SessionStart 挂钩无法追溯中止操作。
问:如果我的钩子处理程序抛出未处理的错误,会发生什么情况?
答:默认情况下,挂钩处理程序中未处理的错误会记录到网关会话日志中,但不会使代理会话崩溃。特工继续说道,就好像钩子没有触发一样。这是设计使然——钩子永远不应该阻止核心代理功能。始终将处理程序逻辑包装在 try/catch 中并显式处理错误,以便您可以了解故障。
问:我可以在钩子处理程序中使用 async/await 吗?
答:是的,PreToolUse 和 PostToolUse 处理程序都支持异步函数。对于 PreToolUse,网关在决定是否继续之前等待处理程序 - 因此异步中止逻辑可以正常工作。请注意,PreToolUse 中长时间运行的异步操作会延迟每个工具调用,因此请保持快速。
问:挂钩适用于所有项目还是仅适用于它们所在的项目?
答:放置在项目的 .OpenClaw/hooks/ 目录中的挂钩是项目范围的,并且仅针对该项目中的会话激活。全局钩子可以放置在 ~/.OpenClaw/hooks/ 中并应用于所有项目。在 monorepos 中,父目录中的挂钩适用于嵌套项目,除非在子目录级别被覆盖。
问:运行许多钩子会产生性能成本吗?
答:每个钩子都会为其订阅的事件增加延迟。范围广泛的快速钩子(50 毫秒以下)是难以察觉的。当钩子在没有工具级作用域的情况下对每个 PostToolUse 事件运行繁重的同步操作时,就会出现问题。使用 OpenClaw hooks list --timing 进行分析,将钩子范围限定到 HOOK.md 中的特定工具,并在可能的情况下将非阻塞工作移至异步。
问:hooks 可以安全地访问环境变量中的机密吗?
答:Hook 继承了 Gateway 进程的完整环境,因此 process.env.MY_SECRET 在任何处理程序中都可以工作。对于 CI 环境,通过管道的机密管理器(例如 GitHub Actions Secrets)注入机密,而不是对其进行硬编码。切勿将机密提交到 HOOK.md 或处理程序文件 - 将挂钩源文件视为将进行审查和版本控制的代码。
最后的想法 - 为您的工作流程选择正确的 Hook 策略
| 设想 | 推荐方法 |
|---|---|
| Solo dev — 保护敏感文件 | 内部钩子,PreToolUse,作用域为编写工具 |
| Solo dev — 自动运行测试 | 内部钩子,PostToolUse,作用范围为测试相邻文件类型 |
| 团队——实施共享护栏 | 将挂钩提交到版本控制,锁定项目配置中启用的关键挂钩 |
| 团队——审计追踪 | Stop 事件挂钩发布到共享日志记录端点 |
| CI 管道 — 自动化会话 | 验证步骤中的 --yes 标志 + OpenClaw_HOOKS_ENABLED 环境变量、--dry-run |
| 外部通知 | Webhook 或 Stop 事件挂钩与 fetch() 到 Slack/PagerDuty |
从解决真正难题的一个钩子开始——文件保护或写入后的 linter。在分层之前先让它端到端地工作。钩子的力量是复合的:具有三个范围良好的钩子的会话平稳运行比具有十个您不信任的范围较小的钩子的会话要可靠得多。
对于大多数开发人员来说,杠杆率最高的第一个钩子是: PreToolUse 保护您的 .env 和机密文件。编写仅需十分钟,运行零维护,并永久消除一整类代理错误。