Skip to content

Cron 定时任务(Gateway 调度器)

Cron 还是 Heartbeat? 参见 Cron vs Heartbeat 了解选型建议。

Cron 是 Gateway 内置的调度器。它能持久化任务、在正确时间唤醒龙虾,还可以把输出回传到聊天界面。

想要"每天早上运行一次"或"20 分钟后提醒我",cron 就是你需要的机制。

故障排查:/openclaw/automation/troubleshooting

快速概览

  • Cron 运行在 Gateway 内部(不在模型内部)。
  • 任务持久化到 ~/.openclaw/cron/,重启不会丢失调度计划。
  • 两种执行模式:
    • 主会话:入队一个系统事件,下次心跳时执行。
    • 隔离:在 cron:<jobId> 或自定义会话中运行独立的 agent 轮次,并支持交付(默认 announce)。
    • 当前会话:绑定到创建 cron 时所在的会话(sessionTarget: "current")。
    • 自定义会话:在持久化命名会话中运行(sessionTarget: "session:custom-id")。
  • Wakeup 是一等公民:任务可以选择"立即唤醒"或"等下次心跳"。
  • Webhook 投递按任务配置,通过 delivery.mode = "webhook" + delivery.to = "<url>"
  • 存储中 notify: true 的旧式任务仍兼容 cron.webhook,建议迁移到 webhook 交付模式。
  • 升级时可用 openclaw doctor --fix 规范化旧 cron 存储字段。

快速上手

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

bash
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>

创建带交付的周期性隔离任务:

bash
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"

工具调用等价写法(Gateway cron 工具)

工具调用的标准 JSON 格式,见下方 JSON schema

Cron 任务存储位置

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 轮次。
    • sessionTarget: "current" → 绑定当前会话(创建时解析为 session:<sessionKey>)。
    • sessionTarget: "session:custom-id" → 在持久化命名会话中运行,跨次保留上下文。

    默认行为(不变):

    • systemEvent 载荷默认使用 main
    • agentTurn 载荷默认使用 isolated

    要使用当前会话绑定,需显式设置 sessionTarget: "current"

  3. 选择载荷类型

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

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

核心概念

任务(Jobs)

一个 cron 任务包含:

  • 调度计划(何时运行)
  • 载荷(做什么)
  • 可选的交付模式announcewebhooknone
  • 可选的 agent 绑定agentId):绑定到特定 agent 运行;缺失或未知时回退到默认 agent。

任务通过稳定的 jobId 标识(CLI/Gateway API 均使用)。工具调用中 jobId 为标准字段,兼容旧版 id。一次性任务默认成功后自动删除,设置 deleteAfterRun: false 可保留。

调度计划(Schedules)

Cron 支持三种调度方式:

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

Cron 表达式使用 croner 解析。若不指定时区,使用 Gateway 主机的本地时区。

为减少多 Gateway 实例的整点负载尖峰,OpenClaw 对整点周期性表达式(如 0 * * * *0 */2 * * *)按任务施加最多 5 分钟的确定性随机错开。固定小时表达式(如 0 7 * * *)保持精确。

可以用 schedule.staggerMs 设置显式错开窗口(0 表示精确执行)。CLI 快捷方式:

  • --stagger 30s(或 1m5m):设置错开窗口
  • --exact:强制 staggerMs = 0

主会话 vs 隔离执行

主会话任务(系统事件)

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

  • wakeMode: "now"(默认):事件触发立即心跳。
  • wakeMode: "next-heartbeat":事件等待下次定时心跳。

适合需要普通心跳提示词 + 主会话上下文的场景。参见 Heartbeat(如有该页面)。

隔离任务(独立 cron 会话)

隔离任务在 cron:<jobId> 或自定义会话中运行独立的 agent 轮次。

关键行为:

  • 提示词会加上 [cron:<jobId> <job name>] 前缀,便于追踪。
  • 每次运行使用全新 session id(无历史对话延续),自定义会话除外。
  • 自定义会话(session:xxx)跨次保留上下文,可实现类似"每日站会接续前次摘要"的工作流。
  • 默认行为:若省略 delivery,隔离任务默认 announce 摘要(delivery.mode = "announce")。
  • delivery.mode 决定后续处理:
    • announce:通过出站渠道适配器直接投递摘要,并在主会话发布简短摘要。
    • webhook:运行完成事件含摘要时,POST 到 delivery.to
    • none:仅内部处理(无投递,无主会话摘要)。
  • wakeMode 控制主会话摘要的发布时机:
    • now:立即触发心跳。
    • next-heartbeat:等待下次定时心跳。

