Cron jobs (Gateway scheduler)
Cron vs Heartbeat? See Cron vs Heartbeat for guidance on when to use each.Cron is the Gateway’s built-in scheduler. It persists jobs, wakes the agent at the right time, and can optionally deliver output back to a chat. If you want “run this every morning” or “poke the agent in 20 minutes”, cron is the mechanism.
TL;DR
- Cron runs inside the Gateway (not inside the model).
- Jobs persist under
~/.clawdbot/cron/so restarts don’t lose schedules. - Two execution styles:
- Main session: enqueue a system event, then run on the next heartbeat.
- Isolated: run a dedicated agent turn in
cron:<jobId>, optionally deliver output.
- Wakeups are first-class: a job can request “wake now” vs “next heartbeat”.
Beginner-friendly overview
Think of a cron job as: when to run + what to do.-
Choose a schedule
- One-shot reminder →
schedule.kind = "at"(CLI:--at) - Repeating job →
schedule.kind = "every"orschedule.kind = "cron" - If your ISO timestamp omits a timezone, it is treated as UTC.
- One-shot reminder →
-
Choose where it runs
sessionTarget: "main"→ run during the next heartbeat with main context.sessionTarget: "isolated"→ run a dedicated agent turn incron:<jobId>.
-
Choose the payload
- Main session →
payload.kind = "systemEvent" - Isolated session →
payload.kind = "agentTurn"
- Main session →
deleteAfterRun: true removes successful one-shot jobs from the store.
Concepts
Jobs
A cron job is a stored record with:- a schedule (when it should run),
- a payload (what it should do),
- optional delivery (where output should be sent).
- optional agent binding (
agentId): run the job under a specific agent; if missing or unknown, the gateway falls back to the default agent.
jobId (used by CLI/Gateway APIs).
In agent tool calls, jobId is canonical; legacy id is accepted for compatibility.
Jobs can optionally auto-delete after a successful one-shot run via deleteAfterRun: true.
Schedules
Cron supports three schedule kinds:at: one-shot timestamp (ms since epoch). Gateway accepts ISO 8601 and coerces to UTC.every: fixed interval (ms).cron: 5-field cron expression with optional IANA timezone.
croner. If a timezone is omitted, the Gateway host’s
local timezone is used.
Main vs isolated execution
Main session jobs (system events)
Main jobs enqueue a system event and optionally wake the heartbeat runner. They must usepayload.kind = "systemEvent".
wakeMode: "next-heartbeat"(default): event waits for the next scheduled heartbeat.wakeMode: "now": event triggers an immediate heartbeat run.
Isolated jobs (dedicated cron sessions)
Isolated jobs run a dedicated agent turn in sessioncron:<jobId>.
Key behaviors:
- Prompt is prefixed with
[cron:<jobId> <job name>]for traceability. - Each run starts a fresh session id (no prior conversation carry-over).
- A summary is posted to the main session (prefix
Cron, configurable). wakeMode: "now"triggers an immediate heartbeat after posting the summary.- If
payload.deliver: true, output is delivered to a channel; otherwise it stays internal.
Payload shapes (what runs)
Two payload kinds are supported:systemEvent: main-session only, routed through the heartbeat prompt.agentTurn: isolated-session only, runs a dedicated agent turn.
agentTurn fields:
message: required text prompt.model/thinking: optional overrides (see below).timeoutSeconds: optional timeout override.deliver:trueto send output to a channel target.channel:lastor a specific channel.to: channel-specific target (phone/chat/channel id).bestEffortDeliver: avoid failing the job if delivery fails.
session=isolated):
postToMainPrefix(CLI:--post-prefix): prefix for the system event in main.postToMainMode:summary(default) orfull.postToMainMaxChars: max chars whenpostToMainMode=full(default 8000).
Model and thinking overrides
Isolated jobs (agentTurn) can override the model and thinking level:
model: Provider/model string (e.g.,anthropic/claude-sonnet-4-20250514) or alias (e.g.,opus)thinking: Thinking level (off,minimal,low,medium,high,xhigh; GPT-5.2 + Codex models only)
model on main-session jobs too, but it changes the shared main
session model. We recommend model overrides only for isolated jobs to avoid
unexpected context shifts.
Resolution priority:
- Job payload override (highest)
- Hook-specific defaults (e.g.,
hooks.gmail.model) - Agent config default
Delivery (channel + target)
Isolated jobs can deliver output to a channel. The job payload can specify:channel:whatsapp/telegram/discord/slack/mattermost(plugin) /signal/imessage/lastto: channel-specific recipient target
channel or to is omitted, cron can fall back to the main session’s “last route”
(the last place the agent replied).
Delivery notes:
- If
tois set, cron auto-delivers the agent’s final output even ifdeliveris omitted. - Use
deliver: truewhen you want last-route delivery without an explicitto. - Use
deliver: falseto keep output internal even if atois present.
- Slack/Discord/Mattermost (plugin) targets should use explicit prefixes (e.g.
channel:<id>,user:<id>) to avoid ambiguity. - Telegram topics should use the
:topic:form (see below).
Telegram delivery targets (topics / forum threads)
Telegram supports forum topics viamessage_thread_id. For cron delivery, you can encode
the topic/thread into the to field:
-1001234567890(chat id only)-1001234567890:topic:123(preferred: explicit topic marker)-1001234567890:123(shorthand: numeric suffix)
telegram:... / telegram:group:... are also accepted:
telegram:group:-1001234567890:topic:123
Storage & history
- Job store:
~/.clawdbot/cron/jobs.json(Gateway-managed JSON). - Run history:
~/.clawdbot/cron/runs/<jobId>.jsonl(JSONL, auto-pruned). - Override store path:
cron.storein config.
Configuration
cron.enabled: false(config)CLAWDBOT_SKIP_CRON=1(env)
CLI quickstart
One-shot reminder (UTC ISO, auto-delete after success):Gateway API surface
cron.list,cron.status,cron.add,cron.update,cron.removecron.run(force or due),cron.runsFor immediate system events without a job, useclawdbot system event.
Troubleshooting
“Nothing runs”
- Check cron is enabled:
cron.enabledandCLAWDBOT_SKIP_CRON. - Check the Gateway is running continuously (cron runs inside the Gateway process).
- For
cronschedules: confirm timezone (--tz) vs the host timezone.
Telegram delivers to the wrong place
- For forum topics, use
-100…:topic:<id>so it’s explicit and unambiguous. - If you see
telegram:...prefixes in logs or stored “last route” targets, that’s normal; cron delivery accepts them and still parses topic IDs correctly.