Cron-Jobs (Gateway-Scheduler)

Cron vs Heartbeat? Siehe Cron vs Heartbeat für Entscheidungshilfe.

Cron ist der eingebaute Scheduler des Gateways. Er persistiert Jobs, weckt den Agent zur richtigen Zeit und kann optional die Ausgabe zurück in einen Chat liefern.

Wenn du “führe das jeden Morgen aus” oder “stupp den Agent in 20 Minuten an” willst, ist Cron der Mechanismus.

Fehlerbehebung: /automation/troubleshooting

TL;DR

  • Cron läuft innerhalb des Gateways (nicht innerhalb des Modells).
  • Jobs werden unter ~/.openclaw/cron/ persistiert, sodass Neustarts keine Zeitpläne verlieren.
  • Zwei Ausführungsstile:
    • Main-Session: Ein System-Event einreihen, dann beim nächsten Heartbeat ausführen.
    • Isoliert: Einen dedizierten Agent-Turn in cron:<jobId> ausführen, mit Zustellung (standardmäßig Announce oder None).
  • Wakeups sind erstklassig: Ein Job kann “sofort aufwecken” vs “nächster Heartbeat” anfordern.
  • Webhook-Posting ist pro Job über delivery.mode = "webhook" + delivery.to = "<url>".
  • Legacy-Fallback bleibt für gespeicherte Jobs mit notify: true wenn cron.webhook gesetzt ist, migriere diese Jobs zum Webhook-Delivery-Modus.
  • Für Upgrades kann openclaw doctor --fix Legacy-Cron-Store-Felder normalisieren, bevor der Scheduler sie anfasst.

Schnellstart (umsetzbar)

Erstelle eine Einmal-Erinnerung, prüfe ob sie existiert, und führe sie sofort aus:

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>

Plane einen wiederkehrenden isolierten Job mit Zustellung:

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"

Tool-Call-Äquivalente (Gateway-Cron-Tool)

Für die kanonischen JSON-Shapes und Beispiele siehe JSON-Schema für Tool-Calls.

Wo Cron-Jobs gespeichert werden

Cron-Jobs werden auf dem Gateway-Host standardmäßig unter ~/.openclaw/cron/jobs.json persistiert. Das Gateway lädt die Datei in den Speicher und schreibt sie bei Änderungen zurück, daher sind manuelle Bearbeitungen nur sicher, wenn das Gateway gestoppt ist. Bevorzuge openclaw cron add/edit oder die Cron- Tool-Call-API für Änderungen.

Übersicht für Einsteiger

Stelle dir einen Cron-Job vor als: wann ausführen + was tun.

  1. Zeitplan wählen

    • Einmal-Erinnerung → schedule.kind = "at" (CLI: --at)
    • Wiederkehrender Job → schedule.kind = "every" oder schedule.kind = "cron"
    • Wenn dein ISO-Zeitstempel keine Zeitzone enthält, wird er als UTC behandelt.
  2. Ausführungsort wählen

    • sessionTarget: "main" → Beim nächsten Heartbeat mit Main-Kontext ausführen.
    • sessionTarget: "isolated" → Einen dedizierten Agent-Turn in cron:<jobId> ausführen.
  3. Payload wählen

    • Main-Session → payload.kind = "systemEvent"
    • Isolierte Session → payload.kind = "agentTurn"

Optional: Einmal-Jobs (schedule.kind = "at") löschen sich nach Erfolg standardmäßig. Setze deleteAfterRun: false, um sie zu behalten (sie werden nach Erfolg deaktiviert).

Konzepte

Jobs

Ein Cron-Job ist ein gespeicherter Datensatz mit:

  • einem Zeitplan (wann er laufen soll),
  • einem Payload (was er tun soll),
  • optionalem Zustellmodus (announce, webhook oder none).
  • optionalem Agent-Binding (agentId): Den Job unter einem bestimmten Agent ausführen; wenn fehlend oder unbekannt, fällt das Gateway auf den Standard-Agent zurück.

Jobs werden durch eine stabile jobId identifiziert (verwendet von CLI/Gateway-APIs). In Agent-Tool-Calls ist jobId kanonisch; Legacy-id wird zur Kompatibilität akzeptiert. Einmal-Jobs löschen sich nach Erfolg standardmäßig; setze deleteAfterRun: false, um sie zu behalten.

Zeitpläne

