Cron Jobs (Gateway Scheduler)
Cron vs Heartbeat? Schau dir Cron vs Heartbeat an, um zu entscheiden, wann du was verwendest.
Cron ist der eingebaute Scheduler des Gateway. Er speichert Jobs persistent, weckt den Agent zur richtigen Zeit und kann optional die Ausgabe zurück in einen Chat liefern.
Wenn du “das jeden Morgen ausführen” oder “den Agent in 20 Minuten anstupsen” willst, ist Cron der richtige Mechanismus.
TL;DR
- Cron läuft im Gateway (nicht im Modell).
- Jobs werden unter
~/.openclaw/cron/gespeichert, sodass Neustarts keine Zeitpläne verlieren. - Zwei Ausführungsstile:
- Main Session: System-Event in die Warteschlange stellen, dann beim nächsten Heartbeat ausführen.
- Isolated: Dedizierte Agent-Ausführung in
cron:<jobId>, optional mit Ausgabe-Zustellung.
- Wakeups sind erstklassig: Ein Job kann “jetzt aufwecken” vs. “nächster Heartbeat” anfordern.
Schnellstart (praktisch)
Erstelle eine einmalige 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> --force
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." \
--deliver \
--channel slack \
--to "channel:C1234567890"
Tool-Call-Äquivalente (Gateway Cron Tool)
Die kanonischen JSON-Strukturen und Beispiele findest du unter JSON Schema für Tool Calls.
Wo Cron Jobs gespeichert werden
Cron Jobs werden standardmäßig auf dem Gateway-Host unter ~/.openclaw/cron/jobs.json persistent gespeichert.
Das Gateway lädt die Datei in den Speicher und schreibt sie bei Änderungen zurück. Manuelle Bearbeitungen sind daher nur sicher, wenn das Gateway gestoppt ist. Verwende besser openclaw cron add/edit oder die Cron Tool Call API für Änderungen.
Einsteigerfreundliche Übersicht
Denk an einen Cron Job als: wann ausführen + was tun.
-
Wähle einen Zeitplan
- Einmalige Erinnerung →
schedule.kind = "at"(CLI:--at) - Wiederkehrender Job →
schedule.kind = "every"oderschedule.kind = "cron" - Wenn dein ISO-Zeitstempel keine Zeitzone angibt, wird er als UTC behandelt.
- Einmalige Erinnerung →
-
Wähle wo er läuft
sessionTarget: "main"→ läuft beim nächsten Heartbeat mit Main-Context.sessionTarget: "isolated"→ läuft als dedizierte Agent-Ausführung incron:<jobId>.
-
Wähle die Payload
- Main Session →
payload.kind = "systemEvent" - Isolated Session →
payload.kind = "agentTurn"
- Main Session →
Optional: deleteAfterRun: true entfernt erfolgreiche einmalige Jobs aus dem Speicher.
Konzepte
Jobs
Ein Cron Job ist ein gespeicherter Datensatz mit:
- einem Schedule (wann er laufen soll),
- einer Payload (was er tun soll),
- optionaler Delivery (wohin die Ausgabe gesendet werden soll).
- optionalem Agent Binding (
agentId): Job unter einem bestimmten Agent ausführen; falls 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; das veraltete id wird aus Kompatibilitätsgründen akzeptiert.
Jobs können optional nach einer erfolgreichen einmaligen Ausführung automatisch gelöscht werden via deleteAfterRun: true.
Schedules
Cron unterstützt drei Schedule-Arten:
at: Einmaliger Zeitstempel (ms seit Epoch). Gateway akzeptiert ISO 8601 und konvertiert zu UTC.every: Festes Intervall (ms).cron: 5-Feld-Cron-Ausdruck mit optionaler IANA-Zeitzone.
Cron-Ausdrücke verwenden croner. Wenn eine Zeitzone weggelassen wird, wird die lokale Zeitzone des Gateway-Hosts verwendet.
Main vs. Isolated Execution
Main Session Jobs (System Events)
Main Jobs stellen ein System-Event in die Warteschlange und wecken optional den Heartbeat Runner.
Sie müssen payload.kind = "systemEvent" verwenden.
wakeMode: "next-heartbeat"(Standard): Event wartet auf den nächsten geplanten Heartbeat.wakeMode: "now": Event löst einen sofortigen Heartbeat-Lauf aus.
Das ist die beste Wahl, wenn du den normalen Heartbeat Prompt + Main-Session-Context willst. Siehe Heartbeat.
Isolated Jobs (dedizierte Cron Sessions)
Isolated Jobs führen eine dedizierte Agent-Ausführung in Session cron:<jobId> aus.
Wichtige Verhaltensweisen:
- Prompt wird mit
[cron:<jobId> <job name>]für Nachvollziehbarkeit präfixiert. - Jede Ausführung startet eine frische Session ID (keine Übernahme vorheriger Konversationen).
- Eine Zusammenfassung wird in die Main Session gepostet (Präfix
Cron, konfigurierbar). wakeMode: "now"löst einen sofortigen Heartbeat nach dem Posten der Zusammenfassung aus.- Wenn
payload.deliver: true, wird die Ausgabe an einen Channel zugestellt; andernfalls bleibt sie intern.
Verwende Isolated Jobs für laute, häufige oder “Hintergrund-Aufgaben”, die deine Main-Chat-Historie nicht zuspammen sollen.
Payload Shapes (was läuft)
Zwei Payload-Arten werden unterstützt:
systemEvent: Nur Main-Session, geroutet durch den Heartbeat Prompt.agentTurn: Nur Isolated-Session, führt eine dedizierte Agent-Ausführung aus.
Häufige agentTurn Felder:
message: Erforderlicher Text-Prompt.model/thinking: Optionale Overrides (siehe unten).timeoutSeconds: Optionaler Timeout-Override.deliver:trueum Ausgabe an ein Channel-Ziel zu senden.channel:lastoder ein spezifischer Channel.to: Channel-spezifisches Ziel (Telefon/Chat/Channel-ID).bestEffortDeliver: Verhindert Fehlschlagen des Jobs, wenn Zustellung fehlschlägt.
Isolation-Optionen (nur für session=isolated):
postToMainPrefix(CLI:--post-prefix): Präfix für das System-Event in Main.postToMainMode:summary(Standard) oderfull.postToMainMaxChars: Max. Zeichen wennpostToMainMode=full(Standard 8000).
Model und Thinking Overrides
Isolated Jobs (agentTurn) können das 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 gemeinsame Main-Session-Modell. Wir empfehlen Modell-Overrides nur für Isolated Jobs, um unerwartete Context-Wechsel zu vermeiden.
Auflösungspriorität:
- Job Payload Override (höchste)
- Hook-spezifische Defaults (z.B.
hooks.gmail.model) - Agent Config Default
Delivery (Channel + Target)
Isolated Jobs können Ausgabe an einen Channel zustellen. Die Job Payload kann angeben:
channel:whatsapp/telegram/discord/slack/mattermost(Plugin) /signal/imessage/lastto: Channel-spezifisches Empfängerziel
Wenn channel oder to weggelassen wird, kann Cron auf die “Last Route” der Main Session zurückfallen (der letzte Ort, an dem der Agent geantwortet hat).
Delivery-Hinweise:
- Wenn
togesetzt ist, stellt Cron automatisch die finale Ausgabe des Agent zu, auch wenndeliverweggelassen wird. - Verwende
deliver: true, wenn du Last-Route-Zustellung ohne explizitestowillst. - Verwende
deliver: false, um Ausgabe intern zu halten, auch wenn eintovorhanden ist.
Target-Format-Erinnerungen:
- Slack/Discord/Mattermost (Plugin) Targets sollten explizite Präfixe verwenden (z.B.
channel:<id>,user:<id>), um Mehrdeutigkeit zu vermeiden. - Telegram Topics sollten die
:topic:-Form verwenden (siehe unten).
Telegram Delivery Targets (Topics / Forum Threads)
Telegram unterstützt Forum-Topics via 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
Verwende diese Strukturen beim direkten Aufrufen von Gateway cron.* Tools (Agent Tool Calls oder RPC).
CLI-Flags akzeptieren menschenlesbare Dauern wie 20m, aber Tool Calls verwenden Epoch-Millisekunden für atMs und everyMs (ISO-Zeitstempel werden für at-Zeiten akzeptiert).
cron.add params
Einmalig, Main Session Job (System Event):
{
"name": "Reminder",
"schedule": { "kind": "at", "atMs": 1738262400000 },
"sessionTarget": "main",
"wakeMode": "now",
"payload": { "kind": "systemEvent", "text": "Reminder text" },
"deleteAfterRun": true
}
Wiederkehrend, Isolated 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.",
"deliver": true,
"channel": "slack",
"to": "channel:C1234567890",
"bestEffortDeliver": true
},
"isolation": { "postToMainPrefix": "Cron", "postToMainMode": "summary" }
}
Hinweise:
schedule.kind:at(atMs),every(everyMs), odercron(expr, optionaltz).atMsundeveryMssind Epoch-Millisekunden.sessionTargetmuss"main"oder"isolated"sein und muss zupayload.kindpassen.- Optionale Felder:
agentId,description,enabled,deleteAfterRun,isolation. wakeModeist standardmäßig"next-heartbeat", wenn weggelassen.
cron.update params
{
"jobId": "job-123",
"patch": {
"enabled": false,
"schedule": { "kind": "every", "everyMs": 3600000 }
}
}
Hinweise:
jobIdist kanonisch;idwird aus Kompatibilitätsgründen akzeptiert.- Verwende
agentId: nullim Patch, um ein Agent Binding zu löschen.
cron.run und cron.remove params
{ "jobId": "job-123", "mode": "force" }
{ "jobId": "job-123" }
Storage & History
- Job Store:
~/.openclaw/cron/jobs.json(Gateway-verwaltetes JSON). - Run History:
~/.openclaw/cron/runs/<jobId>.jsonl(JSONL, automatisch bereinigt). - Store-Pfad überschreiben:
cron.storein der Config.
Konfiguration
{
cron: {
enabled: true, // Standard true
store: "~/.openclaw/cron/jobs.json",
maxConcurrentRuns: 1, // Standard 1
},
}
Cron komplett deaktivieren:
cron.enabled: false(Config)OPENCLAW_SKIP_CRON=1(Umgebungsvariable)
CLI Schnellstart
Einmalige Erinnerung (UTC ISO, automatisches 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
Einmalige Erinnerung (Main Session, sofort aufwecken):
openclaw cron add \
--name "Calendar check" \
--at "20m" \
--session main \
--system-event "Next heartbeat: check calendar." \
--wake now
Wiederkehrender Isolated Job (Zustellung an WhatsApp):
openclaw cron add \
--name "Morning status" \
--cron "0 7 * * *" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Summarize inbox + calendar for today." \
--deliver \
--channel whatsapp \
--to "+15551234567"
Wiederkehrender Isolated 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." \
--deliver \
--channel telegram \
--to "-1001234567890:topic:123"
Isolated Job mit Model 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 \
--deliver \
--channel whatsapp \
--to "+15551234567"
Agent-Auswahl (Multi-Agent-Setups):
# Job an Agent "ops" binden (fällt auf Default zurück, wenn dieser Agent fehlt)
openclaw cron add --name "Ops sweep" --cron "0 6 * * *" --session isolated --message "Check ops queue" --agent ops
# Agent bei einem bestehenden Job wechseln oder löschen
openclaw cron edit <jobId> --agent ops
openclaw cron edit <jobId> --clear-agent
Manueller Lauf (Debug):
openclaw cron run <jobId> --force
Bestehenden Job bearbeiten (Felder patchen):
openclaw cron edit <jobId> \
--message "Updated prompt" \
--model "opus" \
--thinking low
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 Surface
cron.list,cron.status,cron.add,cron.update,cron.removecron.run(force oder due),cron.runsFür sofortige System-Events ohne Job verwendeopenclaw system event.
Troubleshooting
”Nichts läuft”
- Prüfe ob Cron aktiviert ist:
cron.enabledundOPENCLAW_SKIP_CRON. - Prüfe ob das Gateway kontinuierlich läuft (Cron läuft im Gateway-Prozess).
- Für
cronSchedules: Bestätige die Zeitzone (--tz) vs. die Host-Zeitzone.
Telegram liefert an den falschen Ort
- Für Forum-Topics verwende
-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.