对于嘈杂、高频或"后台杂务"类任务,用隔离模式避免污染主聊天记录。

载荷类型

支持两种载荷:

  • systemEvent:仅限主会话,通过心跳提示词路由。
  • agentTurn:仅限隔离会话,运行独立 agent 轮次。

agentTurn 常用字段:

  • message:必填,提示词文本。
  • model / thinking:可选覆盖(见下)。
  • timeoutSeconds:可选超时覆盖。
  • lightContext:可选轻量启动模式,适合不需要工作区 bootstrap 文件注入的任务。

交付配置:

  • delivery.modenone | announce | webhook
  • delivery.channellast 或指定渠道。
  • delivery.to:渠道特定目标(announce 模式)或 webhook URL(webhook 模式)。
  • delivery.bestEffort:announce 交付失败时不让任务失败。

Announce 交付会抑制该次运行中 messaging 工具的发送;用 delivery.channel/delivery.to 指定目标聊天。delivery.mode = "none" 时不向主会话发布摘要。

若隔离任务省略 delivery,OpenClaw 默认使用 announce

Announce 交付流程

delivery.mode = "announce" 时,cron 直接通过出站渠道适配器投递。主 agent 不会启动来转发消息。

行为细节:

  • 内容:使用隔离运行的出站载荷(文本/媒体),按正常分块和渠道格式化。
  • 仅含 HEARTBEAT_OK 的响应(无实质内容)不会投递。
  • 若隔离运行已通过 message 工具向同一目标发送了消息,则跳过投递以避免重复。
  • 目标缺失或无效时任务失败,除非 delivery.bestEffort = true
  • delivery.mode = "announce" 时才会向主会话发布简短摘要。
  • 主会话摘要遵循 wakeModenow 触发立即心跳,next-heartbeat 等待下次心跳。

Webhook 交付流程

delivery.mode = "webhook" 时,完成事件含摘要时,cron 将载荷 POST 到 delivery.to

行为细节:

  • 端点必须是合法的 HTTP(S) URL。
  • Webhook 模式不尝试渠道投递。
  • Webhook 模式不向主会话发布摘要。
  • 若设置了 cron.webhookToken,Auth 头为 Authorization: Bearer <cron.webhookToken>
  • 旧式降级:存储中 notify: true 的任务仍会 POST 到 cron.webhook(若已配置),并显示警告提示迁移。

模型与思考级别覆盖

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

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

注意:主会话任务也可设置 model,但会改变共享的主会话模型。建议只在隔离任务上覆盖模型,避免上下文意外切换。

解析优先级:

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

轻量 bootstrap 上下文

隔离任务(agentTurn)可设置 lightContext: true 使用轻量 bootstrap 上下文。

  • 适用于不需要工作区 bootstrap 文件注入的定时杂务。
  • 实际上,内嵌运行时使用 bootstrapContextMode: "lightweight",有意保持 cron bootstrap 上下文为空。
  • CLI 等价:openclaw cron add --light-context ...openclaw cron edit --light-context

交付(渠道 + 目标)

隔离任务可通过顶层 delivery 配置将输出投递到渠道:

  • delivery.modeannounce(渠道投递)、webhook(HTTP POST)或 none
  • delivery.channelwhatsapp / telegram / discord / slack / signal / imessage / irc / googlechat / line / last,以及扩展渠道如 msteams / mattermost(插件)。
  • delivery.to:渠道特定的接收目标。

announce 交付仅对隔离任务(sessionTarget: "isolated")有效。webhook 交付对主会话和隔离任务均有效。

若省略 delivery.channeldelivery.to,cron 可回退到主会话的"最后路由"(agent 最后一次回复的地方)。

目标格式提示:

  • Slack/Discord/Mattermost(插件)目标应使用显式前缀(如 channel:<id>user:<id>)以避免歧义。Mattermost 裸 26 字符 ID 优先解析为 user(若 user 存在则 DM,否则 channel)——建议用 user:<id>channel:<id> 确保确定性路由。
  • Telegram 话题应使用 :topic: 格式(见下)。

