Cron 任务
Cron 任务 (Gateway 调度器)
Section titled “Cron 任务 (Gateway 调度器)”Cron 还是心跳 (Heartbeat)? 请参阅 Cron vs Heartbeat 以了解何时使用各机制。
Cron 是 Gateway 内置的调度器。它会持久化任务,在正确的时间唤醒 Agent,并可以可选地将输出发送回聊天界面。
如果你想实现“每天早上运行”或“20 分钟后提醒 Agent”,cron 就是相应的机制。
- Cron 运行在 Gateway 内部(而不是模型内部)。
- 任务持久化在
~/.openclaw/cron/下,因此重启不会丢失调度。 - 两种执行风格:
- 主会话 (Main session): 排队一个系统事件,然后在下一次心跳时运行。
- 隔离会话 (Isolated): 在
cron:<jobId>中运行一个专门的 Agent 回合,可选地投递输出。
- 唤醒是头等公民:任务可以请求“立即唤醒”或“下一次心跳”。
创建一个一次性提醒,验证它是否存在,并立即运行:
openclaw cron add \ --name "提醒" \ --at "2026-02-01T16:00:00Z" \ --session main \ --system-event "提醒:检查 cron 文档草稿" \ --wake now \ --delete-after-run
openclaw cron listopenclaw cron run <job-id> --forceopenclaw cron runs --id <job-id>调度一个带有投递功能的重复性隔离任务:
openclaw cron add \ --name "晨报" \ --cron "0 7 * * *" \ --tz "America/Los_Angeles" \ --session isolated \ --message "总结昨晚的更新。" \ --deliver \ --channel slack \ --to "channel:C1234567890"工具调用等价物 (Gateway cron 工具)
Section titled “工具调用等价物 (Gateway cron 工具)”有关规范的 JSON 结构和示例,请参阅 工具调用的 JSON 模式。
Cron 任务的存储位置
Section titled “Cron 任务的存储位置”Cron 任务默认持久化在 Gateway 主机的 ~/.openclaw/cron/jobs.json 中。 Gateway 会将该文件加载到内存中,并在更改时写回,因此只有在 Gateway 停止时手动编辑才是安全的。建议使用 openclaw cron add/edit 或 cron 工具调用 API 进行更改。
可以将 cron 任务理解为:何时运行 + 要做什么。
选择调度
- 一次性提醒 →
schedule.kind = "at"(CLI:--at) - 重复性任务 →
schedule.kind = "every"或schedule.kind = "cron" - 如果你的 ISO 时间戳忽略了时区,它将被视为 UTC。
- 一次性提醒 →
选择运行位置
sessionTarget: "main"→ 在下一次心跳期间使用主上下文运行。sessionTarget: "isolated"→ 在cron:<jobId>中运行一个专门的 Agent 回合。
选择负载 (Payload)
- 主会话 →
payload.kind = "systemEvent" - 隔离会话 →
payload.kind = "agentTurn"
- 主会话 →
可选:deleteAfterRun: true 会在一次性任务运行成功后将其从存储中移除。
任务 (Jobs)
Section titled “任务 (Jobs)”Cron 任务是一个存储的记录,包含:
- 调度 (何时运行),
- 负载 (要做什么),
- 可选的 投递 (输出应发送到哪里)。
- 可选的 Agent 绑定 (
agentId):在特定的 Agent 下运行任务;如果缺失或未知,Gateway 将回退到默认 Agent。
任务由稳定的 jobId 标识(由 CLI/Gateway API 使用)。 在 Agent 工具调用中,jobId 是规范的;为了兼容性也接受旧的 id。 通过 deleteAfterRun: true,一次性任务在运行成功后可以自动删除。
调度 (Schedules)
Section titled “调度 (Schedules)”Cron 支持三种调度类型:
at: 一次性时间戳(自 epoch 以来的毫秒数)。Gateway 接受 ISO 8601 并强制转换为 UTC。every: 固定间隔(毫秒)。cron: 带有可选 IANA 时区的 5 字段 cron 表达式。
Cron 表达式使用 croner。如果省略时区,则使用 Gateway 主机的本地时区。
主执行 vs 隔离执行
Section titled “主执行 vs 隔离执行”主会话任务 (系统事件)
Section titled “主会话任务 (系统事件)”主任务会排队一个系统事件,并可选地唤醒心跳运行器。 它们必须使用 payload.kind = "systemEvent"。
wakeMode: "next-heartbeat"(默认): 事件等待下一次调度的心跳。wakeMode: "now": 事件触发立即的心跳运行。
当你想要使用正常的心跳提示词 + 主会话上下文时,这是最佳选择。请参阅 心跳 (Heartbeat)。
隔离任务 (专用 cron 会话)
Section titled “隔离任务 (专用 cron 会话)”隔离任务在会话 cron:<jobId> 中运行一个专门的 Agent 回合。
关键行为:
- 提示词带有
[cron:<jobId> <任务名称>]前缀以便追溯。 - 每次运行都会启动一个全新的会话 ID(不继承之前的对话)。
- 摘要会发布到主会话中(前缀为
Cron,可配置)。 wakeMode: "now"在发布摘要后触发立即的心跳。- 如果
payload.deliver: true,输出将投递到频道;否则保持在内部。
对于嘈杂、频繁或不应干扰主聊天历史的“后台杂务”,请使用隔离任务。
负载结构 (运行内容)
Section titled “负载结构 (运行内容)”支持两种负载类型:
systemEvent: 仅限主会话,通过心跳提示词路由。agentTurn: 仅限隔离会话,运行专门的 Agent 回合。
常见的 agentTurn 字段:
message: 必填文本提示词。model/thinking: 可选覆盖(见下文)。timeoutSeconds: 可选超时覆盖。deliver: 设置为true以将输出发送到频道目标。channel:last或特定频道。to: 频道特定的目标(手机号/聊天/频道 ID)。bestEffortDeliver: 避免因投递失败而导致任务失败。
隔离选项(仅适用于 session=isolated):
postToMainPrefix(CLI:--post-prefix): 主会话中系统事件的前缀。postToMainMode:summary(默认) 或full。postToMainMaxChars:postToMainMode=full时的最大字符数(默认 8000)。
模型和思考等级覆盖
Section titled “模型和思考等级覆盖”隔离任务 (agentTurn) 可以覆盖模型和思考等级:
model: 提供商/模型字符串(例如anthropic/claude-3-5-sonnet-20240620)或别名(例如opus)thinking: 思考等级 (off,minimal,low,medium,high,xhigh)
注意:你也可以在主会话任务上设置 model,但这会更改共享的主会话模型。我们建议仅对隔离任务使用模型覆盖,以避免意外的上下文切换。
解析优先级:
- 任务负载覆盖(最高)
- Hook 特定默认值(例如
hooks.gmail.model) - Agent 配置默认值
投递 (频道 + 目标)
Section titled “投递 (频道 + 目标)”隔离任务可以将输出投递到频道。任务负载可以指定:
channel:whatsapp/telegram/discord/slack/mattermost(插件) /signal/imessage/lastto: 频道特定的接收者目标
如果省略 channel 或 to,cron 可以回退到主会话的“最后路由 (last route)”(Agent 最后回复的地方)。
投递说明:
- 如果设置了
to,即使省略deliver,cron 也会自动投递 Agent 的最终输出。 - 当你想要在没有显式
to的情况下使用最后路由投递时,请使用deliver: true。 - 使用
deliver: false即使存在to也要保持输出在内部。
目标格式提醒:
- Slack/Discord/Mattermost (插件) 目标应使用显式前缀(例如
channel:<id>,user:<id>)以避免歧义。 - Telegram 话题应使用
:topic:形式(见下文)。
Telegram 投递目标 (话题 / 论坛线程)
Section titled “Telegram 投递目标 (话题 / 论坛线程)”Telegram 通过 message_thread_id 支持论坛话题。对于 cron 投递,你可以将话题/线程编码到 to 字段中:
-1001234567890(仅聊天 ID)-1001234567890:topic:123(首选:显式话题标记)-1001234567890:123(简写:数字后缀)
也接受带有前缀的目标,如 telegram:... / telegram:group:...:
telegram:group:-1001234567890:topic:123
工具调用的 JSON 模式
Section titled “工具调用的 JSON 模式”直接调用 Gateway cron.* 工具(Agent 工具调用或 RPC)时使用这些结构。 CLI 标志接受人类可读的时间长度(如 20m),但工具调用使用 epoch 毫秒作为 atMs 和 everyMs(at 时间也接受 ISO 时间戳)。
cron.add 参数
Section titled “cron.add 参数”一次性主会话任务 (系统事件):
{ "name": "提醒", "schedule": { "kind": "at", "atMs": 1738262400000 }, "sessionTarget": "main", "wakeMode": "now", "payload": { "kind": "systemEvent", "text": "提醒文本" }, "deleteAfterRun": true}重复性隔离任务并投递:
{ "name": "晨报", "schedule": { "kind": "cron", "expr": "0 7 * * *", "tz": "America/Los_Angeles" }, "sessionTarget": "isolated", "wakeMode": "next-heartbeat", "payload": { "kind": "agentTurn", "message": "总结昨晚的更新。", "deliver": true, "channel": "slack", "to": "channel:C1234567890", "bestEffortDeliver": true }, "isolation": { "postToMainPrefix": "Cron", "postToMainMode": "summary" }}说明:
schedule.kind:at(atMs),every(everyMs), 或cron(expr, 可选tz)。atMs和everyMs是 epoch 毫秒。sessionTarget必须是"main"或"isolated",且必须与payload.kind匹配。- 可选字段:
agentId,description,enabled,deleteAfterRun,isolation。 - 省略时
wakeMode默认为"next-heartbeat"。
cron.update 参数
Section titled “cron.update 参数”{ "jobId": "job-123", "patch": { "enabled": false, "schedule": { "kind": "every", "everyMs": 3600000 } }}说明:
jobId是规范的;为了兼容性也接受id。- 在补丁中使用
agentId: null来清除 Agent 绑定。
cron.run 和 cron.remove 参数
Section titled “cron.run 和 cron.remove 参数”{ "jobId": "job-123", "mode": "force" }{ "jobId": "job-123" }- 任务存储:
~/.openclaw/cron/jobs.json(Gateway 管理的 JSON)。 - 运行历史:
~/.openclaw/cron/runs/<jobId>.jsonl(JSONL,自动修剪)。 - 覆盖存储路径:配置中的
cron.store。
{ cron: { enabled: true, // 默认 true store: "~/.openclaw/cron/jobs.json", maxConcurrentRuns: 1, // 默认 1 },}完全禁用 cron:
cron.enabled: false(配置)OPENCLAW_SKIP_CRON=1(环境变量)
CLI 快速参考
Section titled “CLI 快速参考”一次性提醒 (UTC ISO, 成功后自动删除):
openclaw cron add \ --name "发送提醒" \ --at "2026-01-12T18:00:00Z" \ --session main \ --system-event "提醒:提交报销单。" \ --wake now \ --delete-after-run一次性提醒 (主会话,立即唤醒):
openclaw cron add \ --name "日历检查" \ --at "20m" \ --session main \ --system-event "下一次心跳:检查日历。" \ --wake now重复性隔离任务 (投递到 WhatsApp):
openclaw cron add \ --name "晨间状态" \ --cron "0 7 * * *" \ --tz "America/Los_Angeles" \ --session isolated \ --message "总结今天的收件箱 + 日历。" \ --deliver \ --channel whatsapp \ --to "+15551234567"重复性隔离任务 (投递到 Telegram 话题):
openclaw cron add \ --name "夜间总结 (话题)" \ --cron "0 22 * * *" \ --tz "America/Los_Angeles" \ --session isolated \ --message "总结今天;发送到夜间话题。" \ --deliver \ --channel telegram \ --to "-1001234567890:topic:123"带有模型和思考等级覆盖的隔离任务:
openclaw cron add \ --name "深度分析" \ --cron "0 6 * * 1" \ --tz "America/Los_Angeles" \ --session isolated \ --message "每周项目进度的深度分析。" \ --model "opus" \ --thinking high \ --deliver \ --channel whatsapp \ --to "+15551234567"Agent 选择 (多 Agent 设置):
# 将任务绑定到 Agent "ops"(如果该 Agent 缺失,则回退到默认值)openclaw cron add --name "Ops 扫描" --cron "0 6 * * *" --session isolated --message "检查 ops 队列" --agent ops
# 切换或清除现有任务上的 Agentopenclaw cron edit <jobId> --agent opsopenclaw cron edit <jobId> --clear-agent手动运行 (调试用):
openclaw cron run <jobId> --force编辑现有任务 (补丁字段):
openclaw cron edit <jobId> \ --message "更新后的提示词" \ --model "opus" \ --thinking low运行历史:
openclaw cron runs --id <jobId> --limit 50不创建任务而立即发送系统事件:
openclaw system event --mode now --text "下一次心跳:检查电池。"Gateway API 接口
Section titled “Gateway API 接口”cron.list,cron.status,cron.add,cron.update,cron.removecron.run(强制或到期),cron.runs对于不带任务的即时系统事件,请使用openclaw system event。
“什么也没运行”
Section titled ““什么也没运行””- 检查 cron 是否已启用:
cron.enabled和OPENCLAW_SKIP_CRON。 - 检查 Gateway 是否在持续运行(cron 在 Gateway 进程内部运行)。
- 对于
cron调度:确认时区 (--tz) 与主机时区。
Telegram 投递到了错误的地方
Section titled “Telegram 投递到了错误的地方”- 对于论坛话题,请使用
-100…:topic:<id>,这样显式且无歧义。 - 如果你在日志或存储的“最后路由”目标中看到
telegram:...前缀,这是正常的;cron 投递接受它们,并且仍然能正确解析话题 ID。