定时任务(网关调度器)

Cron vs 心跳: 请参考 Cron vs 心beat 了解何时使用各自的指南。

Cron 是网关的内置调度器。它会持久化任务,在正确的时间唤醒代理,并且可以选择将输出返回到聊天窗口。

如果您想”每天早上运行这个”或”20分钟后提醒代理”,cron 就是这种机制。

故障排除:/zh/docs/automation/troubleshooting

简要说明

  • Cron 在网关内部运行(不在模型内部)。
  • 任务持久化在 ~/.openclaw/cron/ 下,因此重启不会丢失计划。
  • 两种执行方式:
    • 主会话:将系统事件加入队列,然后在下一个心跳时运行。
    • 独立运行:在 cron:<jobId> 中运行专用代理回合,并进行投递(默认宣布或无)。
  • 唤醒是一等的:任务可以请求”立即唤醒”或”下一个心跳”。
  • Webhook 发布通过 delivery.mode = "webhook" + delivery.to = "<url>" 每个任务单独配置。
  • 对于已存储的带 notify: true 的任务,当设置了 cron.webhook 时仍保留传统回退,请将这些任务迁移到 webhook 投递模式。

快速开始(可操作)

创建一次性提醒,验证它存在,然后立即运行:

openclaw cron add \
  --name "Reminder" \
  --at "2026-02-01T16:00:00Z" \
  --session main \
  --system-event "Reminder: check the cron docs draft" \
  --wake now \
  --delete-after-run

openclaw cron list
openclaw cron run <job-id>
openclaw cron runs --id <job-id>

安排一个带投递的重复独立任务:

openclaw cron add \
  --name "Morning brief" \
  --cron "0 7 * * *" \
  --tz "America/Los_Angeles" \
  --session isolated \
  --message "Summarize overnight updates." \
  --announce \
  --channel slack \
  --to "channel:C1234567890"

工具调用 equivalents(Gateway cron 工具)

关于规范的 JSON 形状和示例,请参阅工具调用和 JSON 模式

Cron 任务存储位置

Cron 任务默认持久化在网关主机的 ~/.openclaw/cron/jobs.json。 网关将文件加载到内存中,并在更改时写回,因此手动编辑只有在网关停止时才是安全的。 请优先使用 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> 中运行专用代理回合。
  3. 选择负载

    • 主会话:payload.kind = "systemEvent"
    • 独立会话:payload.kind = "agentTurn"

可选:一次性任务(schedule.kind = "at")默认成功后自动删除。设置 deleteAfterRun: false 可以保留它们(成功后会自动禁用)。

概念

任务

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

  • 一?计划*(何时运行)?
  • 一?负载*(做什么)?
  • 可选的**投递模?*(announcewebhook ?none)?
  • 可选的代理绑定agentId):在特定代理下运行任务;如果缺失或未知,网关会回退到默认代理?

任务通过稳定?jobId 识别(CLI/网关 API 使用)? 在代理工具调用中,jobId 是规范的;为兼容性接受传?id? 一次性任务默认成功后自动删除;设?deleteAfterRun: false 可以保留它们?

计划

Cron 支持三种计划类型?

  • at:通过 schedule.at 的一次性时间戳(ISO 8601)?
  • every:固定间隔(毫秒)?
  • cron? 字段 cron 表达式(或带秒的 6 字段),带可选的 IANA 时区?

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

为减少多个网关之间的整点负载峰值,OpenClaw 对重复的整点表达式(例如 0 * * * *0 */2 * * *)应用了每个任务最?5 分钟的确定性抖动窗口。固定小时表达式(如 0 7 * * *)保持精确?

对于任何 cron 计划,您可以通过 schedule.staggerMs 设置显式抖动窗口(0 保持精确时间)。CLI 快捷方式?

  • --stagger 30s(或 1m5m)设置显式抖动窗口?
  • --exact 强制设置 staggerMs = 0?

主会?vs 独立执行