Cron unterstützt drei Zeitplan-Arten:

  • at: Einmaliger Zeitstempel über schedule.at (ISO 8601).
  • every: Festes Intervall (ms).
  • cron: 5-Feld Cron-Ausdruck (oder 6-Feld mit Sekunden) mit optionaler IANA-Zeitzone.

Cron-Ausdrücke nutzen croner. Wenn eine Zeitzone weggelassen wird, wird die lokale Zeitzone des Gateway-Hosts verwendet.

Um Spitzenlast zur vollen Stunde über viele Gateways zu reduzieren, wendet OpenClaw ein deterministisches, pro-Job Stagger-Fenster von bis zu 5 Minuten für wiederkehrende Zur-vollen-Stunde-Ausdrücke an (zum Beispiel 0 * * * *, 0 */2 * * *). Feste-Stunde- Ausdrücke wie 0 7 * * * bleiben exakt.

Für jeden Cron-Zeitplan kannst du ein explizites Stagger-Fenster mit schedule.staggerMs setzen (0 behält exaktes Timing bei). CLI-Kürzel:

  • --stagger 30s (oder 1m, 5m) um ein explizites Stagger-Fenster zu setzen.
  • --exact um staggerMs = 0 zu erzwingen.

Main- vs isolierte Ausführung

Main-Session-Jobs (System-Events)

Main-Jobs reihen ein System-Event ein und wecken optional den Heartbeat-Runner. Sie müssen payload.kind = "systemEvent" verwenden.

  • wakeMode: "now" (Standard): Event löst einen sofortigen Heartbeat-Run aus.
  • wakeMode: "next-heartbeat": Event wartet auf den nächsten planmäßigen Heartbeat.

Das passt am besten, wenn du den normalen Heartbeat-Prompt + Main-Session-Kontext willst. Siehe Heartbeat.

Isolierte Jobs (dedizierte Cron-Sessions)

Isolierte Jobs führen einen dedizierten Agent-Turn in Session cron:<jobId> aus.

Wichtige Verhaltensweisen:

  • Prompt wird mit [cron:<jobId> <Job-Name>] prefixed für Nachverfolgbarkeit.
  • Jeder Lauf startet eine neue Session-ID (kein Carry-over früherer Gespräche).
  • Standardverhalten: Wenn delivery weggelassen wird, stellen isolierte Jobs eine Zusammenfassung zu (delivery.mode = "announce").
  • delivery.mode bestimmt, was passiert:
    • announce: Zusammenfassung an den Ziel-Channel liefern und eine kurze Zusammenfassung in die Main-Session posten.
    • webhook: Das fertige Event-Payload an delivery.to POSTen, wenn das fertige Event eine Zusammenfassung enthält.
    • none: Nur intern (keine Zustellung, keine Main-Session-Zusammenfassung).
  • wakeMode steuert, wann die Main-Session-Zusammenfassung postet:
    • now: Sofortiger Heartbeat.
    • next-heartbeat: Wartet auf den nächsten planmäßigen Heartbeat.

Nutze isolierte Jobs für laute, häufige oder „Hintergrund-Routinen”, die deine Main-Chat-History nicht vollmüllen sollen.

Payload-Shapes (was ausgeführt wird)

Zwei Payload-Arten werden unterstützt:

  • systemEvent: Nur Main-Session, wird durch den Heartbeat-Prompt geroutet.
  • agentTurn: Nur isolierte Session, führt einen dedizierten Agent-Turn aus.

Übliche agentTurn-Felder:

  • message: Erforderlicher Text-Prompt.
  • model / thinking: Optionale Overrides (siehe unten).
  • timeoutSeconds: Optionaler Timeout-Override.
  • lightContext: Optionaler leichtgewichtiger Bootstrap-Modus für Jobs, die keine Workspace-Bootstrap-Datei-Injektion brauchen.

Zustellkonfiguration:

  • delivery.mode: none | announce | webhook.
  • delivery.channel: last oder ein bestimmter Channel.
  • delivery.to: Channel-spezifisches Ziel (Announce) oder Webhook-URL (Webhook-Modus).
  • delivery.bestEffort: Job nicht fehlschlagen lassen, wenn Announce-Zustellung fehlschlägt.

Announce-Zustellung unterdrückt Messaging-Tool-Sends für den Lauf; nutze delivery.channel/delivery.to, um stattdessen den Chat anzusprechen. Bei delivery.mode = "none" wird keine Zusammenfassung in die Main-Session gepostet.

