Cron 排程(Gateway 排程器)

Cron 還是 Heartbeat? 請參閱 Cron vs Heartbeat 了解何時該用哪一個。

Cron 是 Gateway 內建的排程器。它會持久化排程、在正確的時間喚醒代理,並可選擇將輸出回傳到聊天中。

如果你想要「每天早上執行這個」或「20 分鐘後戳一下代理」,cron 就是對應的機制。

疑難排解:/automation/troubleshooting

重點摘要

  • Cron 在 Gateway 內部執行(不是在模型內部)。
  • 排程持久化在 ~/.openclaw/cron/ 下,重啟不會遺失。
  • 兩種執行方式:
    • 主要工作階段:排入系統事件,在下次 heartbeat 時執行。
    • 獨立:在 cron:<jobId> 中執行專屬的代理回合,支援投遞(預設為 announce 或 none)。
  • 喚醒是一級功能:排程可以要求「立即喚醒」或「等到下次 heartbeat」。
  • 每個排程可透過 delivery.mode = "webhook" + delivery.to = "<url>" 使用 webhook 推送。
  • cron.webhook 已設定時,儲存中含 notify: true 的舊版排程仍有向後相容的退回機制,建議將這些排程遷移到 webhook 投遞模式。
  • 升級時,openclaw doctor --fix 可在排程器處理之前正規化舊版 cron store 欄位。

快速上手(可直接執行)

建立一次性提醒,確認它存在,然後立即執行:

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"

工具呼叫對等方式(Gateway cron 工具)

標準 JSON 結構和範例,請參閱 JSON schema for tool calls

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" -> 在主要 heartbeat 中以主要上下文執行。
    • sessionTarget: "isolated" -> 在 cron:<jobId> 中執行專屬代理回合。
  3. 選擇 payload

    • 主要工作階段 -> payload.kind = "systemEvent"
    • 獨立工作階段 -> payload.kind = "agentTurn"

選用:一次性排程(schedule.kind = "at")成功後預設會刪除。設定 deleteAfterRun: false 可保留(成功後會停用)。

概念

排程

Cron 排程是一筆儲存的記錄,包含:

  • 排程表(何時應該執行),
  • payload(應該做什麼),
  • 選用的投遞模式announcewebhooknone)。
  • 選用的代理綁定agentId):在特定代理下執行排程;如果遺失或未知,Gateway 退回使用預設代理。

排程由穩定的 jobId 識別(用於 CLI/Gateway API)。 在代理工具呼叫中,jobId 是標準欄位;舊版 id 仍接受以保持相容。 一次性排程成功後預設自動刪除;設定 deleteAfterRun: false 可保留。

排程表

Cron 支援三種排程類型:

  • at:透過 schedule.at 的一次性時間戳(ISO 8601)。
  • every:固定間隔(毫秒)。
  • cron:5 欄位 cron 表達式(或 6 欄位含秒數),搭配選用的 IANA 時區。

Cron 表達式使用 croner。如果省略時區,使用 Gateway 主機的本地時區。

為了減少多個 Gateway 在整點時的負載高峰,OpenClaw 會對週期性整點表達式(例如 0 * * * *0 */2 * * *)套用確定性的逐排程錯開視窗,最多 5 分鐘。固定時刻的表達式如 0 7 * * * 則維持精確。

任何 cron 排程都可以用 schedule.staggerMs 設定明確的錯開視窗(0 維持精確計時)。CLI 捷徑:

  • --stagger 30s(或 1m5m)設定明確的錯開視窗。
  • --exact 強制 staggerMs = 0

主要 vs 獨立執行

主要工作階段排程(系統事件)

主要排程會排入系統事件並選擇性地喚醒 heartbeat 執行器。 必須使用 payload.kind = "systemEvent"

  • wakeMode: "now"(預設):事件觸發即時 heartbeat 執行。
  • wakeMode: "next-heartbeat":事件等待下次排定的 heartbeat。

當你想要搭配正常的 heartbeat 提示加上主要工作階段上下文時,這是最佳選擇。 請參閱 Heartbeat

獨立排程(專屬 cron 工作階段)

獨立排程在 cron:<jobId> 工作階段中執行專屬的代理回合。

關鍵行為:

  • 提示前綴為 [cron:<jobId> <job name>] 以利追蹤。
  • 每次執行開啟全新的工作階段 ID(不延續先前的對話)。
  • 預設行為:如果省略 delivery,獨立排程會投遞摘要(delivery.mode = "announce")。
  • delivery.mode 決定後續動作:
    • announce:將摘要投遞到目標頻道,並在主要工作階段發布簡短摘要。
    • webhook:當完成事件包含摘要時,將完成事件 payload POST 到 delivery.to
    • none:僅限內部(不投遞,不發布主要工作階段摘要)。
  • wakeMode 控制主要工作階段摘要的發布時機:
    • now:即時 heartbeat。
    • next-heartbeat:等待下次排定的 heartbeat。