Telegram 交付目标(话题 / 论坛帖子)

Telegram 通过 message_thread_id 支持论坛话题。cron 交付时可在 to 字段编码话题/帖子:

  • -1001234567890(仅 chat id)
  • -1001234567890:topic:123(推荐:显式话题标记)
  • -1001234567890:123(简写:数字后缀)

也接受带前缀的目标:

  • telegram:group:-1001234567890:topic:123

JSON schema(工具调用)

直接调用 Gateway cron.* 工具时(agent 工具调用或 RPC),使用以下格式。CLI 接受 20m 这样的人性化时间,但工具调用中 schedule.at 应使用 ISO 8601 字符串,schedule.everyMs 应使用毫秒数。

cron.add 参数

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

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

周期性隔离任务(含交付):

json
{
  "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.",
    "lightContext": true
  },
  "delivery": {
    "mode": "announce",
    "channel": "slack",
    "to": "channel:C1234567890",
    "bestEffort": true
  }
}

绑定当前会话的周期性任务(创建时自动解析):

json
{
  "name": "Daily standup",
  "schedule": { "kind": "cron", "expr": "0 9 * * *" },
  "sessionTarget": "current",
  "payload": {
    "kind": "agentTurn",
    "message": "Summarize yesterday's progress."
  }
}

使用自定义持久化会话的周期性任务:

json
{
  "name": "Project monitor",
  "schedule": { "kind": "every", "everyMs": 300000 },
  "sessionTarget": "session:project-alpha-monitor",
  "payload": {
    "kind": "agentTurn",
    "message": "Check project status and update the running log."
  }
}

字段说明:

  • schedule.kindatat)、everyeveryMs)或 cronexpr,可选 tz)。
  • schedule.at 接受 ISO 8601。工具/API 无时区值视为 UTC;CLI 支持 openclaw cron add|edit --at "<offset-less-iso>" --tz <iana> 的本地时钟一次性任务。
  • everyMs 单位为毫秒。
  • sessionTarget"main""isolated""current""session:<custom-id>"
  • "current" 创建时解析为 "session:<sessionKey>"
  • 自定义会话(session:xxx)跨次保留上下文。
  • 可选字段:agentIddescriptionenableddeleteAfterRunat 类型默认 true)、delivery
  • wakeMode 省略时默认 "now"

cron.update 参数

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

说明:

  • jobId 为标准字段,兼容 id
  • agentId: null 清除 agent 绑定。

cron.run 和 cron.remove 参数

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

存储与历史

  • 任务存储:~/.openclaw/cron/jobs.json(Gateway 管理的 JSON)。
  • 运行历史:~/.openclaw/cron/runs/<jobId>.jsonl(JSONL,按大小和行数自动裁剪)。
  • sessions.json 中的隔离 cron 运行会话由 cron.sessionRetention 清理(默认 24h;设为 false 禁用)。
  • 覆盖存储路径:配置中的 cron.store

重试策略

任务失败时,OpenClaw 将错误分类为瞬时(可重试)或永久(立即禁用)。

瞬时错误(重试)

  • 速率限制(429、too many requests、resource exhausted)
  • Provider 过载(如 Anthropic 529 overloaded_error、过载降级摘要)
  • 网络错误(超时、ECONNRESET、fetch failed、socket)
  • 服务器错误(5xx)
  • Cloudflare 相关错误

永久错误(不重试)

  • 鉴权失败(无效 API key、未授权)
  • 配置或校验错误
  • 其他非瞬时错误

默认行为(无配置)

一次性任务(schedule.kind: "at"):

  • 瞬时错误:最多重试 3 次,指数退避(30s → 1m → 5m)。
  • 永久错误:立即禁用。
  • 成功或跳过:禁用(deleteAfterRun: true 则删除)。

周期性任务(cron / every):

  • 任何错误:对下次计划运行应用指数退避(30s → 1m → 5m → 15m → 60m)。
  • 任务保持启用;下次成功运行后退避重置。

可通过 cron.retry 覆盖默认值(见配置)。

配置