主会话任务(系统事件?

主任务将系统事件加入队列,并可选择唤醒心跳运行器? 它们必须使用 payload.kind = "systemEvent"?

  • wakeMode: "now"(默认):事件触发立即心跳运行?
  • wakeMode: "next-heartbeat":事件等待下一次计划心跳?

当您想要正常的心跳提?+ 主会话上下文时,这是最佳选择? 请参阅心跳?

独立任务(专?cron 会话?

独立任务在会?cron:<jobId> 中运行专用代理回合?

关键行为?

  • 提示前缀?[cron:<jobId> <job name>] 以便追踪?
  • 每次运行都会启动一个新?会话 ID*(没有之前的对话延续)?
  • 默认行为:如果省?delivery,独立任务会宣布摘要(delivery.mode = "announce")?
  • delivery.mode 选择发生什么:
    • announce:将摘要投递到目标频道,并发布简要摘要到主会话?
    • webhook:当完成事件包含摘要时,将完成事件负?POST ?delivery.to?
    • none:仅内部(无投递,无主会话摘要)?
  • wakeMode 控制主会话摘要何时发布:
    • now:立即心跳?
    • next-heartbeat:等待下一次计划心跳?

将独立任务用于频繁的、嘈杂的?后台杂务”,这些不应该刷屏您的主聊天历史?

负载形状(运行什么)

支持两种负载类型?

  • systemEvent:仅主会话,通过心跳提示路由?
  • agentTurn:仅独立会话,运行专用代理回合?

常见 agentTurn 字段?

  • message:必需的文本提示?
  • model / thinking:可选覆盖(见下文)?
  • timeoutSeconds:可选超时覆盖?

投递配置:

  • delivery.modenone | announce | webhook?
  • delivery.channellast 或特定频道?
  • delivery.to:频道特定的目标(宣布)?webhook URL(webhook 模式)?
  • delivery.bestEffort:避免在宣布投递失败时使任务失败?

宣布投递会抑制该运行的消息工具发送;使用 delivery.channel/delivery.to 定位到聊天。当 delivery.mode = "none" 时,不会向主会话发布摘要?

如果独立任务省略 delivery,OpenClaw 默认?announce?

宣布投递流?

?delivery.mode = "announce" 时,cron 直接通过出站频道适配器投递? 不会启动主代理来制作或转发消息?

行为详情?

  • 内容:投递使用独立运行的出站负载(文?媒体),进行正常分块和频道格式化?
  • 仅心跳响应(HEARTBEAT_OK 无实际内容)不会被投递?
  • 如果独立运行已通过消息工具向同一目标发送了消息,则跳过投递以避免重复?
  • 缺失或无效的投递目标会使任务失败,除非 delivery.bestEffort = true?
  • 简短摘要仅?delivery.mode = "announce" 时发布到主会话?
  • 主会话摘要遵?wakeModenow 触发立即心跳,next-heartbeat 等待下一次计划心跳?

Webhook 投递流?

?delivery.mode = "webhook" 时,cron 在完成事件包含摘要时将完成事件负?POST ?delivery.to?

行为详情?

  • 端点必须是有效的 HTTP(S) URL?
  • Webhook 模式下不尝试频道投递?
  • Webhook 模式下不向主会话发布摘要?
  • 如果设置?cron.webhookToken,认证头?Authorization: Bearer <cron.webhookToken>?
  • 传统回退:带 notify: true 的已存储传统任务仍会发布?cron.webhook(如果已配置),并带有警告,以便您可以迁移到 delivery.mode = "webhook"?

模型和思考覆?

独立任务(agentTurn)可以覆盖模型和思考级别:

  • model:提供商/模型字符串(例如 anthropic/claude-sonnet-4-20250514)或别名(例?opus?
  • thinking:思考级别(offminimallowmediumhighxhigh;仅 GPT-5.2 + Codex 模型?

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

解析优先级:

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

投递(频道 + 目标?

独立任务可以通过顶级 delivery 配置将输出投递到频道?

  • delivery.modeannounce(频道投递)、webhook(HTTP POST)或 none?
  • delivery.channelwhatsapp / telegram / discord / slack / mattermost(插件)/ signal / imessage / last?
  • delivery.to:频道特定的目标接收者?

announce 投递仅对独立任务有效(sessionTarget: "isolated")? webhook 投递对主会话和独立任务都有效?

如果省略 delivery.channel ?delivery.to,cron 可以回退到主会话?最后路?(代理最后回复的地方)?

目标格式提醒?

  • 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

工具调用?JSON 模式

在直接调用网?cron.* 工具时使用这些形状(代理工具调用?RPC)? CLI 标志接受人类可读的时长如 20m,但工具调用应对 schedule.at 使用 ISO 8601 字符串,?schedule.everyMs 使用毫秒?

cron.add 参数

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

{
  "name": "Reminder",
  "schedule": { "kind": "at", "at": "2026-02-01T16:00:00Z" },
  "sessionTarget": "main",
  "wakeMode": "now",
  "payload": { "kind": "systemEvent", "text": "Reminder text" },
  "deleteAfterRun": true
}

重复独立任务,带投递:

{
  "name": "Morning brief",
  "schedule": { "kind": "cron", "expr": "0 7 * * *", "tz": "America/Los_Angeles" },
  "sessionTarget": "isolated",
  "wakeMode": "next-heartbeat",
  "payload": {
    "kind": "agentTurn",
    "message": "Summarize overnight updates."
  },
  "delivery": {
    "mode": "announce",
    "channel": "slack",
    "to": "channel:C1234567890",
    "bestEffort": true
  }
}

注意?

  • schedule.kindatat)、everyeveryMs)或 cronexpr,可?tz)?
  • schedule.at 接受 ISO 8601(时区可选;省略时视?UTC)?
  • everyMs 是毫秒?
  • sessionTarget 必须?"main" ?"isolated",并且必须匹?payload.kind?
  • 可选字段:agentIddescriptionenableddeleteAfterRunat 默认?true)? delivery?
  • wakeMode 省略时默认为 "now"?

cron.update 参数

{
  "jobId": "job-123",
  "patch": {
    "enabled": false,
    "schedule": { "kind": "every", "everyMs": 3600000 }
  }
}

注意?

  • jobId 是规范的;id 为兼容性而接受?
  • 在补丁中使用 agentId: null 清除代理绑定?

cron.run ?cron.remove 参数

{ "jobId": "job-123", "mode": "force" }
{ "jobId": "job-123" }

存储和历?

  • 任务存储:~/.openclaw/cron/jobs.json(网关管理的 JSON)?
  • 运行历史:~/.openclaw/cron/runs/<jobId>.jsonl(JSONL,按大小和行数自动修剪)?
  • 独立 cron 运行会话?sessions.json 中按 cron.sessionRetention 修剪(默?24h;设?false 禁用)?
  • 覆盖存储路径:配置中?cron.store?

配置

{
  cron: {
    enabled: true, // 默认 true
    store: "~/.openclaw/cron/jobs.json",
    maxConcurrentRuns: 1, // 默认 1
    webhook: "https://example.invalid/legacy", // 传统回退,用于存储的 notify:true 任务
    webhookToken: "replace-with-dedicated-webhook-token", // webhook 模式的可?bearer 令牌
    sessionRetention: "24h", // 时长字符串或 false
    runLog: {
      maxBytes: "2mb", // 默认 2_000_000 字节
      keepLines: 2000, // 默认 2000
    },
  },
}

运行日志修剪行为?

  • cron.runLog.maxBytes:修剪前的最大运行日志文件大小?
  • cron.runLog.keepLines:修剪时仅保留最新的 N 行?
  • 两者都适用?cron/runs/<jobId>.jsonl 文件?

Webhook 行为?

  • 首选:每任务设?delivery.mode: "webhook" ?delivery.to: "https://..."?
  • Webhook URL 必须是有效的 http:// ?https:// URL?
  • 发布时,负载?cron 完成事件 JSON?
  • 如果设置?cron.webhookToken,认证头?Authorization: Bearer <cron.webhookToken>?
  • 如果未设?cron.webhookToken,则不发?Authorization 头?
  • 传统回退:带 notify: true 的已存储传统任务在存在时仍使?cron.webhook?

完全禁用 cron?

  • cron.enabled: false(配置)
  • OPENCLAW_SKIP_CRON=1(环境变量)

维护

Cron 有两条内置维护路径:独立运行会话保留和运行日志修剪?

默认?

  • cron.sessionRetention24h(设?false 禁用运行会话修剪?
  • cron.runLog.maxBytes2_000_000 字节
  • cron.runLog.keepLines2000

工作原理

  • 独立运行创建会话条目(...:cron:<jobId>:run:<uuid>)和转录文件?
  • 清理器删除早?cron.sessionRetention 的过期运行会话条目?
  • 对于不再被会话存储引用的已删除运行会话,OpenClaw 归档转录文件,并在同一保留窗口期间清除旧归档?
  • 每次运行追加后,检?cron/runs/<jobId>.jsonl 的大小:
    • 如果文件大小超过 runLog.maxBytes,则修剪为最新的 runLog.keepLines 行?

高容量调度器的性能注意事项

高频?cron 设置会产生大量运行会话和运行日志占用。内置了维护,但宽松的限制仍然会造成不必要的 IO 和清理工作?

需要注意:

  • 带有许多独立运行的长时间 cron.sessionRetention 窗口
  • ?cron.runLog.keepLines 结合?runLog.maxBytes
  • 许多嘈杂的重复任务写入同一 cron/runs/<jobId>.jsonl

应该做的?

  • 根据您的调试/审计需求尽可能保持 cron.sessionRetention 较短
  • 使用适度?runLog.maxBytes ?runLog.keepLines 保持运行日志有界
  • 将嘈杂的后台任务移至独立模式,并设置避免不必要的闲聊的投递规?
  • 定期?openclaw cron runs 检查增长,并在日志变大前调整保?

自定义示?

保留运行会话一周并允许更大的运行日志:

{
  cron: {
    sessionRetention: "7d",
    runLog: {
      maxBytes: "10mb",
      keepLines: 5000,
    },
  },
}

禁用独立运行会话修剪但保持运行日志修剪:

{
  cron: {
    sessionRetention: false,
    runLog: {
      maxBytes: "5mb",
      keepLines: 3000,
    },
  },
}

针对高容?cron 使用调整(示例)?

{
  cron: {
    sessionRetention: "12h",
    runLog: {
      maxBytes: "3mb",
      keepLines: 1500,
    },
  },
}

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." \
  --announce \
  --channel whatsapp \
  --to "+15551234567"

带显?30 秒抖动的重复 cron 任务?

openclaw cron add \
  --name "Minute watcher" \
  --cron "0 * * * * *" \
  --tz "UTC" \
  --stagger 30s \
  --session isolated \
  --message "Run minute watcher checks." \
  --announce

重复独立任务(投递到 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." \
  --announce \
  --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 \
  --announce \
  --channel whatsapp \
  --to "+15551234567"

代理选择(多代理设置):

# 将任务固定到代理 "ops"(如果该代理缺失则回退到默认)
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

手动运行(force 是默认的,使?--due 仅在到期时运行)?

openclaw cron run <jobId>
openclaw cron run <jobId> --due

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

openclaw cron edit <jobId> \
  --message "Updated prompt" \
  --model "opus" \
  --thinking low

强制现有 cron 任务精确按计划运行(无抖动)?

openclaw cron edit <jobId> --exact

运行历史?

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

无需创建任务即可立即发送系统事件:

openclaw system event --mode now --text "Next heartbeat: check battery."

网关 API 表面

  • cron.listcron.statuscron.addcron.updatecron.remove
  • cron.run(force ?due)、cron.runs 对于无需任务的立即系统事件,请使用openclaw system event?

故障排除

”什么都不运?

  • 检?cron 是否已启用:cron.enabled ?OPENCLAW_SKIP_CRON?
  • 检查网关是否持续运行(cron 在网关进程内部运行)?
  • 对于 cron 计划:确认时区(--tz)vs 主机时区?

重复任务在失败后不断延迟

  • OpenClaw 对连续错误后的重复任务应用指数退避重试:30s?m?m?5m,然?60m 重试?
  • 退避在下一次成功运行后自动重置?
  • 一次性(at)任务在终端运行(okerror ?skipped)后禁用,不重试?

Telegram 投递到错误的地?

  • 对于论坛主题,使?-100?topic:<id> 使其明确且无歧义?
  • 如果您在日志或存储的”最后路?目标中看?telegram:... 前缀,这是正常的;cron 投递接受它们并仍能正确解析主题 ID?

子代理宣布投递重?

  • 当子代理运行完成时,网关会向请求者会话宣布结果?
  • 如果宣布流程返回 false(例如请求者会话忙碌),网关会重试最?3 次,并通过 announceRetryCount 跟踪?
  • 超过 endedAt 5 分钟的宣布会被强制过期,以防止过时条目无限循环?
  • 如果您在日志中看到重复的宣布投递,请检查子代理注册表中具有?announceRetryCount 值的条目?