獨立排程適合用於嘈雜、頻繁或不應污染主要聊天歷史的「背景雜務」。

Payload 結構(執行內容)

支援兩種 payload 類型:

  • systemEvent:僅限主要工作階段,透過 heartbeat 提示路由。
  • agentTurn:僅限獨立工作階段,執行專屬代理回合。

常見的 agentTurn 欄位:

  • message:必填文字提示。
  • model / thinking:選用的覆寫(見下方)。
  • timeoutSeconds:選用的逾時覆寫。
  • lightContext:選用的輕量啟動模式,適用於不需要工作區啟動檔案注入的排程。

投遞設定:

  • delivery.modenone | announce | webhook
  • delivery.channellast 或特定頻道。
  • delivery.to:頻道專屬目標(announce)或 webhook URL(webhook 模式)。
  • delivery.bestEffort:如果 announce 投遞失敗,不讓排程失敗。

Announce 投遞會在執行期間抑制訊息工具的發送;使用 delivery.channel/delivery.to 來指定聊天目標。當 delivery.mode = "none" 時,不會在主要工作階段發布摘要。

如果獨立排程省略 delivery,OpenClaw 預設為 announce

Announce 投遞流程

delivery.mode = "announce" 時,cron 透過外送頻道適配器直接投遞。 不會啟動主要代理來撰寫或轉發訊息。

行為細節:

  • 內容:投遞使用獨立執行的外送 payload(文字/媒體),搭配正常的分段和頻道格式化。
  • 僅為 heartbeat 回應(HEARTBEAT_OK 且無實質內容)不會投遞。
  • 如果獨立執行已透過訊息工具向同一目標發送訊息,投遞會跳過以避免重複。
  • 投遞目標遺失或無效時排程會失敗,除非設定 delivery.bestEffort = true
  • 僅在 delivery.mode = "announce" 時,簡短摘要會發布到主要工作階段。
  • 主要工作階段摘要遵循 wakeModenow 觸發即時 heartbeat,next-heartbeat 等待下次排定的 heartbeat。

Webhook 投遞流程

delivery.mode = "webhook" 時,cron 在完成事件包含摘要時,將完成事件 payload POST 到 delivery.to

行為細節:

  • 端點必須是有效的 HTTP(S) URL。
  • webhook 模式不會嘗試頻道投遞。
  • webhook 模式不會發布主要工作階段摘要。
  • 如果設定了 cron.webhookToken,驗證標頭為 Authorization: Bearer <cron.webhookToken>
  • 已棄用的退回:含 notify: true 的舊版儲存排程仍會 POST 到 cron.webhook(如果已設定),並帶警告以便你遷移到 delivery.mode = "webhook"

模型和思考覆寫

