跳转到内容

Cron 任务

Cron 还是心跳 (Heartbeat)? 请参阅 Cron vs Heartbeat 以了解何时使用各机制。

Cron 是 Gateway 内置的调度器。它会持久化任务,在正确的时间唤醒 Agent,并可以可选地将输出发送回聊天界面。

如果你想实现“每天早上运行”或“20 分钟后提醒 Agent”,cron 就是相应的机制。

  • Cron 运行在 Gateway 内部(而不是模型内部)。
  • 任务持久化在 ~/.openclaw/cron/ 下,因此重启不会丢失调度。
  • 两种执行风格:
    • 主会话 (Main session): 排队一个系统事件,然后在下一次心跳时运行。
    • 隔离会话 (Isolated): 在 cron:<jobId> 中运行一个专门的 Agent 回合,可选地投递输出。
  • 唤醒是头等公民:任务可以请求“立即唤醒”或“下一次心跳”。

创建一个一次性提醒,验证它是否存在,并立即运行:

Terminal window
openclaw cron add \
--name "提醒" \
--at "2026-02-01T16:00:00Z" \
--session main \
--system-event "提醒:检查 cron 文档草稿" \
--wake now \
--delete-after-run
openclaw cron list
openclaw cron run <job-id> --force
openclaw cron runs --id <job-id>

调度一个带有投递功能的重复性隔离任务:

Terminal window
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 任务默认持久化在 Gateway 主机的 ~/.openclaw/cron/jobs.json 中。 Gateway 会将该文件加载到内存中,并在更改时写回,因此只有在 Gateway 停止时手动编辑才是安全的。建议使用 openclaw cron add/edit 或 cron 工具调用 API 进行更改。

可以将 cron 任务理解为:何时运行 + 要做什么。

  1. 选择调度

    • 一次性提醒 → schedule.kind = "at" (CLI: --at)
    • 重复性任务 → schedule.kind = "every"schedule.kind = "cron"
    • 如果你的 ISO 时间戳忽略了时区,它将被视为 UTC
  2. 选择运行位置

    • sessionTarget: "main" → 在下一次心跳期间使用主上下文运行。
    • sessionTarget: "isolated" → 在 cron:<jobId> 中运行一个专门的 Agent 回合。
  3. 选择负载 (Payload)

    • 主会话 → payload.kind = "systemEvent"
    • 隔离会话 → payload.kind = "agentTurn"

可选:deleteAfterRun: true 会在一次性任务运行成功后将其从存储中移除。

Cron 任务是一个存储的记录,包含:

  • 调度 (何时运行),
  • 负载 (要做什么),
  • 可选的 投递 (输出应发送到哪里)。
  • 可选的 Agent 绑定 (agentId):在特定的 Agent 下运行任务;如果缺失或未知,Gateway 将回退到默认 Agent。

任务由稳定的 jobId 标识(由 CLI/Gateway API 使用)。 在 Agent 工具调用中,jobId 是规范的;为了兼容性也接受旧的 id。 通过 deleteAfterRun: true,一次性任务在运行成功后可以自动删除。

Cron 支持三种调度类型:

  • at: 一次性时间戳(自 epoch 以来的毫秒数)。Gateway 接受 ISO 8601 并强制转换为 UTC。
  • every: 固定间隔(毫秒)。
  • cron: 带有可选 IANA 时区的 5 字段 cron 表达式。

Cron 表达式使用 croner。如果省略时区,则使用 Gateway 主机的本地时区。

主任务会排队一个系统事件,并可选地唤醒心跳运行器。 它们必须使用 payload.kind = "systemEvent"

  • wakeMode: "next-heartbeat" (默认): 事件等待下一次调度的心跳。
  • wakeMode: "now": 事件触发立即的心跳运行。

当你想要使用正常的心跳提示词 + 主会话上下文时,这是最佳选择。请参阅 心跳 (Heartbeat)

隔离任务在会话 cron:<jobId> 中运行一个专门的 Agent 回合。

