定时任务 (Cron jobs, Gateway 调度器)
定时任务 vs 心跳? 参见 定时任务 vs 心跳 了解何时使用哪种方式的指导。
Cron 是 Gateway 的内置调度器。它持久化任务,在正确的时间唤醒 agent,并可以选择将输出传递回聊天。
如果你想要*"每天早上运行这个"或"20 分钟后提醒 agent"*,cron 就是机制。
要点总结 (TL;DR)
- Cron 在 Gateway 内部运行(不在模型内部)。
- 任务持久化在 ~/.openclaw/cron/ 下,因此重启不会丢失调度。
- 两种执行方式:
- 主会话 (Main session):排队系统事件,然后在下一次心跳时运行。
- 隔离 (Isolated):在 cron:<jobId> 中运行专用 agent 轮次,可选择传递输出。
- 唤醒是一等公民:任务可以请求"立即唤醒" vs "下次心跳"。
新手友好概述
将 cron 任务视为:何时运行 + 做什么。
-
选择调度
- 一次性提醒 → schedule.kind = "at" (CLI: --at)
- 重复任务 → schedule.kind = "every" 或 schedule.kind = "cron"
- 如果你的 ISO 时间戳省略时区,它将被视为 UTC。
-
选择运行位置
- sessionTarget: "main" → 在下一次心跳期间使用主上下文运行。
- sessionTarget: "isolated" → 在 cron:<jobId> 中运行专用 agent 轮次。
-
选择负载
- 主会话 → payload.kind = "systemEvent"
- 隔离会话 → payload.kind = "agentTurn"
可选:deleteAfterRun: true 在成功的一次性任务后从存储中删除任务。
概念
任务 (Jobs)
Cron 任务是一个存储记录,包含:
- 调度 (schedule)(何时运行),
- 负载 (payload)(做什么),
- 可选的 传递 (delivery)(输出应发送到哪里)。
- 可选的 agent 绑定 (agentId):在特定 agent 下运行任务;如果缺失或未知,gateway 回退到默认 agent。
任务由稳定的 jobId 标识(由 CLI/Gateway API 使用)。在 agent 工具调用中,jobId 是规范的;旧版 id 被接受以实现兼容性。任务可以通过 deleteAfterRun: true 在成功的一次性运行后自动删除。
调度 (Schedules)
Cron 支持三种调度类型:
- at:一次性时间戳(自纪元以来的毫秒)。Gateway 接受 ISO 8601 并强制转换为 UTC。
- every:固定间隔(毫秒)。
- cron:5 字段 cron 表达式,带可选的 IANA 时区。
Cron 表达式使用 croner。如果省略时区,则使用 Gateway 主机的本地时区。
主会话 vs 隔离执行
主会话任务(系统事件)
主任务排队系统事件并可选择唤醒心跳运行器。它们必须使用 payload.kind = "systemEvent"。
- wakeMode: "next-heartbeat"(默认):事件等待下一次计划的心跳。
- wakeMode: "now":事件触发立即心跳运行。
这是当你想要正常心跳提示 + 主会话上下文时的最佳选择。参见 Heartbeat。
隔离任务(专用 cron 会话)
隔离任务在会话 cron:<jobId> 中运行专用 agent 轮次。
关键行为:
- 提示前缀为 [cron:<jobId> <job name>] 以便追踪。
- 每次运行启动一个新的会话 ID(没有之前的对话延续)。
- 摘要发布到主会话(前缀 Cron,可配置)。
- wakeMode: "now" 在发布摘要后触发立即心跳。
- 如果 payload.deliver: true,输出传递到渠道;否则保持内部。
对于嘈杂、频繁或"后台杂务"的任务使用隔离任务,这些任务不应该向你的主聊天历史发送垃圾信息。
负载形状(运行什么)
支持两种负载类型:
- 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)。
模型和推理覆盖
隔离任务(agentTurn)可以覆盖模型和推理级别:
- model:提供商/模型字符串(例如,anthropic/claude-sonnet-4-20250514)或别名(例如,opus)
- thinking:推理级别(off、minimal、low、medium、high、xhigh;仅 GPT-5.2 + Codex 模型)
注意:你也可以在主会话任务上设置 model,但它会更改共享主会话模型。我们建议仅对隔离任务进行模型覆盖,以避免意外的上下文转换。
解析优先级:
- 任务负载覆盖(最高)
- Hook 特定默认值(例如,hooks.gmail.model)
- Agent 配置默认值
传递(渠道 + 目标)
隔离任务可以将输出传递到渠道。任务负载可以指定:
- channel:whatsapp / telegram / discord / slack / mattermost(插件)/ signal / imessage / last
- to:渠道特定接收者目标
如果省略 channel 或 to,cron 可以回退到主会话的"最后路由"(agent 上次回复的地方)。
传递注意事项:
- 如果设置了 to,即使省略 deliver,cron 也会自动传递 agent 的最终输出。
- 当你想要最后路由传递而没有显式 to 时使用 deliver: true。
- 即使存在 to,使用 deliver: false 也可以保持输出内部。
目标格式提醒:
- Slack/Discord/Mattermost(插件)目标应使用显式前缀(例如 channel:<id>、user:<id>)以避免歧义。
- Telegram 主题应使用 :topic: 形式(见下文)。
Telegram 传递目标(主题/论坛线程)
Telegram 通过 message_thread_id 支持论坛主题。对于 cron 传递,你可以将主题/线程编码到 to 字段中:
- -1001234567890(仅聊天 ID)
- -1001234567890:topic:123(首选:显式主题标记)
- -1001234567890:123(简写:数字后缀)
还接受带前缀的目标,如 telegram:... / telegram:group:...:
- telegram:group:-1001234567890:topic: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 快速入门
一次性提醒(UTC ISO,成功后自动删除):
openclaw cron add \
--name "Send reminder" \
--at "2026-01-12T18:00:00Z" \
--session main \
--system-event "Reminder: submit expense report." \
--wake now \
--delete-after-run
一次性提醒(主会话,立即唤醒):
openclaw cron add \
--name "Calendar check" \
--at "20m" \
--session main \
--system-event "Next heartbeat: check calendar." \
--wake now
重复隔离任务(传递到 WhatsApp):
openclaw cron add \
--name "Morning status" \
--cron "0 7 * * *" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Summarize inbox + calendar for today." \
--deliver \
--channel whatsapp \
--to "+15551234567"
重复隔离任务(传递到 Telegram 主题):
openclaw cron add \
--name "Nightly summary (topic)" \
--cron "0 22 * * *" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Summarize today; send to the nightly topic." \
--deliver \
--channel telegram \
--to "-1001234567890:topic:123"
带模型和推理覆盖的隔离任务:
openclaw cron add \
--name "Deep analysis" \
--cron "0 6 * * 1" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Weekly deep analysis of project progress." \
--model "opus" \
--thinking high \
--deliver \
--channel whatsapp \
--to "+15551234567"
Agent 选择(多 agent 设置):
# 将任务固定到 agent "ops"(如果该 agent 缺失则回退到默认)
openclaw cron add --name "Ops sweep" --cron "0 6 * * *" --session isolated --message "Check ops queue" --agent ops
# 在现有任务上切换或清除 agent
openclaw cron edit <jobId> --agent ops
openclaw cron edit <jobId> --clear-agent
手动运行(调试):
openclaw cron run <jobId> --force
编辑现有任务(修补字段):
openclaw cron edit <jobId> \
--message "Updated prompt" \
--model "opus" \
--thinking low
运行历史:
openclaw cron runs --id <jobId> --limit 50
立即系统事件而不创建任务:
openclaw system event --mode now --text "Next heartbeat: check battery."
Gateway API 界面
- cron.list、cron.status、cron.add、cron.update、cron.remove
- cron.run(强制或到期)、cron.runs 对于没有任务的立即系统事件,使用 openclaw system event。
故障排除
"什么都不运行"
- 检查 cron 是否启用:cron.enabled 和 OPENCLAW_SKIP_CRON。
- 检查 Gateway 是否持续运行(cron 在 Gateway 进程内运行)。
- 对于 cron 调度:确认时区(--tz)vs 主机时区。
Telegram 传递到错误的地方
- 对于论坛主题,使用 -100…:topic:<id> 使其显式且明确。
- 如果你在日志或存储的"最后路由"目标中看到 telegram:... 前缀,这是正常的;cron 传递接受它们并仍然正确解析主题 ID。