json5
{
  cron: {
    enabled: true, // 默认 true
    store: "~/.openclaw/cron/jobs.json",
    maxConcurrentRuns: 1, // 默认 1
    // 可选:覆盖一次性任务的重试策略
    retry: {
      maxAttempts: 3,
      backoffMs: [60000, 120000, 300000],
      retryOn: ["rate_limit", "overloaded", "network", "server_error"],
    },
    webhook: "https://example.invalid/legacy", // 旧式降级:notify:true 任务用
    webhookToken: "replace-with-dedicated-webhook-token", // 可选 bearer token
    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。
  • POST 载荷为 cron finished event JSON。
  • 若设置了 cron.webhookToken,Auth 头为 Authorization: Bearer <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>)和 transcript 文件。
  • 清理器删除超过 cron.sessionRetention 的旧会话条目。
  • 对于已从会话存储中删除的运行会话,OpenClaw 归档 transcript 文件,并在同一保留窗口内清除旧的已删除归档。
  • 每次追加运行记录后,检查 cron/runs/<jobId>.jsonl 的大小:
    • 若超过 runLog.maxBytes,裁剪为最新 runLog.keepLines 行。

高频调度的性能注意事项

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

需要关注:

  • 隔离运行次数多且 cron.sessionRetention 窗口长
  • cron.runLog.keepLines 高且 runLog.maxBytes
  • 多个嘈杂周期任务写同一个 cron/runs/<jobId>.jsonl

建议:

  • 根据调试/审计需要尽量缩短 cron.sessionRetention
  • 用适中的 runLog.maxBytesrunLog.keepLines 限制日志大小
  • 把嘈杂后台任务迁移到带交付规则的隔离模式,避免不必要的噪音
  • 定期用 openclaw cron runs 查看增长情况,在日志变大前调整保留策略

配置示例

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

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

禁用隔离运行会话裁剪,保留日志裁剪:

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

高频 cron 调优示例:

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

CLI 快速参考

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

bash
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

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

bash
openclaw cron add \
  --name "Calendar check" \
  --at "20m" \
  --session main \
  --system-event "Next heartbeat: check calendar." \
  --wake now

周期性隔离任务(announce 到 WhatsApp):

bash
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 秒错开的周期任务:

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

投递到 Telegram 话题的隔离任务:

bash
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"

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

bash
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"

Agent 选择(多 agent 场景):

bash
# 将任务绑定到 "ops" agent(找不到时回退默认 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

手动运行(默认强制,--due 仅在到期时运行):

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

cron.run 在手动运行入队后即返回确认,不等任务完成。成功入队响应形如 { ok: true, enqueued: true, runId }。若任务已在运行或 --due 未到期,响应为 { ok: true, ran: false, reason }。用 openclaw cron runs --id <jobId>cron.runs 查看最终完成记录。

修改现有任务(patch 字段):

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

强制现有任务按精确计划运行(无错开):

bash
openclaw cron edit <jobId> --exact

查看运行历史:

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

不创建任务直接发送系统事件:

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

Gateway API

  • cron.listcron.statuscron.addcron.updatecron.remove
  • cron.run(强制或到期时)、cron.runs 无需创建任务直接发送系统事件,用 openclaw system event(如有该页面)。

故障排查

"任务不执行"

  • 检查 cron 是否启用:cron.enabledOPENCLAW_SKIP_CRON
  • 检查 Gateway 是否持续运行(cron 在 Gateway 进程内运行)。
  • cron 调度:确认时区(--tz)与主机时区的关系。

周期任务在失败后持续延迟

  • OpenClaw 对周期任务连续失败后应用指数退避重试:30s、1m、5m、15m,最后 60m。
  • 下次成功运行后退避自动重置。
  • 一次性(at)任务对瞬时错误(速率限制、过载、网络、server_error)最多重试 3 次;永久错误立即禁用。参见重试策略

Telegram 投递到了错误的地方

  • 对论坛话题,使用 -100…:topic:<id> 以确保明确无歧义。
  • 若日志或存储的"last route"目标中出现 telegram:... 前缀,这是正常现象;cron 交付能接受并正确解析话题 ID。

子 agent announce 交付重试

  • 子 agent 运行完成后,gateway 向请求方会话发布结果。
  • 若 announce 流程返回 false(如请求方会话正忙),gateway 通过 announceRetryCount 跟踪并最多重试 3 次。
  • 超过 endedAt 后 5 分钟的 announce 会强制过期,防止陈旧条目无限循环。
  • 若日志中出现重复 announce 投递,检查子 agent 注册表中 announceRetryCount 较高的条目。