关键行为:

  • 提示词带有 [cron:<jobId> <任务名称>] 前缀以便追溯。
  • 每次运行都会启动一个全新的会话 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-3-5-sonnet-20240620)或别名(例如 opus
  • thinking: 思考等级 (off, minimal, low, medium, high, xhigh)

注意:你也可以在主会话任务上设置 model,但这会更改共享的主会话模型。我们建议仅对隔离任务使用模型覆盖,以避免意外的上下文切换。

解析优先级:

  1. 任务负载覆盖(最高)
  2. Hook 特定默认值(例如 hooks.gmail.model
  3. Agent 配置默认值

隔离任务可以将输出投递到频道。任务负载可以指定:

  • channel: whatsapp / telegram / discord / slack / mattermost (插件) / signal / imessage / last
  • to: 频道特定的接收者目标

如果省略 channelto,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

直接调用 Gateway cron.* 工具(Agent 工具调用或 RPC)时使用这些结构。 CLI 标志接受人类可读的时间长度(如 20m),但工具调用使用 epoch 毫秒作为 atMseveryMsat 时间也接受 ISO 时间戳)。

一次性主会话任务 (系统事件):

{
"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)。
  • atMseveryMs 是 epoch 毫秒。
  • sessionTarget 必须是 "main""isolated",且必须与 payload.kind 匹配。
  • 可选字段:agentId, description, enabled, deleteAfterRun, isolation
  • 省略时 wakeMode 默认为 "next-heartbeat"
{
"jobId": "job-123",
"patch": {
"enabled": false,
"schedule": { "kind": "every", "everyMs": 3600000 }
}
}

说明:

  • jobId 是规范的;为了兼容性也接受 id
  • 在补丁中使用 agentId: null 来清除 Agent 绑定。
{ "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 (环境变量)

一次性提醒 (UTC ISO, 成功后自动删除):

Terminal window
openclaw cron add \
--name "发送提醒" \
--at "2026-01-12T18:00:00Z" \
--session main \
--system-event "提醒:提交报销单。" \
--wake now \
--delete-after-run

一次性提醒 (主会话,立即唤醒):

Terminal window
openclaw cron add \
--name "日历检查" \
--at "20m" \
--session main \
--system-event "下一次心跳:检查日历。" \
--wake now

重复性隔离任务 (投递到 WhatsApp):

Terminal window
openclaw cron add \
--name "晨间状态" \
--cron "0 7 * * *" \
--tz "America/Los_Angeles" \
--session isolated \
--message "总结今天的收件箱 + 日历。" \
--deliver \
--channel whatsapp \
--to "+15551234567"

重复性隔离任务 (投递到 Telegram 话题):

Terminal window
openclaw cron add \
--name "夜间总结 (话题)" \
--cron "0 22 * * *" \
--tz "America/Los_Angeles" \
--session isolated \
--message "总结今天;发送到夜间话题。" \
--deliver \
--channel telegram \
--to "-1001234567890:topic:123"

带有模型和思考等级覆盖的隔离任务:

Terminal window
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 设置):

Terminal window
# 将任务绑定到 Agent "ops"(如果该 Agent 缺失,则回退到默认值)
openclaw cron add --name "Ops 扫描" --cron "0 6 * * *" --session isolated --message "检查 ops 队列" --agent ops
# 切换或清除现有任务上的 Agent
openclaw cron edit <jobId> --agent ops
openclaw cron edit <jobId> --clear-agent

手动运行 (调试用):

Terminal window
openclaw cron run <jobId> --force

编辑现有任务 (补丁字段):

Terminal window
openclaw cron edit <jobId> \
--message "更新后的提示词" \
--model "opus" \
--thinking low

运行历史:

Terminal window
openclaw cron runs --id <jobId> --limit 50

不创建任务而立即发送系统事件:

Terminal window
openclaw system event --mode now --text "下一次心跳:检查电池。"
  • cron.list, cron.status, cron.add, cron.update, cron.remove
  • cron.run (强制或到期), cron.runs 对于不带任务的即时系统事件,请使用 openclaw system event
  • 检查 cron 是否已启用:cron.enabledOPENCLAW_SKIP_CRON
  • 检查 Gateway 是否在持续运行(cron 在 Gateway 进程内部运行)。
  • 对于 cron 调度:确认时区 (--tz) 与主机时区。
  • 对于论坛话题,请使用 -100…:topic:<id>,这样显式且无歧义。
  • 如果你在日志或存储的“最后路由”目标中看到 telegram:... 前缀,这是正常的;cron 投递接受它们,并且仍然能正确解析话题 ID。