獨立排程(agentTurn)可以覆寫模型和思考層級:

  • model:供應商/模型字串(例如 anthropic/claude-sonnet-4-20250514)或別名(例如 opus
  • thinking:思考層級(offminimallowmediumhighxhigh;僅限 GPT-5.2 + Codex 模型)

注意:主要工作階段排程也可以設定 model,但這會改變共享的主要工作階段模型。建議僅在獨立排程上使用模型覆寫,以避免意外的上下文切換。

解析優先順序:

  1. 排程 payload 覆寫(最高)
  2. Hook 專屬預設值(例如 hooks.gmail.model
  3. 代理設定預設值

輕量啟動上下文

獨立排程(agentTurn)可設定 lightContext: true 以使用輕量啟動上下文。

  • 適用於不需要工作區啟動檔案注入的排程雜務。
  • 實際上,嵌入的執行環境以 bootstrapContextMode: "lightweight" 執行,刻意讓 cron 啟動上下文保持空白。
  • CLI 對應:openclaw cron add --light-context ...openclaw cron edit --light-context

投遞(頻道 + 目標)

獨立排程可透過頂層 delivery 設定將輸出投遞到頻道:

  • delivery.modeannounce(頻道投遞)、webhook(HTTP POST)或 none
  • delivery.channelwhatsapp / telegram / discord / slack / mattermost(外掛)/ signal / imessage / last
  • delivery.to:頻道專屬的收件人目標。

announce 投遞僅對獨立排程有效(sessionTarget: "isolated")。 webhook 投遞對主要和獨立排程都有效。

如果省略 delivery.channeldelivery.to,cron 可以退回使用主要工作階段的「上次路由」(代理上次回覆的位置)。

目標格式提醒:

  • Slack/Discord/Mattermost(外掛)目標應使用明確的前綴(例如 channel:<id>user:<id>)以避免歧義。 Mattermost 的裸 26 字元 ID 會先解析為使用者(如果使用者存在則為 DM,否則為頻道)——使用 user:<id>channel:<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 schema

透過 Gateway cron.* 工具直接呼叫(代理工具呼叫或 RPC)時使用這些結構。 CLI 旗標接受人類可讀的持續時間如 20m,但工具呼叫應使用 ISO 8601 字串表示 schedule.at,毫秒表示 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.",
    "lightContext": true
  },
  "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 仍接受以保持相容。
  • 在 patch 中使用 agentId: null 可清除代理綁定。

cron.run 和 cron.remove 參數

{ "jobId": "job-123", "mode": "force" }
{ "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)
  • 供應商過載(例如 Anthropic 529 overloaded_error、過載退回摘要)
  • 網路錯誤(timeout、ECONNRESET、fetch failed、socket)
  • 伺服器錯誤(5xx)
  • Cloudflare 相關錯誤

永久性錯誤(不重試)

  • 驗證失敗(invalid API key、unauthorized)
  • 設定或驗證錯誤
  • 其他非暫時性錯誤

預設行為(無設定)

一次性排程(schedule.kind: "at"):

  • 暫時性錯誤:最多重試 3 次,指數退避(30s -> 1m -> 5m)。
  • 永久性錯誤:立即停用。
  • 成功或跳過:停用(如果 deleteAfterRun: true 則刪除)。

週期性排程(cron / every):

  • 任何錯誤:在下次排定執行前套用指數退避(30s -> 1m -> 5m -> 15m -> 60m)。
  • 排程保持啟用;下次成功執行後退避重設。

配置 cron.retry 可覆寫這些預設值(參閱 Configuration)。

設定

{
  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", // 選用:webhook 模式的 bearer token
    sessionRetention: "24h", // 持續時間字串或 false
    runLog: {
      maxBytes: "2mb", // 預設 2_000_000 bytes
      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。
  • 推送時,payload 為 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 bytes
  • 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.maxBytesrunLog.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

週期性獨立排程(announce 到 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

cron.run 現在在手動執行排入佇列時就確認,而非等到排程完成後。成功的佇列回應看起來像 { ok: true, enqueued: true, runId }。如果排程正在執行或 --due 發現沒有到期項目,回應維持 { ok: true, ran: false, reason }。使用 openclaw cron runs --id <jobId>cron.runs Gateway 方法檢查最終的完成條目。

編輯現有排程(修補欄位):

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

Gateway API 介面

  • cron.listcron.statuscron.addcron.updatecron.remove
  • cron.run(force 或 due)、cron.runs 不建立排程的即時系統事件請使用 openclaw system event

疑難排解

「什麼都沒執行」

  • 檢查 cron 是否啟用:cron.enabledOPENCLAW_SKIP_CRON
  • 檢查 Gateway 是否持續執行(cron 在 Gateway 行程內執行)。
  • cron 排程:確認時區(--tz)和主機時區是否一致。

週期性排程在失敗後持續延遲

  • OpenClaw 在連續錯誤後對週期性排程套用指數重試退避:30s、1m、5m、15m,然後每次重試間隔 60m。
  • 下次成功執行後退避自動重設。
  • 一次性(at)排程對暫時性錯誤(速率限制、過載、網路、伺服器錯誤)最多重試 3 次搭配退避;永久性錯誤立即停用。參閱 Retry policy

Telegram 投遞到錯誤的位置

  • 論壇主題請使用 -100…:topic:<id>,明確且不會產生歧義。
  • 如果你在日誌或儲存的「上次路由」目標中看到 telegram:... 前綴,這是正常的;cron 投遞接受這些格式,仍能正確解析主題 ID。

子代理 announce 投遞重試

  • 子代理執行完成時,Gateway 會向請求者的工作階段宣布結果。
  • 如果 announce 流程回傳 false(例如請求者工作階段忙碌中),Gateway 最多重試 3 次,透過 announceRetryCount 追蹤。
  • 超過 endedAt 5 分鐘的 announce 會被強制過期,防止過期條目無限迴圈。
  • 如果你在日誌中看到重複的 announce 投遞,檢查子代理登錄冊中 announceRetryCount 值偏高的條目。