Appearance
OpenClaw Hooks 是网关内部事件触发时自动运行的小脚本,支持 /new、/reset、/stop 以及消息、session 压缩、gateway 启停等 14 种事件。本文说明如何编写 Hook 目录结构、配置 HOOK.md 元数据、启用内置钩子(session-memory、command-logger、compaction-notifier、boot-md 等)、设置自定义目录,并通过 openclaw hooks list 和日志排查不发现或不执行的问题。
OpenClaw Hooks 配置与编写:事件驱动自动化完整指南
Hooks 是在 Gateway 内部发生特定事件时自动运行的小脚本。它们从目录中自动发现,可通过 openclaw hooks 命令查看。
OpenClaw 有两类 Hook:
- 内部 Hook(本页):在 agent 事件触发时在 Gateway 内部运行,如
/new、/reset、/stop或生命周期事件。 - Webhook:让外部系统通过 HTTP 触发 OpenClaw 工作的外部端点。参见 Webhooks(定时任务页)。
Hook 也可以打包在插件内。openclaw hooks list 会同时显示独立 Hook 和插件管理的 Hook。
快速开始
bash
# 列出可用 Hooks
openclaw hooks list
# 启用某个 Hook
openclaw hooks enable session-memory
# 检查 Hook 状态
openclaw hooks check
# 获取详细信息
openclaw hooks info session-memory事件类型
| 事件 | 触发时机 |
|---|---|
command:new | 执行 /new 命令时 |
command:reset | 执行 /reset 命令时 |
command:stop | 执行 /stop 命令时 |
command | 任意命令事件(通用监听) |
session:compact:before | 压缩历史记录之前 |
session:compact:after | 压缩完成之后 |
session:patch | session 属性被修改时 |
agent:bootstrap | workspace bootstrap 文件注入之前 |
gateway:startup | 频道启动、Hooks 加载完成之后 |
gateway:shutdown | gateway 关闭开始时 |
gateway:pre-restart | 预期 gateway 重启之前 |
message:received | 从任意频道收到消息时 |
message:transcribed | 音频转录完成后 |
message:preprocessed | 媒体和链接预处理完成后或跳过时 |
message:sent | 出站消息送达时 |
编写 Hook
Hook 目录结构
每个 Hook 是一个包含两个文件的目录:
my-hook/
├── HOOK.md # 元数据 + 文档
└── handler.ts # 处理器实现HOOK.md 格式
markdown
---
name: my-hook
description: "这个 Hook 做什么的简短描述"
metadata:
{ "openclaw": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } }
---
# My Hook
详细文档写在这里。元数据字段(metadata.openclaw):
| 字段 | 说明 |
|---|---|
emoji | CLI 显示用的 emoji |
events | 要监听的事件数组 |
export | 使用的命名导出(默认 "default") |
os | 要求的平台(如 ["darwin", "linux"]) |
requires | 需要的 bins、anyBins、env 或 config 路径 |
always | 绕过资格检查(布尔值) |
install | 安装方式 |
处理器实现
typescript
const handler = async (event) => {
if (event.type !== "command" || event.action !== "new") {
return;
}
console.log(`[my-hook] 触发了新命令`);
// 你的业务逻辑
// 可选:向用户发送消息
event.messages.push("Hook 已执行!");
};
export default handler;每个事件包含:type、action、sessionKey、timestamp、messages(推送到此数组即可向用户发送消息)和 context(事件特定数据)。agent 和工具插件的 hook 上下文还可以包含 trace,一个只读的 W3C 兼容诊断追踪上下文,插件可将其传入结构化日志用于 OTEL 关联。
事件上下文说明
命令事件(command:new、command:reset):context.sessionEntry、context.previousSessionEntry、context.commandSource、context.workspaceDir、context.cfg。
消息事件(message:received):context.from、context.content、context.channelId、context.metadata(含 senderId、senderName、guildId 等提供商特定数据)。context.content 对于类命令消息优先取非空命令体,否则回退到原始入站正文和通用正文;不包含 agent 专属富化信息(如线程历史或链接摘要)。
消息事件(message:sent):context.to、context.content、context.success、context.channelId。
消息事件(message:transcribed):context.transcript、context.from、context.channelId、context.mediaPath。
消息事件(message:preprocessed):context.bodyForAgent(最终富化后的正文)、context.from、context.channelId。
Bootstrap 事件(agent:bootstrap):context.bootstrapFiles(可修改的数组)、context.agentId。
Session patch 事件(session:patch):context.sessionEntry、context.patch(仅变更字段)、context.cfg。只有特权客户端能触发 patch 事件。
压缩事件:session:compact:before 包含 messageCount、tokenCount;session:compact:after 额外包含 compactedCount、summaryLength、tokensBefore、tokensAfter。
command:stop 是取消/命令生命周期,不是 agent 最终化的门控。需要检查自然最终答案并让 agent 再多做一轮的插件应使用类型化的插件 hook before_agent_finalize。参见 Plugin hooks。
Gateway 生命周期事件:gateway:shutdown 包含 reason 和 restartExpectedMs,在 gateway 关闭开始时触发。gateway:pre-restart 包含相同上下文,但仅在关闭属于预期重启且提供了有限值 restartExpectedMs 时触发。关闭过程中,每个生命周期 hook 的等待是尽力而为且有边界的:默认等待预算为 gateway:shutdown 5 秒,gateway:pre-restart 10 秒,若 handler 停滞则继续关闭。
使用 gateway:pre-restart 在频道仍可用时发送简短重启通知:
typescript
import { execFile } from "node:child_process";
import { promisify } from "node:util";
const execFileAsync = promisify(execFile);
export default async function handler(event) {
if (event.type !== "gateway" || event.action !== "pre-restart") {
return;
}
const restartInSeconds = Math.ceil(event.context.restartExpectedMs / 1000);
await execFileAsync("openclaw", [
"system",
"event",
"--mode",
"now",
"--text",
`Gateway 将在约 ${restartInSeconds} 秒后重启(原因:${event.context.reason})。请立即保存检查点。`,
]);
}在 gateway:shutdown(或 gateway:pre-restart)事件和后续关闭序列之间,gateway 还会针对进程停止时仍处于活动状态的每个 session 触发类型化插件 hook session_end。该事件的 reason 为 shutdown(普通 SIGTERM/SIGINT 停止)或 restart(关闭是预期重启的一部分)。此 drain 有边界,慢 handler 不会阻塞进程退出;已通过 replace/reset/delete/compaction 最终化的 session 被跳过以防止重复触发。
Hook 发现机制
Hook 按照以下顺序从目录中发现,后面的优先级更高:
- 内置 Hook:随 OpenClaw 一起发布
- 插件 Hook:已安装插件内打包的 Hook
- 托管 Hook:
~/.openclaw/hooks/(用户安装,跨 workspace 共享)。hooks.internal.load.extraDirs中的额外目录也属于这个优先级。 - Workspace Hook:
<workspace>/hooks/(每个 agent 独立,默认禁用,需显式启用)
Workspace Hook 可以新增新 Hook 名称,但不能覆盖同名的内置、托管或插件 Hook。
Gateway 在内部 hooks 配置之前会跳过内部 Hook 发现。通过 openclaw hooks enable <name> 启用一个 bundled 或 managed hook,安装 hook pack,或设置 hooks.internal.enabled=true 来启用。当你启用一个命名 hook 时,Gateway 只加载该 handler;hooks.internal.enabled=true、额外 hook 目录和旧 handler 则启用完整发现。
Hook 包
Hook 包是通过 package.json 中的 openclaw.hooks 导出 Hook 的 npm 包。安装命令:
bash
openclaw plugins install <path-or-spec>npm 规格只支持注册表(包名 + 可选的精确版本或 dist-tag)。Git/URL/文件规格和语义化版本范围会被拒绝。
内置 Hooks
| Hook | 事件 | 功能 |
|---|---|---|
| session-memory | command:new、command:reset | 将 session 上下文保存到 <workspace>/memory/ |
| bootstrap-extra-files | agent:bootstrap | 从 glob 模式注入额外的 bootstrap 文件 |
| command-logger | command | 将所有命令记录到 ~/.openclaw/logs/commands.log |
| compaction-notifier | session:compact:before、session:compact:after | 压缩开始和结束时发送可见聊天通知 |
| boot-md | gateway:startup | Gateway 启动时运行 BOOT.md |
启用任意内置 Hook:
bash
openclaw hooks enable <hook-name>session-memory 详解
提取最近 15 条用户/助手消息,保存到 <workspace>/memory/YYYY-MM-DD-HHMM.md(使用主机本地日期)。内存捕获在后台运行,因此 /new 和 /reset 的确认不会被转录读取或可选的 slug 生成延迟。设置 hooks.internal.entries.session-memory.llmSlug: true 可使用配置的模型生成描述性文件名 slug。需要配置 workspace.dir。
bootstrap-extra-files 配置
json
{
"hooks": {
"internal": {
"entries": {
"bootstrap-extra-files": {
"enabled": true,
"paths": ["packages/*/AGENTS.md", "packages/*/TOOLS.md"]
}
}
}
}
}路径相对于 workspace 解析。只会加载识别到的 bootstrap 基础名(AGENTS.md、SOUL.md、TOOLS.md、IDENTITY.md、USER.md、HEARTBEAT.md、BOOTSTRAP.md、MEMORY.md)。
command-logger 详解
将所有斜杠命令记录到 ~/.openclaw/logs/commands.log。
compaction-notifier 详解
当 OpenClaw 开始和完成压缩 session 转录时,向当前对话发送短状态消息。这使长时间对话在聊天界面上更易理解——用户可以看到 assistant 正在总结上下文,并且压缩后将继续。
boot-md 详解
Gateway 启动时运行活动 workspace 中的 BOOT.md。
插件 Hooks
插件可以通过 Plugin SDK 注册类型化 Hook,实现更深度的集成:拦截工具调用、修改提示词、控制消息流等。当需要 before_tool_call、before_agent_reply、before_install 或其他进程内生命周期 hook 时使用插件 Hook。
完整插件 Hook 参考,请参见 Plugin hooks。
配置
json
{
"hooks": {
"internal": {
"enabled": true,
"entries": {
"session-memory": { "enabled": true },
"command-logger": { "enabled": false }
}
}
}
}每个 Hook 的环境变量:
json
{
"hooks": {
"internal": {
"entries": {
"my-hook": {
"enabled": true,
"env": { "MY_CUSTOM_VAR": "value" }
}
}
}
}
}额外 Hook 目录:
json
{
"hooks": {
"internal": {
"load": {
"extraDirs": ["/path/to/more/hooks"]
}
}
}
}旧版
hooks.internal.handlers数组配置格式仍然支持(向后兼容),但新 Hook 应使用基于发现的系统。
CLI 参考
bash
# 列出所有 Hooks(可加 --eligible、--verbose 或 --json)
openclaw hooks list
# 显示某个 Hook 的详细信息
openclaw hooks info <hook-name>
# 显示资格摘要
openclaw hooks check
# 启用/禁用
openclaw hooks enable <hook-name>
openclaw hooks disable <hook-name>最佳实践
- 保持处理器快速。 Hook 在命令处理期间运行。对耗时操作使用
void processInBackground(event)异步触发。 - 优雅处理错误。 用 try/catch 包裹风险操作;不要抛出异常,让其他处理器也能运行。
- 尽早过滤事件。 如果事件类型/动作不相关,立即返回。
- 使用精确的事件键。 优先用
"events": ["command:new"]而非"events": ["command"],减少不必要的开销。
故障排查
Hook 未被发现
bash
# 验证目录结构
ls -la ~/.openclaw/hooks/my-hook/
# 应该显示:HOOK.md, handler.ts
# 列出所有已发现的 Hooks
openclaw hooks listHook 不符合资格
bash
openclaw hooks info my-hook检查是否缺少必要的可执行文件(PATH)、环境变量、配置值或 OS 兼容性。
Hook 未执行
- 确认 Hook 已启用:
openclaw hooks list - 重启 Gateway 进程以重新加载 Hooks。
- 检查 Gateway 日志:
./scripts/clawlog.sh | grep hook
常见问题
为什么我的 Hook 没有执行?
先确认 Hook 已启用:openclaw hooks list 中是否显示 enabled。然后重启 Gateway 进程使配置生效,最后查看日志 ./scripts/clawlog.sh | grep hook 是否有错误。
Hook 和 Webhook 有什么区别?
内部 Hook 在 Gateway 内部事件(如 /new 命令)触发时运行;Webhook 是对外暴露的 HTTP 端点,让外部系统主动触发 OpenClaw 执行任务。
Workspace Hook 能覆盖内置 Hook 吗?
不能。Workspace Hook 只能新增新的 Hook 名称,无法覆盖同名的内置、托管或插件 Hook。
相关链接
- CLI 参考:hooks
- Webhooks
- Plugin hooks — 进程内插件生命周期 Hook
- 配置参考