Wenn delivery bei isolierten Jobs weggelassen wird, setzt OpenClaw auf announce als Standard.

Announce-Zustellungsablauf

Bei delivery.mode = "announce" liefert Cron direkt über die Outbound-Channel-Adapter zu. Der Main-Agent wird nicht hochgefahren, um die Nachricht zu verfassen oder weiterzuleiten.

Verhaltensdetails:

  • Inhalt: Zustellung nutzt die Outbound-Payloads des isolierten Runs (Text/Media) mit normalem Chunking und Channel-Formatierung.
  • Heartbeat-only-Antworten (HEARTBEAT_OK ohne echten Inhalt) werden nicht zugestellt.
  • Wenn der isolierte Run bereits eine Nachricht an das gleiche Ziel über das Message-Tool gesendet hat, wird die Zustellung übersprungen, um Duplikate zu vermeiden.
  • Fehlende oder ungültige Zustellziele lassen den Job fehlschlagen, es sei denn delivery.bestEffort = true.
  • Eine kurze Zusammenfassung wird nur dann in die Main-Session gepostet, wenn delivery.mode = "announce".
  • Die Main-Session-Zusammenfassung respektiert wakeMode: now löst einen sofortigen Heartbeat aus und next-heartbeat wartet auf den nächsten planmäßigen Heartbeat.

Webhook-Zustellungsablauf

Bei delivery.mode = "webhook" postet Cron das fertige Event-Payload an delivery.to, wenn das fertige Event eine Zusammenfassung enthält.

Verhaltensdetails:

  • Der Endpunkt muss eine gültige HTTP(S)-URL sein.
  • Im Webhook-Modus wird kein Channel-Delivery versucht.
  • Im Webhook-Modus wird keine Main-Session-Zusammenfassung gepostet.
  • Wenn cron.webhookToken gesetzt ist, wird Auth-Header Authorization: Bearer <cron.webhookToken> gesendet.
  • Veralteter Fallback: Gespeicherte Legacy-Jobs mit notify: true posten weiterhin an cron.webhook (falls konfiguriert), mit einer Warnung, damit du auf delivery.mode = "webhook" migrieren kannst.

Modell- und Thinking-Overrides

Isolierte Jobs (agentTurn) können Modell und Thinking-Level überschreiben:

  • model: Provider/Modell-String (z.B. anthropic/claude-sonnet-4-20250514) oder Alias (z.B. opus)
  • thinking: Thinking-Level (off, minimal, low, medium, high, xhigh; nur GPT-5.2 + Codex-Modelle)

Hinweis: Du kannst model auch bei Main-Session-Jobs setzen, aber das ändert das geteilte Main- Session-Modell. Wir empfehlen Modell-Overrides nur für isolierte Jobs, um unerwartete Kontextwechsel zu vermeiden.

Auflösungspriorität:

  1. Job-Payload-Override (höchste)
  2. Hook-spezifische Defaults (z.B. hooks.gmail.model)
  3. Agent-Config-Standard

Leichtgewichtiger Bootstrap-Kontext

Isolierte Jobs (agentTurn) können lightContext: true setzen, um mit leichtgewichtigem Bootstrap-Kontext zu laufen.

  • Nutze das für geplante Routinen, die keine Workspace-Bootstrap-Datei-Injektion brauchen.
  • In der Praxis läuft die eingebettete Runtime mit bootstrapContextMode: "lightweight", was den Cron-Bootstrap-Kontext absichtlich leer hält.
  • CLI-Äquivalente: openclaw cron add --light-context ... und openclaw cron edit --light-context.

Zustellung (Channel + Ziel)

Isolierte Jobs können Ausgaben über die Top-Level delivery-Konfiguration an einen Channel liefern:

  • delivery.mode: announce (Channel-Zustellung), webhook (HTTP POST) oder none.
  • delivery.channel: whatsapp / telegram / discord / slack / mattermost (Plugin) / signal / imessage / last.
  • delivery.to: Channel-spezifisches Empfängerziel.

announce-Zustellung gilt nur für isolierte Jobs (sessionTarget: "isolated"). webhook-Zustellung gilt für sowohl Main- als auch isolierte Jobs.

Wenn delivery.channel oder delivery.to weggelassen wird, kann Cron auf die “letzte Route” der Main-Session zurückfallen (der letzte Ort, an dem der Agent geantwortet hat).

