第 10 章 · 自动化体系
你雇佣了一个助理,但你还得每次手动告诉他"检查邮件"、"整理日报"、"跟进客户"——这不是助理,这是复读机。OpenClaw 的自动化体系,就是让 Agent 从"等你说话"进化到"自己知道什么时候该干什么"。
本章你将学到:
- 理解 Heartbeat 和 Cron 两种调度机制的本质区别和选择策略
- 掌握 Cron 作业的完整生命周期——从创建、执行、投递到重试
- 学会用 Webhook 把外部系统接入 Agent 的工作流
- 理解 Hooks 事件驱动系统,实现"发生了什么就自动做什么"
- 能设计包含常驻指令(Standing Orders)的完整自主工作流
10.1 自动化的三种时间模型
在深入具体功能之前,你需要理解 OpenClaw 自动化的三种时间模型——它们解决的是不同的问题:
┌───────────────────────────────────────────────────────────┐
│ 自动化三模型 │
├───────────────────┬───────────────────┬───────────────────┤
│ Heartbeat │ Cron │ Webhook │
│ 周期性"巡逻" │ 精确"闹钟" │ 事件"门铃" │
├───────────────────┼───────────────────┼───────────────────┤
│ 每 30 分钟醒来 │ 每天早上 7:00 │ 收到邮件时触发 │
│ 看一眼有什么事 │ 执行指定任务 │ 外部系统推送事件 │
│ 没事就回去睡觉 │ 可以只跑一次 │ Agent 被动响应 │
│ 上下文共享 │ 可以隔离会话 │ 独立会话处理 │
└───────────────────┴───────────────────┴───────────────────┘
Heartbeat(心跳)是 Agent 的"自动巡逻"——每隔一段时间醒来,按检查清单扫一遍,有情况就报告,没情况就回去睡觉。
Cron(定时任务)是 Agent 的"精确闹钟"——在指定时间点触发指定任务,精确到分钟,支持一次性提醒和周期性执行。
Webhook(网络钩子)是 Agent 的"门铃"——外部系统(邮件、GitHub、监控)有事情发生时,通过 HTTP 请求"按门铃",Agent 被唤醒处理。
三者不是互斥的——一个成熟的自动化系统通常是三者的组合。本章的后续章节会逐一深入,但先记住这个决策框架:
需要精确时间? → Cron
需要批量检查? → Heartbeat
需要外部触发? → Webhook
不确定? → 继续读下去
10.2 Heartbeat:Agent 的"自动巡逻"
10.2.1 心跳的工作原理
Heartbeat 是 OpenClaw 中最"无感"的自动化机制。它的核心思路很简单:每隔一段时间,自动在主会话中插入一条系统消息,触发 Agent 执行一次检查。
时间线:
08:00 [用户发消息] → Agent 正常回复
08:30 [Heartbeat 触发] → Agent 检查 HEARTBEAT.md → 回复 HEARTBEAT_OK(无消息发送)
09:00 [Heartbeat 触发] → Agent 检查 → 发现新邮件 → 发送提醒
09:30 [Heartbeat 触发] → Agent 检查 → 回复 HEARTBEAT_OK
10:00 [用户发消息] → Agent 正常回复
关键机制:如果 Agent 判断"没什么事",会回复 HEARTBEAT_OK。OpenClaw 识别到这个信号后,不会把消息发送给你——所以你完全感知不到这次心跳的发生。
10.2.2 配置心跳
默认心跳间隔是 30 分钟。如果你用的是 Anthropic OAuth 认证,默认间隔会自动调整为 1 小时(更省 Token)。
{
agents: {
defaults: {
heartbeat: {
every: "30m", // 心跳间隔(设为 "0m" 禁用)
target: "last", // 投递到最近联系的通道(默认 "none" 不投递)
activeHours: { // 只在活跃时段运行
start: "08:00",
end: "22:00",
},
},
},
},
}
target 选项:
| 值 | 行为 |
|---|---|
none |
心跳照常运行,但不发送任何消息(默认) |
last |
发送到最近一次对话的通道 |
whatsapp / telegram / discord 等 |
发送到指定通道 |
| 具体通道 ID | 发送到指定通道账号 |
10.2.3 HEARTBEAT.md:心跳检查清单
心跳的核心配置不是在 JSON 里,而是在工作空间中的 HEARTBEAT.md 文件。这个文件定义了 Agent 每次醒来要检查什么。
# Heartbeat checklist
- Quick scan: anything urgent in inboxes?
- If it's daytime, do a lightweight check-in if nothing else is pending.
- If a task is blocked, write down _what is missing_ and ask Peter next time.
写作原则:
- 保持简短——每次心跳都会把
HEARTBEAT.md注入上下文,太长浪费 Token - 只写可执行的检查项,不写模糊的"关注一下"
- 不要放 API Key、手机号等敏感信息
💡 提示:你可以随时让 Agent 修改
HEARTBEAT.md。比如在聊天中说"把日历检查加到心跳清单里",Agent 会直接更新文件。
10.2.4 节省心跳成本
心跳每次都是一次完整的 Agent Turn,默认间隔 30 分钟意味着每天 48 次。如果你用的是 Opus 模型,这就是一笔不小的开销。几个省钱的配置:
{
agents: {
defaults: {
heartbeat: {
every: "30m",
lightContext: true, // 只注入 HEARTBEAT.md,不注入其他工作空间文件
isolatedSession: true, // 每次心跳用全新会话,不发完整对话历史
model: "openai/gpt-5.2-mini", // 用便宜模型做心跳检查
target: "none", // 只做内部状态更新,不发送消息
},
},
},
}
| 配置 | 效果 | 省钱幅度 |
|---|---|---|
lightContext: true |
只注入 HEARTBEAT.md |
中等(省去 SOUL.md 等文件) |
isolatedSession: true |
不发送对话历史 | 巨大(100K → 2-5K Token) |
model: "便宜模型" |
用低配模型检查 | 巨大(Opus → Mini 差 10 倍) |
target: "none" |
不发送外部消息 | 中等(省去发送步骤) |
⚠️ 踩坑记录
问题:开启了
isolatedSession: true后,Agent 似乎"忘了"之前的对话。原因:这正是预期行为。隔离会话每次都是全新的,Agent 看不到之前的聊天记录。
解决:如果你需要 Agent 在心跳中记住上下文,不要开
isolatedSession。或者把需要记住的关键信息写入工作空间的记忆文件。
10.2.5 活跃时段
你不会想让 Agent 凌晨三点发心跳消息吵醒你:
{
agents: {
defaults: {
heartbeat: {
every: "30m",
activeHours: {
start: "09:00", // 包含(09:00 开始运行)
end: "22:00", // 不包含(22:00 停止运行)
timezone: "America/New_York",
},
},
},
},
}
时区处理:
timezone省略时,使用userTimezone配置,再省略则用主机时区start和end相同时(比如都是08:00)会被视为零宽度窗口,心跳永远跳过
10.2.6 手动唤醒
有时候你不想等心跳,想让 Agent 立刻检查一下:
# 立即触发心跳
openclaw system event --text "Check for urgent follow-ups" --mode now
# 排队到下一次心跳
openclaw system event --text "Check battery level" --mode next-heartbeat
--mode now 会立即触发 Agent 运行。如果你有多个 Agent 配置了心跳,手动唤醒会同时触发所有 Agent。
10.2.7 多 Agent 心跳
当你的系统中有多个 Agent 时,可以精确控制哪些 Agent 跑心跳、各自的间隔和目标:
{
agents: {
defaults: {
heartbeat: {
every: "30m",
target: "last",
},
},
list: [
{ id: "main", default: true }, // main Agent 不单独配心跳,继承 defaults
{
id: "ops",
heartbeat: {
every: "1h", // ops Agent 每小时一次
target: "whatsapp",
to: "+15551234567",
prompt: "Read HEARTBEAT.md. Check server health and alert queue. Report anomalies.",
},
},
],
},
}
重要规则:一旦任何 agents.list[] 中包含了 heartbeat 配置,只有配置了心跳的 Agent 会运行心跳。没有配置的 Agent(如上面的 main)会被跳过。
10.3 Cron 作业:精确"闹钟"
如果说 Heartbeat 是"巡逻",Cron 就是"闹钟"——在精确的时间点执行精确的任务。
10.3.1 两种执行模式
Cron 作业有两种执行模式,对应不同的使用场景:
┌──────────────────────────────────────────────────────┐
│ 主会话模式(systemEvent) │
│ ┌────────────────────────────────────────────────┐ │
│ │ [主会话] ← 系统事件入队 → 下次心跳时处理 │ │
│ │ │ │
│ │ 适合:提醒、轻量触发 │ │
│ │ 优点:共享主会话上下文 │ │
│ │ 缺点:依赖心跳周期 │ │
│ └────────────────────────────────────────────────┘ │
├──────────────────────────────────────────────────────┤
│ 隔离模式(agentTurn) │
│ ┌────────────────────────────────────────────────┐ │
│ │ [cron:jobId] → 独立 Agent Turn → 结果投递 │ │
│ │ │ │
│ │ 适合:复杂任务、定时报告 │ │
│ │ 优点:不污染主会话、可覆盖模型 │ │
│ │ 缺点:没有主会话上下文 │ │
│ └────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────┘
10.3.2 快速上手:创建第一个 Cron 作业
场景 1:一次性提醒(20 分钟后提醒我打电话)
openclaw cron add \
--name "Call back client" \
--at "20m" \
--session main \
--system-event "Reminder: call back the client about the proposal." \
--wake now \
--delete-after-run
执行后会看到作业 ID。验证一下:
openclaw cron list
预期输出:
Jobs (1):
✓ call-back-client [at] 2026-03-28T14:20:00Z session=main wake=now
场景 2:每天早上的简报(隔离模式,发送到 Slack)
openclaw cron add \
--name "Morning brief" \
--cron "0 7 * * *" \
--tz "America/New_York" \
--session isolated \
--message "Summarize overnight updates: check inbox, calendar, and project status." \
--announce \
--channel slack \
--to "channel:C1234567890"
场景 3:每周深度分析(用更强的模型)
openclaw cron add \
--name "Weekly deep analysis" \
--cron "0 6 * * 1" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Weekly deep analysis of project progress and code quality." \
--model "opus" \
--thinking "high" \
--announce \
--channel whatsapp \
--to "+15551234567"
10.3.3 三种调度类型
| 类型 | 用法 | 适用场景 |
|---|---|---|
at |
--at "2026-03-28T16:00:00Z" 或 --at "20m" |
一次性提醒 |
every |
--every "30m" |
固定间隔轮询 |
cron |
--cron "0 7 * * *" |
标准定时表达式 |
Cron 表达式:支持 5 字段(分 时 日 月 周)和 6 字段(秒 分 时 日 月 周),使用 croner 库解析。
时区注意:如果 ISO 时间戳不带时区,会被当作 UTC。建议始终用 --tz 明确指定。
10.3.4 四种会话目标
Cron 作业可以运行在不同的会话上下文中:
// 主会话——注入系统事件,由心跳处理
{ sessionTarget: "main" }
// 隔离会话——每次全新上下文
{ sessionTarget: "isolated" }
// 当前会话——绑定到创建时的会话(创建时解析为 session:<key>)
{ sessionTarget: "current" }
// 自定义持久会话——跨次运行保持上下文
{ sessionTarget: "session:project-alpha-monitor" }
自定义持久会话是最容易被忽视但最强大的选项。它让 Cron 作业在多次运行之间保持上下文——比如每日站会可以"记住"昨天的进度:
{
"name": "Daily standup",
"schedule": { "kind": "cron", "expr": "0 9 * * 1-5" },
"sessionTarget": "session:daily-standup", // 持久会话,上下文累积
"payload": {
"kind": "agentTurn",
"message": "Summarize yesterday's progress and plan today's priorities."
}
}
10.3.5 投递控制
隔离模式的 Cron 作业默认会把结果摘要发送到指定通道(announce 模式)。三种投递模式:
| 模式 | 行为 |
|---|---|
announce |
发送摘要到指定通道 + 在主会话中记录(默认) |
webhook |
POST 结果到指定 URL |
none |
内部运行,不发送任何消息 |
Announce 投递细节:
- 使用隔离运行的外发内容(文本/媒体),走正常的分块和通道格式化
- 如果 Agent 只回复了
HEARTBEAT_OK(没有实质内容),不会投递 - 如果 Agent 已经通过 message 工具发了消息到同一目标,不会重复投递
Webhook 投递:
{
"delivery": {
"mode": "webhook",
"to": "https://your-api.example.com/cron-results"
}
}
如果配置了 cron.webhookToken,请求会携带 Authorization: Bearer <token>。
10.3.6 模型和思考级别覆盖
隔离模式的 Cron 作业可以覆盖模型和思考级别——这是 Heartbeat 做不到的:
# 用便宜模型做日常检查
openclaw cron add --name "Health check" --cron "*/30 * * * *" \
--session isolated --model "openai/gpt-5.2-mini" \
--message "Check service health."
# 用强模型做周报分析
openclaw cron add --name "Weekly review" --cron "0 9 * * 1" \
--session isolated --model "opus" --thinking "high" \
--message "Deep weekly analysis."
模型覆盖的优先级:作业 payload 覆盖 > Hook 特定默认值 > Agent 配置默认值。
10.3.7 负载分散(Stagger)
如果多个 Cron 作业都设在整点运行(0 * * * *),会造成瞬间 API 压力。OpenClaw 会自动给整点周期的任务加最多 5 分钟的随机偏移。
手动控制偏移:
# 强制精确时间(不偏移)
openclaw cron add --name "Exact" --cron "0 * * * *" --exact ...
# 自定义 30 秒偏移
openclaw cron add --name "Staggered" --cron "0 * * * *" --stagger "30s" ...
⚠️ 注意:固定小时表达式(如
0 7 * * *每天 7 点)不受自动偏移影响,时间精确。
10.3.8 重试策略
Cron 作业失败时,OpenClaw 会区分可恢复错误和永久错误:
可恢复错误(会重试):
- 速率限制(429)
- Provider 过载(529)
- 网络错误(超时、连接重置)
- 服务器错误(5xx)
永久错误(立即禁用):
- 认证失败(API Key 无效)
- 配置或验证错误
默认行为:
| 作业类型 | 重试策略 |
|---|---|
一次性(at) |
指数退避重试 3 次(30s → 1m → 5m),永久错误立即禁用 |
周期性(cron/every) |
指数退避(30s → 1m → 5m → 15m → 60m),下次成功后重置 |
自定义重试策略:
{
cron: {
retry: {
maxAttempts: 5,
backoffMs: [30000, 60000, 120000, 300000, 600000],
retryOn: ["rate_limit", "overloaded", "network", "server_error"],
},
},
}
10.3.9 存储、历史和维护
Cron 作业的存储结构:
~/.openclaw/cron/
├── jobs.json # 作业定义(Gateway 管理)
└── runs/
├── <jobId>.jsonl # 每次运行的日志(JSONL 格式)
└── ...
维护配置:
{
cron: {
sessionRetention: "24h", // 隔离运行会话保留时间
runLog: {
maxBytes: "2mb", // 运行日志文件最大大小
keepLines: 2000, // 裁剪后保留的行数
},
},
}
查看运行历史:
openclaw cron runs --id <jobId> --limit 50
⚠️ 踩坑记录
问题:手动编辑
jobs.json后,Gateway 重启时 Cron 作业丢失或冲突。原因:Gateway 运行时会加载
jobs.json到内存,修改后写回。如果 Gateway 正在运行,手动编辑会被覆盖。解决:始终用
openclaw cron add/edit或 Cron 工具 API 修改作业。如果必须手动编辑,先停止 Gateway。
10.3.10 Agent 绑定
在多 Agent 系统中,可以把 Cron 作业绑定到特定 Agent:
# 创建时绑定
openclaw cron add --name "Ops sweep" --cron "0 6 * * *" \
--session isolated --message "Check ops queue" --agent ops
# 修改现有作业的绑定
openclaw cron edit <jobId> --agent ops
openclaw cron edit <jobId> --clear-agent
如果指定的 Agent 不存在,作业会回退到默认 Agent。
10.4 Heartbeat vs Cron:选择指南
这是 OpenClaw 自动化中最常见的困惑点。用一个决策树来帮你快速判断:
任务需要精确时间执行吗?
├─ YES → 用 Cron
└─ NO → 继续...
│
任务需要和主会话隔离吗?
├─ YES → 用 Cron(隔离模式)
└─ NO → 继续...
│
能和其他检查批量执行吗?
├─ YES → 用 Heartbeat(加到 HEARTBEAT.md)
└─ NO → 用 Cron
│
是一次性提醒吗?
├─ YES → 用 Cron(--at)
└─ NO → 用 Heartbeat
│
需要不同的模型或思考级别?
├─ YES → 用 Cron(隔离模式 + --model)
└─ NO → 用 Heartbeat
实际场景对照表:
| 场景 | 推荐 | 原因 |
|---|---|---|
| 每 30 分钟检查收件箱 | Heartbeat | 批量检查,上下文感知 |
| 每天早上 9 点发日报 | Cron(隔离) | 精确时间,独立任务 |
| 20 分钟后提醒我开会 | Cron(主会话) | 一次性精确提醒 |
| 监控日历即将到来的事件 | Heartbeat | 周期性感知,自然适配 |
| 每周深度代码审查 | Cron(隔离) | 独立任务,用强模型 |
| 后台项目健康检查 | Heartbeat | 搭载已有周期 |
最佳实践:两者结合
最高效的自动化系统同时使用两种机制:
- Heartbeat 处理日常监控(收件箱、日历、通知),每次心跳一个 Turn 批量完成
- Cron 处理精确调度(日报、周报、一次性提醒)
这样既不会错过精确时间要求,又能把多个零散检查合并成一次 API 调用。
成本对比:
| 机制 | 成本特征 |
|---|---|
| Heartbeat | 每个 N 分钟一次 Turn;成本随 HEARTBEAT.md 大小增长 |
| Cron(主会话) | 下次心跳时处理,不产生额外的隔离 Turn |
| Cron(隔离) | 每个作业一次完整 Turn;可以用便宜模型 |
10.5 Webhook:外部系统的"门铃"
Heartbeat 和 Cron 都是 Agent 主动发起的。但如果外部系统(邮件、GitHub、监控)有事情发生呢?你需要一个"门铃"——Webhook。
10.5.1 启用 Webhook
{
hooks: {
enabled: true,
token: "your-shared-secret", // 必须!每个请求都需要携带
path: "/hooks", // 默认路径
},
}
⚠️ 安全警告:
hooks.token是 Webhook 的唯一认证。把它当作密码——不要和 Gateway 认证 Token 复用,定期更换。
10.5.2 两个核心端点
POST /hooks/wake — 唤醒主会话
curl -X POST http://127.0.0.1:18789/hooks/wake \
-H 'Authorization: Bearer SECRET' \
-H 'Content-Type: application/json' \
-d '{"text":"New email received","mode":"now"}'
效果:向主会话注入一个系统事件。mode: "now" 立即触发心跳,mode: "next-heartbeat" 等待下次心跳。
POST /hooks/agent — 运行独立 Agent Turn
curl -X POST http://127.0.0.1:18789/hooks/agent \
-H 'Authorization: Bearer SECRET' \
-H 'Content-Type: application/json' \
-d '{
"message": "Summarize new emails",
"name": "Email",
"sessionKey": "hook:email:msg-123",
"wakeMode": "now",
"deliver": true,
"channel": "last",
"model": "openai/gpt-5.2-mini"
}'
效果:在独立会话中运行 Agent Turn,结果摘要发布到主会话。
关键参数:
| 参数 | 说明 |
|---|---|
message |
发送给 Agent 的提示(必填) |
name |
Hook 名称,用于会话摘要前缀 |
sessionKey |
自定义会话键(默认拒绝,需开启 allowRequestSessionKey) |
wakeMode |
now(立即唤醒)或 next-heartbeat |
deliver |
是否把 Agent 回复发送到聊天通道 |
channel / to |
投递通道和目标 |
model |
模型覆盖 |
thinking |
思考级别覆盖 |
timeoutSeconds |
超时时间 |
agentId |
路由到特定 Agent |
10.5.3 会话键安全策略
sessionKey 允许调用者自定义会话,这是一个安全风险。OpenClaw 默认拒绝请求中的 sessionKey。
推荐配置:
{
hooks: {
enabled: true,
token: "${OPENCLAW_HOOK_TOKEN}",
defaultSessionKey: "hook:ingress", // 所有 Hook 使用固定会话
allowRequestSessionKey: false, // 禁止调用者自定义
allowedSessionKeyPrefixes: ["hook:"], // 即使开启,也限制前缀
},
}
10.5.4 自定义 Hook 映射
POST /hooks/<name> 端点通过映射表把外部请求转换为 Agent 操作:
{
hooks: {
enabled: true,
token: "${OPENCLAW_HOOK_TOKEN}",
presets: ["gmail"], // 启用内置 Gmail 映射
mappings: [
{
match: { path: "github" },
action: "agent",
name: "GitHub",
messageTemplate: "New GitHub event: {{action}} on {{repo}}\n{{body}}",
deliver: true,
channel: "slack",
to: "channel:C1234567890",
},
],
},
}
映射可以把任意外部 payload 转换为 Agent 可理解的 prompt。你还可以用 JS/TS 模块做更复杂的转换:
{
hooks: {
transformsDir: "~/.openclaw/hooks/transforms",
mappings: [
{
match: { path: "custom" },
action: "agent",
transform: { module: "my-transform" },
deliver: true,
},
],
},
}
10.5.5 Gmail Pub/Sub 集成实战
Gmail 是最常见的 Webhook 场景——收到邮件时自动让 Agent 处理。OpenClaw 提供了完整的 Gmail Pub/Sub 集成。
一键设置(推荐):
openclaw webhooks gmail setup --account openclaw@gmail.com
这个命令会自动:
- 安装依赖(macOS 通过 Homebrew)
- 创建 GCP Pub/Sub Topic
- 配置 Gmail Watch
- 通过 Tailscale Funnel 暴露公共 HTTPS 端点
- 写入
hooks.gmail配置
手动配置:
{
hooks: {
enabled: true,
token: "${OPENCLAW_HOOK_TOKEN}",
presets: ["gmail"],
mappings: [
{
match: { path: "gmail" },
action: "agent",
wakeMode: "now",
name: "Gmail",
sessionKey: "hook:gmail:{{messages[0].id}}",
messageTemplate: "New email from {{messages[0].from}}\nSubject: {{messages[0].subject}}\n{{messages[0].snippet}}",
model: "openai/gpt-5.2-mini", // 用便宜模型处理邮件
deliver: true,
channel: "last",
},
],
},
}
Gmail 专用配置:
{
hooks: {
gmail: {
model: "openrouter/meta-llama/llama-3.3-70b-instruct:free",
thinking: "off",
},
},
}
⚠️ 踩坑记录
问题:Gmail Hook 收到邮件后没有触发 Agent。
原因:Pub/Sub Topic 和 OAuth Client 不在同一个 GCP 项目中。
解决:确保
gcloud config set project指向的是 OAuth Client 所属的项目。Gmail Watch 要求 Topic 必须和 OAuth Client 在同一项目中。
10.6 Hooks:事件驱动的"自动化胶水"
注意:这里的 Hooks 和上一节的 Webhook 是两个不同的概念。Webhook 是外部 HTTP 触发器;Hooks 是内部事件监听器——当 Agent 内部发生了某些事件时,自动执行你定义的逻辑。
10.6.1 两种 Hooks 的区别
┌───────────────────────────────────────────────────────┐
│ Hooks(内部事件监听) │
│ 触发源:Agent 内部事件 │
│ 例子:/new、/reset、会话压缩、消息收发 │
│ 实现:TypeScript 函数,运行在 Gateway 进程内 │
│ │
│ Webhook(外部 HTTP 触发) │
│ 触发源:外部系统 HTTP 请求 │
│ 例子:邮件推送、GitHub Webhook、监控告警 │
│ 实现:HTTP 端点 + 映射规则 │
└───────────────────────────────────────────────────────┘
10.6.2 四个内置 Hook
OpenClaw 自带四个内置 Hook:
| Hook | 事件 | 作用 |
|---|---|---|
| 💾 session-memory | command:new、command:reset |
会话重置时自动保存上下文到记忆文件 |
| 📎 bootstrap-extra-files | agent:bootstrap |
注入额外的工作空间引导文件 |
| 📝 command-logger | command |
记录所有命令到审计日志 |
| 🚀 boot-md | gateway:startup |
Gateway 启动时执行 BOOT.md 中的指令 |
查看和管理:
openclaw hooks list # 列出所有 Hook
openclaw hooks enable session-memory # 启用
openclaw hooks info session-memory # 查看详情
openclaw hooks check # 检查资格
10.6.3 session-memory Hook 详解
这是最有实用价值的内置 Hook。每次你执行 /new 或 /reset 时,它会自动把当前会话的最后 15 条消息保存到记忆文件:
# Session: 2026-03-28 14:30:00 UTC
- **Session Key**: agent:main:main
- **Session ID**: abc123def456
- **Source**: telegram
## Conversation Summary
user: Can you help me design the API?
assistant: Sure! Let's start with the endpoints...
文件保存在 <workspace>/memory/ 目录下,文件名由 LLM 自动生成(如 2026-03-28-api-design.md)。
为什么这很重要:没有 session-memory,每次 /new 都会丢失当前会话的上下文。有了它,Agent 可以在未来的会话中通过记忆系统回忆起之前的对话。
10.6.4 事件类型完整列表
命令事件:
command:new—/new命令command:reset—/reset命令command:stop—/stop命令
会话事件:
session:compact:before— 压缩前session:compact:after— 压缩后session:patch— 会话属性被修改
Agent 事件:
agent:bootstrap— 工作空间引导文件注入前
Gateway 事件:
gateway:startup— Gateway 启动完成后
消息事件:
message:received— 收到消息(媒体可能尚未处理)message:transcribed— 音频消息完成转录message:preprocessed— 消息完成所有预处理(媒体理解、链接理解)message:sent— 发送消息成功
10.6.5 创建自定义 Hook
一个 Hook 由两个文件组成:
my-hook/
├── HOOK.md # 元数据 + 文档
└── handler.ts # 处理函数
步骤 1:创建 Hook 目录
mkdir -p ~/.openclaw/hooks/my-hook
步骤 2:编写 HOOK.md
---
name: my-hook
description: "Logs all /new commands with context"
metadata:
openclaw:
emoji: "🔍"
events:
- "command:new"
---
# My Custom Hook
Logs session reset events with context information.
步骤 3:编写 handler.ts
const handler = async (event) => {
// 只处理 /new 命令
if (event.type !== "command" || event.action !== "new") {
return;
}
const { sessionKey, timestamp } = event;
const { workspaceDir, commandSource } = event.context;
console.log(`[my-hook] Session reset`);
console.log(` Key: ${sessionKey}`);
console.log(` Source: ${commandSource}`);
console.log(` Time: ${timestamp.toISOString()}`);
console.log(` Workspace: ${workspaceDir}`);
// 可选:向用户发送消息
event.messages.push("🔍 Session context saved to memory.");
};
export default handler;
步骤 4:启用并测试
openclaw hooks list # 确认 Hook 被发现
openclaw hooks enable my-hook # 启用
# 重启 Gateway
# 然后在聊天中发送 /new 触发 Hook
10.6.6 Hook 发现顺序
Hook 从四个目录按优先级被发现:
1. Bundled Hooks(<openclaw>/dist/hooks/bundled/)
└─ OpenClaw 自带,优先级最低
2. Plugin Hooks(插件内置)
└─ 安装的插件中的 Hook
3. Managed Hooks(~/.openclaw/hooks/)
└─ 用户安装的,可以覆盖 Bundled 和 Plugin
4. Workspace Hooks(<workspace>/hooks/)
└─ 工作空间级,默认禁用,不能覆盖上级
安全边界:
- Bundled、Plugin、Managed Hook 被视为可信本地代码,自动加载
- Workspace Hook 是仓库本地代码,需要显式启用才加载
10.6.7 Hook 最佳实践
保持 Handler 轻量:
// ✓ 好——异步执行,立即返回
const handler = async (event) => {
void processInBackground(event);
};
// ✗ 坏——阻塞命令处理
const handler = async (event) => {
await slowDatabaseQuery(event);
await evenSlowerAPICall(event);
};
优雅处理错误:
const handler = async (event) => {
try {
await riskyOperation(event);
} catch (err) {
console.error("[hook] Failed:", err.message);
// 不要抛出——让其他 Hook 继续执行
}
};
尽早过滤不相关事件:
const handler = async (event) => {
if (event.type !== "message" || event.action !== "received") {
return; // 不相关,立即退出
}
// 处理逻辑...
};
10.6.8 消息事件实战:构建消息审计系统
一个实际有用的场景:记录所有收发的消息,用于合规审计。
// handler.ts — 消息审计 Hook
const handler = async (event) => {
if (event.type !== "message") return;
if (event.action === "received") {
const { from, content, channelId } = event.context;
console.log(JSON.stringify({
direction: "inbound",
from,
channel: channelId,
content: content.substring(0, 200), // 截断长消息
timestamp: new Date().toISOString(),
}));
} else if (event.action === "sent") {
const { to, content, channelId, success } = event.context;
console.log(JSON.stringify({
direction: "outbound",
to,
channel: channelId,
success,
content: content.substring(0, 200),
timestamp: new Date().toISOString(),
}));
}
};
export default handler;
对应的 HOOK.md:
---
name: message-audit
description: "Audit log for all inbound and outbound messages"
metadata:
openclaw:
emoji: "📋"
events:
- "message:received"
- "message:sent"
---
10.7 Standing Orders:常驻指令(让 Agent 自主运行)
Cron 和 Webhook 解决了"什么时候做"的问题。但如果 Agent 不知道"做什么"和"怎么做",自动化就是空谈。
Standing Orders(常驻指令)就是给 Agent 的一份"常驻操作手册"——定义它被授权做什么、什么时候做、什么需要你批准、什么情况要停下来请示。
10.7.1 为什么需要 Standing Orders
没有 Standing Orders:
- 你每次都要手动告诉 Agent 做什么
- Agent 在两次指令之间处于空闲状态
- 例行工作容易被遗忘
有了 Standing Orders:
- Agent 在定义的边界内自主执行
- 例行工作按计划自动完成
- 你只需要处理异常和审批
打个比方:Standing Orders 就是把"每天提醒我发周报"变成"你负责周报,每周五下午 4 点自动发,只有异常时才通知我"。
10.7.2 Standing Orders 的结构
Standing Orders 写在 AGENTS.md 中(每次会话自动注入)或单独的 standing-orders.md 文件中。每个程序(Program)包含四个要素:
## Program: Weekly Status Report
**Authority:** Compile data, generate report, deliver to stakeholders
**Trigger:** Every Friday at 4 PM (enforced via cron job)
**Approval gate:** None for standard reports. Flag anomalies for human review.
**Escalation:** If data source is unavailable or metrics look unusual (>2σ from norm)
### Execution Steps
1. Pull metrics from configured sources
2. Compare to prior week and targets
3. Generate report in Reports/weekly/YYYY-MM-DD.md
4. Deliver summary via configured channel
5. Log completion to Agent/Logs/
### What NOT to Do
- Do not send reports to external parties
- Do not modify source data
- Do not skip delivery if metrics look bad — report accurately
10.7.3 Execute-Verify-Report 模式
Standing Orders 中最常见的失败模式是 Agent "嘴上说要做但没有做"。解决方法是在每个任务中强制执行 EVR 模式:
### Execution Rules
- Every task follows Execute-Verify-Report. No exceptions.
- "I'll do that" is not execution. Do it, then report.
- "Done" without verification is not acceptable. Prove it.
- If execution fails: retry once with adjusted approach.
- If still fails: report failure with diagnosis. Never silently fail.
- Never retry indefinitely — 3 attempts max, then escalate.
这个模式防止 Agent 犯最常见的错误:确认了任务但没有实际完成。
10.7.4 Standing Orders + Cron:完美配合
Standing Orders 定义"做什么",Cron 定义"什么时候做":
Standing Order: "你负责每日收件箱分类"
↓
Cron Job (每天 8:00): "按 Standing Orders 执行收件箱分类"
↓
Agent: 读取 Standing Orders → 执行步骤 → 报告结果
Cron 的 prompt 应该引用 Standing Orders,而不是重复指令:
openclaw cron add \
--name daily-inbox-triage \
--cron "0 8 * * 1-5" \
--tz America/New_York \
--timeout-seconds 300 \
--announce \
--channel bluebubbles \
--to "+1XXXXXXXXXX" \
--message "Execute daily inbox triage per standing orders. Check mail for new alerts. Parse, categorize, and persist each item. Report summary to owner. Escalate unknowns."
10.7.5 多程序架构
当 Agent 管理多个领域时,把 Standing Orders 拆分成独立的程序:
# Standing Orders
## Program 1: Inbox Management (Daily)
**Authority:** Read, categorize, and respond to emails
**Trigger:** Daily at 8 AM (cron)
**Approval gate:** External replies require review
**Escalation:** Unknown senders, sensitive topics
## Program 2: Financial Processing (Monthly + Event)
**Authority:** Process transactions, generate reports
**Trigger:** Monthly cycle OR new data file detected
**Approval gate:** Analysis automatic, recommendations need approval
**Escalation:** Single item > $500
## Program 3: System Monitoring (Continuous)
**Authority:** Check health, restart services, send alerts
**Trigger:** Every heartbeat cycle
**Approval gate:** Restart automatic. Escalate if fails twice.
**Escalation:** Service down > 5 minutes
## Escalation Rules (All Programs)
- Any action affecting external systems → notify owner
- Uncertainty → ask, don't guess
- 3 failed attempts → stop and escalate
10.7.6 从小权限开始
不要第一天就给 Agent 最大权限。先给最小权限,观察表现,逐步扩大:
第 1 周:只读(检查报告,不发送)
第 2 周:允许内部操作(写文件,整理数据)
第 3 周:允许有限发送(发到指定通道)
第 4 周:全自主(按 Standing Orders 运行,异常时请示)
10.8 综合实战:构建完整的自动化工作流
场景:个人助理的完整自动化系统
假设你是一个独立开发者,需要 Agent 帮你管理日常事务。以下是一个完整的自动化系统设计:
第一步:在 AGENTS.md 中定义 Standing Orders
# Standing Orders
## Program 1: Morning Briefing (Daily 7:30 AM)
**Authority:** Check inbox, calendar, weather, news; compile brief
**Trigger:** Cron job at 7:30 AM
**Approval gate:** None
**Escalation:** Calendar conflicts within 2 hours
### Execution
1. Check email inbox for overnight messages
2. Review calendar for today's events
3. Check weather for outdoor plans
4. Compile morning brief
5. Deliver to Telegram
## Program 2: Code Review (On-demand)
**Authority:** Review PR diffs, flag issues, suggest fixes
**Trigger:** Webhook from GitHub
**Approval gate:** None for review; comment posting requires approval
**Escalation:** Security vulnerabilities → immediate alert
## Program 3: Weekly Report (Fridays 4 PM)
**Authority:** Compile weekly progress, generate report
**Trigger:** Cron job Fridays at 4 PM
**Approval gate:** Review before sending
**Escalation:** Missing data sources
第二步:配置 HEARTBEAT.md
# Heartbeat checklist
- Check for urgent emails
- Review calendar for events in next 2 hours
- If idle for 8+ hours, send a check-in
- Check if any standing orders need attention
第三步:创建 Cron 作业
# 每日早报
openclaw cron add \
--name "Morning brief" \
--cron "30 7 * * *" \
--tz "Asia/Shanghai" \
--session isolated \
--message "Execute morning briefing per standing orders." \
--model "opus" \
--announce \
--channel telegram \
--to "123456789"
# 周报
openclaw cron add \
--name "Weekly report" \
--cron "0 16 * * 5" \
--tz "Asia/Shanghai" \
--session isolated \
--message "Execute weekly report per standing orders." \
--announce \
--channel telegram \
--to "123456789"
# 一次性提醒示例
openclaw cron add \
--name "Team meeting" \
--at "2026-03-28T14:00:00+08:00" \
--session main \
--system-event "Team standup starts in 30 minutes. Prepare notes." \
--wake now \
--delete-after-run
第四步:配置 Webhook(GitHub 代码审查)
{
hooks: {
enabled: true,
token: "${OPENCLAW_HOOK_TOKEN}",
mappings: [
{
match: { path: "github" },
action: "agent",
name: "GitHub",
sessionKey: "hook:github:{{body.pull_request.number}}",
messageTemplate: "New PR #{{body.pull_request.number}}: {{body.pull_request.title}}\nAuthor: {{body.pull_request.user.login}}\nAction: {{action}}\nReview per standing orders Program 2.",
deliver: true,
channel: "telegram",
to: "123456789",
},
],
},
}
第五步:启用关键 Hooks
openclaw hooks enable session-memory # 会话重置时保存记忆
openclaw hooks enable command-logger # 命令审计日志
第六步:配置心跳
{
agents: {
defaults: {
heartbeat: {
every: "30m",
target: "last",
activeHours: { start: "08:00", end: "23:00" },
lightContext: true,
isolatedSession: true,
},
},
},
}
这个系统的工作流:
07:30 Cron → 隔离会话生成早报 → 发送到 Telegram
08:00 Heartbeat → 检查收件箱和日历 → 无异常(HEARTBEAT_OK)
08:30 Heartbeat → 检查 → 发现日历冲突 → 发送提醒
09:15 GitHub Webhook → 新 PR → 隔离会话审查代码 → 发送审查结果
14:00 Cron → 主会话提醒 → "准备站会笔记"
...
16:00 Cron → 隔离会话生成周报 → 发送到 Telegram
10.9 自动化故障排查
自动化系统最大的问题不是配置错误,而是"静默失败"——你以为它在运行,其实没有。
10.9.1 诊断命令梯
从简单到复杂,逐步排查:
# 第一层:基础状态
openclaw status
openclaw gateway status
openclaw cron status
# 第二层:自动化状态
openclaw cron list
openclaw system heartbeat last
openclaw hooks list
# 第三层:详细日志
openclaw logs --follow
openclaw cron runs --id <jobId> --limit 20
10.9.2 Cron 没有运行
症状:预期时间到了,但什么都没发生。
排查步骤:
# 1. 确认 Cron 已启用
openclaw cron status
# 预期输出:enabled: true, nextWakeAtMs: <future timestamp>
# 2. 确认作业存在且启用
openclaw cron list
# 检查作业状态是否为 enabled
# 3. 确认时区正确
openclaw cron list # 检查 --tz 设置
常见签名:
| 日志信息 | 原因 | 解决 |
|---|---|---|
scheduler disabled |
cron.enabled: false 或 OPENCLAW_SKIP_CRON=1 |
启用 Cron |
timer tick failed |
调度器崩溃 | 查看堆栈日志 |
reason: not-due |
手动运行但作业未到时间 | 加 --force |
10.9.3 Cron 运行了但没有投递
症状:cron runs 显示成功,但没收到消息。
openclaw cron runs --id <jobId> --limit 20
openclaw channels status --probe # 检查通道连接
常见原因:
| 原因 | 检查方法 |
|---|---|
投递模式是 none |
openclaw cron list 检查 delivery |
| 通道目标无效 | 确认 channel 和 to 格式正确 |
| 通道认证失败 | openclaw channels status --probe |
Agent 回复了 HEARTBEAT_OK |
正常行为,无实质内容不投递 |
10.9.4 Heartbeat 被跳过
openclaw system heartbeat last
openclaw logs --follow
常见签名:
| 日志信息 | 原因 |
|---|---|
reason=quiet-hours |
当前时间在 activeHours 之外 |
requests-in-flight |
主队列忙,心跳延迟 |
empty-heartbeat-file |
HEARTBEAT.md 为空,跳过以节省 API 调用 |
alerts-disabled |
通道可见性设置抑制了心跳消息 |
10.9.5 时区陷阱
时区问题是自动化排查中最常见的坑:
# 检查心跳时区
openclaw config get agents.defaults.heartbeat.activeHours
openclaw config get agents.defaults.heartbeat.activeHours.timezone
# 检查用户时区
openclaw config get agents.defaults.userTimezone
规则:
- Cron 不指定
--tz时使用主机时区 - Heartbeat
activeHours优先使用userTimezone,然后是主机时区 - ISO 时间戳不带时区 = UTC
- 主机时区变化后,已创建的 Cron 作业的执行时间会跟着变
⚠️ 踩坑记录
问题:Cron 作业总是在错误的时间运行。
原因:服务器时区是 UTC,但你的
--tz设的是本地时区——看起来没问题,但 ISO 时间戳没有带时区后缀,被解析为 UTC。解决:始终在 ISO 时间戳中明确时区(如
2026-03-28T14:00:00+08:00),或者在 CLI 中用--tz参数。不要混用。
10.10 进阶:Lobster 工作流引擎
对于需要多步骤、审批门、可恢复的复杂自动化流水线,OpenClaw 提供了 Lobster 工作流引擎。
Lobster 适合的场景:
- 多步骤自动化——需要固定的工具调用流水线,不是单次 Agent Turn
- 审批门——副作用操作需要暂停等待你批准
- 可恢复运行——暂停后可以继续,不用从头开始
Lobster 和 Heartbeat/Cron 的关系:
- Heartbeat/Cron 决定什么时候运行
- Lobster 定义运行什么步骤
Lobster 作为可选插件启用:
{
tools: {
alsoAllow: ["lobster"],
},
}
本章小结
- 自动化三模型:Heartbeat(周期巡逻)、Cron(精确闹钟)、Webhook(事件门铃),三者互补而非互斥
- Heartbeat 适合批量检查,通过
HEARTBEAT.md定义检查清单,HEARTBEAT_OK信号避免无意义通知 - Cron 有主会话和隔离两种模式,隔离模式支持模型覆盖、自定义会话、三种投递方式
- 一次性任务用
at,周期任务用cron表达式,隔离运行用isolated - Webhook 通过
/hooks/wake和/hooks/agent两个端点接入外部系统 - Hooks 是内部事件监听器,支持命令、会话、消息等多种事件类型
- Standing Orders 是自动化的"操作手册",定义 Agent 的授权范围、触发条件和升级规则
- EVR(Execute-Verify-Report)模式防止 Agent "只说不做"
- 从小权限开始,观察表现,逐步扩大 Agent 的自主权限
下一步
Agent 有了自动化能力,可以"自己干活"了。但一个能自主运行的 Agent,安全问题是绕不开的。下一章深入 OpenClaw 的安全体系——从沙盒隔离到凭证管理,从威胁模型到生产部署,让你放心地把 Agent 放到生产环境。