--- summary: "Hook 目录布局、处理程序合约、回复传递和 HOOK.md 元数据字段" read_when: - "您正在编写一个新的内部钩子并且需要文件布局" - "您需要处理程序签名、事件字段或回复传递边界" - "您需要 `HOOK.md` frontmatter 和 `metadata.openclaw` 合约" title: "写作挂钩" --- 挂钩文件布局、处理程序合约、回复传递和 `HOOK.md` 元数据字段。 [Hooks](/automation/hooks) 指南的一部分。 ## 编写钩子 此示例响应重置命令并写入固定日志标记。它不读取消息内容、调用模型或联系外部服务。 ### 钩子结构 在网关主机上,使用新的托管挂钩目录。以下命令假定默认状态目录并且 `reset-greeting` 尚不存在;选择另一个名称而不是覆盖现有的钩子。 ```bash mkdir -p ~/.openclaw/hooks/reset-greeting cat > ~/.openclaw/hooks/reset-greeting/HOOK.md <<'HOOK' --- name: reset-greeting description: "Confirm that a reset hook ran" metadata: { "openclaw": { "events": ["command:new", "command:reset"] } } --- # Reset greeting Send a short confirmation after an authorized reset command. HOOK cat > ~/.openclaw/hooks/reset-greeting/handler.js <<'HANDLER' export default function handler(event) { if (event.type !== "command" || !["new", "reset"].includes(event.action)) { return; } console.log("[reset-greeting] reset hook ran"); event.messages.push("Reset hook ran."); } HANDLER ``` 挂钩需要 `HOOK.md` 和处理程序文件。发现使用它找到的第一个文件按顺序检查 `handler.ts`、`handler.js`、`index.ts`,然后检查 `index.js`。该示例使用 JavaScript,因此不需要 TypeScript 类型或 SDK 导入。 启用并加载它: ```bash openclaw hooks info reset-greeting openclaw hooks enable reset-greeting ``` 在配置的聊天通道上的一次性对话中发送 `/new`,该通道可以路由回复,例如向机器人发送直接消息。该对话中预计有 **Reset hook ran.** ,网关日志中预计有 `[reset-greeting] reset hook ran` 。 `/reset` 触发相同的示例。正常的命令授权仍然适用。 使用普通的 OpenClaw 会话,而不是 ACP- 绑定线程;绑定会话将重置处理委托给其所属的运行时。不要使用 Control UI/webchat 或 `sessions.reset` RPC 作为聊天回复检查:这些路径不会将此挂钩的 `event.messages` 传递到 UI。日志标记仍然可以显示重置事件已运行。具体边界见[回复投递](/automation/hooks/writing-hooks#reply-delivery)。 完成后禁用该示例: ```bash openclaw hooks disable reset-greeting ``` 禁用会使文件保留在原位。要使用工作区目录,请将这两个文件放入 `/hooks/reset-greeting/` 中,然后显式启用该挂钩。工作区放置不是代理沙箱,也不能保证网关将加载该工作区的挂钩。 ### 处理器实现 处理程序导出返回 `void` 或 `Promise` 的函数。加载程序使用默认导出,除非 `metadata.openclaw.export` 指定另一个导出。返回值不会阻止、取消或重写操作。 每个事件都有这些字段: | 字段 | 含义 | | ------------ | ---------------------------------------------------------------------------------------------------------------------- | | `type` | 系列:`command`、`session`、`agent`、`gateway` 或 `message` | | `action` | 家庭内的行动,例如 `new` 或 `compact:before` | | `sessionKey` | 会话关联键;网关事件使用网关密钥代替 | | `timestamp` | JavaScript 创建事件对象时的 `Date` | | `context` | [事件上下文重点描述的事件特定数据](/automation/hooks/event-types#event-context-highlights) | | `messages` | 最初为空字符串数组;只有某些生产者将其作为回复使用 | 将上下文视为观察,而不是实时状态编辑 API。字段因生产者而异,并且 `cfg` 并不出现在每个事件中。特别是,补丁事件带有克隆快照。显式可变异常是 `agent:bootstrap` 的 `context.bootstrapFiles`。 ### 回复发货 推送到 `event.messages` 不是一般的发送消息 API: | 制片人 | `event.messages` 会发生什么 | | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `/new` 和 `/reset` 的聊天命令处理 | 等待处理程序,用空行连接字符串,并尝试回复原始 channel/recipient,保留帐户和线程上下文 | | 发出 `command:new` 或 `command:reset` 的网关会话 reset/create RPC | 处理程序运行,但消息不会作为聊天回复进行路由 | | `session:compact:before` 和 `session:compact:after` | 当存在时转发到调用者的压缩通知回调;该回调拥有交付 | | 所有其他核心事件 | 忽略回复,包括 `/stop`、自动重置、消息事件、引导程序、补丁和网关生命周期事件 | 缺少收件人、不受支持的路由、发送策略或传送失败可能会阻止回复。在处理程序的承诺解决之前附加消息;稍后推送的独立工作可能会错过生产者的交付步骤。要控制正常代理回复或发送取消,请使用适当的 [ 类型插件钩子 ](/plugins/hooks)。 ### HOOK.md 格式 `HOOK.md` 使用 YAML frontmatter 后跟人类可读的 Markdown: ```markdown --- name: my-hook description: "Short description of what this hook does" homepage: https://example.com/my-hook metadata: { "openclaw": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } } --- # My Hook Explain the side effects, configuration, and verification steps here. ``` `name` 默认为目录名;使用独特、稳定的名称。 `description` 显示在报告中。以下字段属于 `metadata.openclaw`。 2026 年 7 月之前的 `metadata.clawdbot` 格式不再被读取。通过将该元数据块重命名为 `openclaw` 来更新旧的 `HOOK.md`,保留其事件列表和其他字段。如果 `openclaw` 块已存在,请保留其值并仅合并您仍需要的旧字段。 OpenClaw 不重写文件;旧块中的事件声明和要求将被忽略。 | 字段 | 契约 | | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `events` | 事件键数组。注册处理程序至少需要一个。 | | `export` | 函数导出名称;默认为 `default`。 | | `hookKey` | 配置输入键;默认为钩子名称。发现冲突仍然使用钩子名称。 | | `emoji` | 显示表情符号。 | | `homepage` | 文档 URL;覆盖顶级 `homepage`、`website` 或 `url`。 | | `os` | 允许的 Node 平台名称,例如 `darwin`、`linux` 或 `win32`。 | | `requires.bins` | 每个指定的可执行文件必须位于 `PATH` 上。 | | `requires.anyBins` | `PATH` 上必须至少有一个指定的可执行文件。 | | `requires.env` | 每个命名变量都需要一个非空过程值或每个挂钩 `env` 值。 | | `requires.config` | 每个点的配置路径都必须是真实的。 | | `always` | 绕过二进制、环境和配置要求;不会绕过 OS 或启用策略。 | | `install` | 信息安装描述符:`kind` 是 `bundled`、`npm` 或 `git`;可选 `id`、`label`、`package`、`repository` 和 `bins`。此元数据不会安装依赖项或使 Git 规范被 CLI 接受。 | 使用 `hooks.internal.entries..enabled` 来控制激活,而不是 `HOOK.md` 中的顶级 `enabled` 标志。对于历史需求元数据,`workspace.dir`、`browser.enabled` 和 `browser.evaluateEnabled` 在不存在时默认为 true。 `workspace.dir` 不是您需要添加到配置中的新设置。