Zielformat-Erinnerungen:

  • Slack/Discord/Mattermost (Plugin) Ziele sollten explizite Präfixe verwenden (z.B. channel:<id>, user:<id>), um Mehrdeutigkeit zu vermeiden. Mattermost bare 26-Zeichen-IDs werden user-first aufgelöst (DM wenn User existiert, sonst Channel) — nutze user:<id> oder channel:<id> für deterministisches Routing.
  • Telegram-Topics sollten die :topic:-Form verwenden (siehe unten).

Telegram-Zustellziele (Topics / Forum-Threads)

Telegram unterstützt Forum-Topics über message_thread_id. Für Cron-Zustellung kannst du das Topic/Thread in das to-Feld kodieren:

  • -1001234567890 (nur Chat-ID)
  • -1001234567890:topic:123 (bevorzugt: expliziter Topic-Marker)
  • -1001234567890:123 (Kurzform: numerisches Suffix)

Präfixierte Targets wie telegram:... / telegram:group:... werden ebenfalls akzeptiert:

  • telegram:group:-1001234567890:topic:123

JSON-Schema für Tool-Calls

Nutze diese Shapes, wenn du Gateway cron.* Tools direkt aufrufst (Agent-Tool-Calls oder RPC). CLI-Flags akzeptieren menschliche Dauern wie 20m, aber Tool-Calls sollten einen ISO-8601-String für schedule.at und Millisekunden für schedule.everyMs verwenden.

cron.add Parameter

Einmal, Main-Session-Job (System-Event):

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

Wiederkehrend, isolierter Job mit Zustellung:

{
  "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
  }
}

Hinweise:

  • schedule.kind: at (at), every (everyMs) oder cron (expr, optionales tz).
  • schedule.at akzeptiert ISO 8601 (Zeitzone optional; wird als UTC behandelt wenn weggelassen).
  • everyMs ist in Millisekunden.
  • sessionTarget muss "main" oder "isolated" sein und muss zu payload.kind passen.
  • Optionale Felder: agentId, description, enabled, deleteAfterRun (Standard true für at), delivery.
  • wakeMode hat den Standard "now" wenn weggelassen.

cron.update Parameter

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

Hinweise:

  • jobId ist kanonisch; id wird zur Kompatibilität akzeptiert.
  • Nutze agentId: null im Patch, um ein Agent-Binding zu entfernen.

cron.run und cron.remove Parameter

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

Speicher & History

  • Job-Store: ~/.openclaw/cron/jobs.json (Gateway-verwaltetes JSON).
  • Run-History: ~/.openclaw/cron/runs/<jobId>.jsonl (JSONL, automatisch nach Größe und Zeilenanzahl bereinigt).
  • Isolierte Cron-Run-Sessions in sessions.json werden durch cron.sessionRetention bereinigt (Standard 24h; setze false zum Deaktivieren).
  • Store-Pfad überschreiben: cron.store in der Konfiguration.

Retry-Policy

Wenn ein Job fehlschlägt, klassifiziert OpenClaw Fehler als transient (wiederholbar) oder permanent (sofort deaktivieren).

Transiente Fehler (werden wiederholt)

  • Rate-Limit (429, too many requests, resource exhausted)
  • Provider-Überlastung (z.B. Anthropic 529 overloaded_error, Overload-Fallback-Zusammenfassungen)
  • Netzwerkfehler (Timeout, ECONNRESET, fetch failed, Socket)
  • Serverfehler (5xx)
  • Cloudflare-bezogene Fehler

Permanente Fehler (keine Wiederholung)

  • Auth-Fehler (ungültiger API-Key, unauthorized)
  • Konfigurations- oder Validierungsfehler
  • Andere nicht-transiente Fehler

Standardverhalten (ohne Konfiguration)

Einmal-Jobs (schedule.kind: "at"):

  • Bei transientem Fehler: Bis zu 3 Mal mit exponentiellem Backoff wiederholen (30s → 1m → 5m).
  • Bei permanentem Fehler: Sofort deaktivieren.
  • Bei Erfolg oder Skip: Deaktivieren (oder löschen wenn deleteAfterRun: true).

Wiederkehrende Jobs (cron / every):

  • Bei jedem Fehler: Exponentielles Backoff (30s → 1m → 5m → 15m → 60m) vor dem nächsten geplanten Lauf anwenden.
  • Job bleibt aktiviert; Backoff setzt sich nach dem nächsten erfolgreichen Lauf zurück.

