Appearance
Hooks(内部事件钩子)
Hooks 是在 Agent 内部事件触发时自动运行的小型 TypeScript 函数,无需用户主动发消息。
Hooks 与 Webhook 的区别:
- Hooks(本页):Gateway 内部事件(命令、会话、消息)触发的函数
- Webhook:外部 HTTP 端点,让第三方系统触发 OpenClaw(见 Webhook)
内置 Hooks(开箱即用)
OpenClaw 附带 4 个常用 Hook:
| Hook | 功能 |
|---|---|
session-memory 💾 | /new 命令时,将会话上下文保存到工作区记忆 |
bootstrap-extra-files 📎 | agent:bootstrap 时注入额外的工作区启动文件 |
command-logger 📝 | 记录所有命令事件到 ~/.openclaw/logs/commands.log |
boot-md 🚀 | Gateway 启动时运行 BOOT.md |
管理 Hooks
bash
openclaw hooks list # 列出所有可用 Hook
openclaw hooks enable session-memory # 启用 Hook
openclaw hooks check # 检查 Hook 状态
openclaw hooks info session-memory # 查看 Hook 详情Hook 发现机制
Hook 从三个目录自动加载(优先级从高到低):
- 工作区 Hooks:
<workspace>/hooks/(专属于当前 Agent) - 本机共享 Hooks:
~/.openclaw/hooks/(跨 Agent 共享) - 内置 Hooks:
<openclaw>/dist/hooks/bundled/
每个 Hook 是一个目录,包含:
my-hook/
├── HOOK.md # 元数据 + 文档
└── handler.ts # 处理函数实现Hook Packs(批量安装)
Hook Pack 是标准 npm 包,通过 package.json 的 openclaw.hooks 字段声明包含哪些 Hook:
bash
openclaw hooks install <路径或包名>安全提示:安装时使用
npm install --ignore-scripts,不执行 lifecycle scripts。
编写自定义 Hook
HOOK.md 格式
markdown
---
name: my-hook
description: "发生 /new 时执行某些操作"
metadata:
{ "openclaw": { "emoji": "🔗", "events": ["command:new"] } }
---
# My Hook
描述这个 Hook 做什么……元数据字段(metadata.openclaw 下):
| 字段 | 说明 |
|---|---|
emoji | CLI 显示的 emoji |
events | 监听的事件列表(如 ["command:new", "message:received"]) |
export | 使用哪个导出(默认 default) |
requires.bins | 必须在 PATH 上的可执行文件 |
requires.env | 必须存在的环境变量 |
requires.os | 仅在指定平台加载(darwin/linux/win32) |
always | 跳过资格检查(布尔值) |
handler.ts 格式
typescript
const myHandler = async (event) => {
// 过滤事件类型
if (event.type !== "command" || event.action !== "new") {
return;
}
console.log(`[my-hook] 触发:${event.sessionKey}`);
console.log(` 时间:${event.timestamp.toISOString()}`);
// 自定义逻辑……
// 向用户发送消息(可选)
event.messages.push("✨ Hook 已执行!");
};
export default myHandler;事件上下文结构
typescript
{
type: 'command' | 'session' | 'agent' | 'gateway' | 'message',
action: string, // 'new'、'reset'、'received'、'sent' 等
sessionKey: string,
timestamp: Date,
messages: string[], // 向 messages 数组 push 内容即可发送给用户
context: {
// 命令事件
sessionEntry?: SessionEntry,
workspaceDir?: string,
bootstrapFiles?: WorkspaceBootstrapFile[],
cfg?: OpenClawConfig,
// 消息事件(见下方)
from?: string,
to?: string,
content?: string,
channelId?: string,
}
}事件类型参考
命令事件
| 事件 | 触发时机 |
|---|---|
command | 所有命令事件(通用监听) |
command:new | 用户发送 /new |
command:reset | 用户发送 /reset |
command:stop | 用户发送 /stop |
会话事件
| 事件 | 触发时机 |
|---|---|
session:compact:before | 上下文压缩前 |
session:compact:after | 上下文压缩完成后(含摘要元数据) |
Agent 事件
| 事件 | 触发时机 |
|---|---|
agent:bootstrap | 工作区启动文件注入前(可修改 context.bootstrapFiles) |
Gateway 事件
| 事件 | 触发时机 |
|---|---|
gateway:startup | Gateway 启动完成后(渠道和 Hook 加载完成) |
消息事件
| 事件 | 触发时机 |
|---|---|
message | 所有消息事件(通用监听) |
message:received | 收到入站消息(媒体尚未处理,可能含 <media:audio> 占位符) |
message:transcribed | 音频转写完成(context.transcript 包含转写文字) |
message:preprocessed | 所有媒体 + 链接理解完成后(Agent 看到消息前的最终版本) |
message:sent | 出站消息发送成功 |
消息事件上下文(message:received)
typescript
{
from: string, // 发送者标识(手机号、用户 ID 等)
content: string, // 消息内容
channelId: string, // 渠道("whatsapp"、"telegram"、"discord" 等)
accountId?: string, // 多账号场景的 Provider 账号 ID
conversationId?: string,
messageId?: string,
metadata?: { // Provider 专有额外数据
senderName?: string,
senderUsername?: string,
threadId?: string,
}
}消息日志示例
typescript
const handler = async (event) => {
if (event.type === "message" && event.action === "received") {
const { from, content, channelId } = event.context;
console.log(`[message-logger] 收到消息 from=${from} channel=${channelId}`);
console.log(` 内容: ${content.substring(0, 100)}`);
}
if (event.type === "message" && event.action === "sent") {
const { to, success, channelId } = event.context;
console.log(`[message-logger] 发送消息 to=${to} success=${success} channel=${channelId}`);
}
};
export default handler;