Konfiguriere cron.retry, um diese Standards zu überschreiben (siehe Konfiguration).

Konfiguration

{
  cron: {
    enabled: true, // Standard true
    store: "~/.openclaw/cron/jobs.json",
    maxConcurrentRuns: 1, // Standard 1
    // Optional: Retry-Policy für Einmal-Jobs überschreiben
    retry: {
      maxAttempts: 3,
      backoffMs: [60000, 120000, 300000],
      retryOn: ["rate_limit", "overloaded", "network", "server_error"],
    },
    webhook: "https://example.invalid/legacy", // Veralteter Fallback für gespeicherte notify:true Jobs
    webhookToken: "replace-with-dedicated-webhook-token", // Optionales Bearer-Token für Webhook-Modus
    sessionRetention: "24h", // Dauer-String oder false
    runLog: {
      maxBytes: "2mb", // Standard 2_000_000 Bytes
      keepLines: 2000, // Standard 2000
    },
  },
}

Run-Log-Bereinigungsverhalten:

  • cron.runLog.maxBytes: Maximale Run-Log-Dateigröße vor Bereinigung.
  • cron.runLog.keepLines: Bei Bereinigung nur die neuesten N Zeilen behalten.
  • Beides gilt für cron/runs/<jobId>.jsonl-Dateien.

Webhook-Verhalten:

  • Bevorzugt: delivery.mode: "webhook" mit delivery.to: "https://..." pro Job setzen.
  • Webhook-URLs müssen gültige http://- oder https://-URLs sein.
  • Beim Posten ist der Payload das Cron-Finished-Event-JSON.
  • Wenn cron.webhookToken gesetzt ist, wird Auth-Header Authorization: Bearer <cron.webhookToken> gesendet.
  • Wenn cron.webhookToken nicht gesetzt ist, wird kein Authorization-Header gesendet.
  • Veralteter Fallback: Gespeicherte Legacy-Jobs mit notify: true nutzen weiterhin cron.webhook wenn vorhanden.

Cron komplett deaktivieren:

  • cron.enabled: false (Konfiguration)
  • OPENCLAW_SKIP_CRON=1 (Umgebungsvariable)

Wartung

Cron hat zwei eingebaute Wartungspfade: Retention isolierter Run-Sessions und Run-Log-Bereinigung.

Standards

  • cron.sessionRetention: 24h (setze false um Run-Session-Bereinigung zu deaktivieren)
  • cron.runLog.maxBytes: 2_000_000 Bytes
  • cron.runLog.keepLines: 2000

Wie es funktioniert

  • Isolierte Runs erstellen Session-Einträge (...:cron:<jobId>:run:<uuid>) und Transkriptdateien.
  • Der Reaper entfernt abgelaufene Run-Session-Einträge, die älter als cron.sessionRetention sind.
  • Für entfernte Run-Sessions, die nicht mehr vom Session-Store referenziert werden, archiviert OpenClaw Transkriptdateien und bereinigt alte gelöschte Archive im gleichen Retention-Fenster.
  • Nach jedem Run-Append wird cron/runs/<jobId>.jsonl auf Größe geprüft:
    • Wenn die Dateigröße runLog.maxBytes überschreitet, wird auf die neuesten runLog.keepLines Zeilen gekürzt.

Performance-Hinweis für Hochvolumen-Scheduler

Hochfrequente Cron-Setups können große Run-Session- und Run-Log-Spuren hinterlassen. Wartung ist eingebaut, aber lockere Limits können trotzdem vermeidbare IO- und Aufräumarbeit verursachen.

Worauf achten:

  • Lange cron.sessionRetention-Fenster mit vielen isolierten Runs
  • Hohe cron.runLog.keepLines kombiniert mit großen runLog.maxBytes
  • Viele laute wiederkehrende Jobs, die in die gleiche cron/runs/<jobId>.jsonl schreiben

Was tun:

  • Halte cron.sessionRetention so kurz, wie es deine Debugging-/Audit-Bedürfnisse erlauben
  • Halte Run-Logs mit moderaten runLog.maxBytes und runLog.keepLines begrenzt
  • Verschiebe laute Hintergrund-Jobs in den isolierten Modus mit Zustellregeln, die unnötiges Geplapper vermeiden
  • Prüfe das Wachstum regelmäßig mit openclaw cron runs und passe die Retention an, bevor Logs groß werden

Anpassungsbeispiele

Run-Sessions eine Woche behalten und größere Run-Logs erlauben:

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

Isolierte Run-Session-Bereinigung deaktivieren, aber Run-Log-Bereinigung behalten:

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

Für Hochvolumen-Cron-Nutzung optimieren (Beispiel):

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

CLI-Schnellstart

Einmal-Erinnerung (UTC ISO, automatisch löschen nach Erfolg):

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

Einmal-Erinnerung (Main-Session, sofort aufwecken):

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

Wiederkehrender isolierter Job (Announce an 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"

Wiederkehrender Cron-Job mit explizitem 30-Sekunden-Stagger:

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

Wiederkehrender isolierter Job (Zustellung an ein Telegram-Topic):

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"

Isolierter Job mit Modell- und Thinking-Override:

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-Auswahl (Multi-Agent-Setups):

# Job an Agent "ops" pinnen (fällt auf Standard zurück wenn Agent fehlt)
openclaw cron add --name "Ops sweep" --cron "0 6 * * *" --session isolated --message "Check ops queue" --agent ops

# Agent bei bestehendem Job wechseln oder entfernen
openclaw cron edit <jobId> --agent ops
openclaw cron edit <jobId> --clear-agent

Manueller Run (Force ist Standard, nutze --due um nur bei Fälligkeit auszuführen):

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

cron.run bestätigt jetzt, sobald der manuelle Run in die Queue gestellt wurde, nicht erst nach Abschluss des Jobs. Erfolgreiche Queue-Antworten sehen aus wie { ok: true, enqueued: true, runId }. Wenn der Job bereits läuft oder --due nichts Fälliges findet, bleibt die Antwort { ok: true, ran: false, reason }. Nutze openclaw cron runs --id <jobId> oder die cron.runs Gateway-Methode, um den eventuellen Finished-Eintrag einzusehen.

Bestehenden Job bearbeiten (Felder patchen):

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

Bestehenden Cron-Job erzwingen, exakt nach Zeitplan zu laufen (kein Stagger):

openclaw cron edit <jobId> --exact

Run-History:

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

Sofortiges System-Event ohne Job zu erstellen:

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

Gateway-API-Oberfläche

  • cron.list, cron.status, cron.add, cron.update, cron.remove
  • cron.run (Force oder Due), cron.runs Für sofortige System-Events ohne Job nutze openclaw system event.

Fehlerbehebung

„Nichts läuft”

  • Prüfe ob Cron aktiviert ist: cron.enabled und OPENCLAW_SKIP_CRON.
  • Prüfe ob das Gateway kontinuierlich läuft (Cron läuft innerhalb des Gateway-Prozesses).
  • Für cron-Zeitpläne: Zeitzone (--tz) vs Host-Zeitzone bestätigen.

Ein wiederkehrender Job verzögert sich nach Fehlern immer weiter

  • OpenClaw wendet exponentielles Retry-Backoff bei wiederkehrenden Jobs nach aufeinanderfolgenden Fehlern an: 30s, 1m, 5m, 15m, dann 60m zwischen Wiederholungen.
  • Backoff setzt sich nach dem nächsten erfolgreichen Lauf automatisch zurück.
  • Einmal-(at)-Jobs wiederholen transiente Fehler (Rate-Limit, Overloaded, Netzwerk, Server-Error) bis zu 3 Mal mit Backoff; permanente Fehler deaktivieren sofort. Siehe Retry-Policy.

Telegram liefert an den falschen Ort

  • Für Forum-Topics nutze -100…:topic:<id>, damit es explizit und eindeutig ist.
  • Wenn du telegram:...-Präfixe in Logs oder gespeicherten „last route”-Targets siehst, ist das normal; Cron-Zustellung akzeptiert sie und parst Topic-IDs trotzdem korrekt.

Subagent-Announce-Zustellungs-Retries

  • Wenn ein Subagent-Run abschließt, kündigt das Gateway das Ergebnis der Requester-Session an.
  • Wenn der Announce-Flow false zurückgibt (z.B. Requester-Session ist beschäftigt), wiederholt das Gateway bis zu 3 Mal mit Tracking über announceRetryCount.
  • Announces, die älter als 5 Minuten nach endedAt sind, werden zwangs-expired, um zu verhindern, dass veraltete Einträge endlos schleifen.
  • Wenn du wiederholte Announce-Zustellungen in Logs siehst, prüfe die Subagent-Registry auf Einträge mit hohen announceRetryCount-Werten.