Technical reference for the OpenClaw framework. Real-time synchronization with the official documentation engine.
Use this file to discover all available pages before exploring further.
Scheduled tasks
Cron is the Gateway's built-in scheduler. It persists jobs, wakes the agent at the right time, and can deliver output back to a chat channel or webhook endpoint.
Quick start
Add a one-shot reminder
```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
```
Check your jobs
```bash}
openclaw cron list
openclaw cron show
```
See run history
```bash}
openclaw cron runs --id
```
How cron works
Cron runs inside the Gateway process (not inside the model).
Job definitions persist at
text
~/.openclaw/cron/jobs.json
so restarts do not lose schedules.
Runtime execution state persists next to it in
text
~/.openclaw/cron/jobs-state.json
. If you track cron definitions in git, track
text
jobs.json
and gitignore
text
jobs-state.json
.
After the split, older OpenClaw versions can read
text
jobs.json
but may treat jobs as fresh because runtime fields now live in
text
jobs-state.json
.
When
text
jobs.json
is edited while the Gateway is running or stopped, OpenClaw compares the changed schedule fields with pending runtime slot metadata and clears stale
text
nextRunAtMs
values. Pure formatting or key-order-only rewrites preserve the pending slot.
On Gateway startup, overdue isolated agent-turn jobs are rescheduled out of the channel-connect window instead of replaying immediately, so Discord/Telegram startup and native-command setup stay responsive after restarts.
One-shot jobs (
text
--at
) auto-delete after success by default.
Isolated cron runs best-effort close tracked browser tabs/processes for their
text
cron:<jobId>
session when the run completes, so detached browser automation does not leave orphaned processes behind.
Isolated cron runs also guard against stale acknowledgement replies. If the first result is just an interim status update (
text
on it
,
text
pulling everything together
, and similar hints) and no descendant subagent run is still responsible for the final answer, OpenClaw re-prompts once for the actual result before delivery.
Isolated cron runs prefer structured execution-denial metadata from the embedded run, then fall back to known final summary/output markers such as
text
SYSTEM_RUN_DENIED
and
text
INVALID_REQUEST
, so a blocked command is not reported as a green run.
Isolated cron runs also treat run-level agent failures as job errors even when no reply payload is produced, so model/provider failures increment error counters and trigger failure notifications instead of clearing the job as successful.
When an isolated agent-turn job reaches
text
timeoutSeconds
, cron aborts the underlying agent run and gives it a short cleanup window. If the run does not drain, Gateway-owned cleanup force-clears that run's session ownership before cron records the timeout, so queued chat work is not left behind a stale processing session.
note
Task reconciliation for cron is runtime-owned first, durable-history-backed second: an active cron task stays live while the cron runtime still tracks that job as running, even if an old child session row still exists. Once the runtime stops owning the job and the 5-minute grace window expires, maintenance checks persisted run logs and job state for the matching `cron::` run. If that durable history shows a terminal result, the task ledger is finalized from it; otherwise Gateway-owned maintenance can mark the task `lost`. Offline CLI audit can recover from durable history, but it does not treat its own empty in-process active-job set as proof that a Gateway-owned cron run is gone.
Schedule types
Kind
CLI flag
Description
text
at
text
--at
One-shot timestamp (ISO 8601 or relative like
text
20m
)
text
every
text
--every
Fixed interval
text
cron
text
--cron
5-field or 6-field cron expression with optional
text
--tz
Timestamps without a timezone are treated as UTC. Add
text
--tz America/New_York
for local wall-clock scheduling.
Recurring top-of-hour expressions are automatically staggered by up to 5 minutes to reduce load spikes. Use
text
--exact
to force precise timing or
text
--stagger 30s
for an explicit window.
Day-of-month and day-of-week use OR logic
Cron expressions are parsed by croner. When both the day-of-month and day-of-week fields are non-wildcard, croner matches when either field matches — not both. This is standard Vixie cron behavior.
text
# Intended: "9 AM on the 15th, only if it's a Monday"
# Actual: "9 AM on every 15th, AND 9 AM on every Monday"
0 9 15 * 1
This fires ~5–6 times per month instead of 0–1 times per month. OpenClaw uses Croner's default OR behavior here. To require both conditions, use Croner's
text
+
day-of-week modifier (
text
0 9 15 * +1
) or schedule on one field and guard the other in your job's prompt or command.
Execution styles
Style
text
--session
value
Runs in
Best for
Main session
text
main
Next heartbeat turn
Reminders, system events
Isolated
text
isolated
Dedicated
text
cron:<jobId>
Reports, background chores
Current session
text
current
Bound at creation time
Context-aware recurring work
Custom session
text
session:custom-id
Persistent named session
Workflows that build on history
Payload options for isolated jobs
Prompt text (required for isolated).
Model override; uses the selected allowed model for the job.
Thinking level override.
Skip workspace bootstrap file injection.
Restrict which tools the job can use, for example `--tools exec,read`.
text
--model
uses the selected allowed model as that job's primary model. It is not the same as a chat-session
text
/model
override: configured fallback chains still apply when the job primary fails. If the requested model is not allowed or cannot be resolved, cron fails the run with an explicit validation error instead of silently falling back to the job's agent/default model selection.
Cron jobs can also carry payload-level
text
fallbacks
. When present, that list replaces the configured fallback chain for the job. Use
text
fallbacks: []
in the job payload/API when you want a strict cron run that tries only the selected model. If a job has
text
--model
but neither payload nor configured fallbacks, OpenClaw passes an explicit empty fallback override so the agent primary is not appended as a hidden extra retry target.
Model-selection precedence for isolated jobs is:
Gmail hook model override (when the run came from Gmail and that override is allowed)
Per-job payload
text
model
User-selected stored cron session model override
Agent/default model selection
Fast mode follows the resolved live selection too. If the selected model config has
text
params.fastMode
, isolated cron uses that by default. A stored session
text
fastMode
override still wins over config in either direction.
If an isolated run hits a live model-switch handoff, cron retries with the switched provider/model and persists that live selection for the active run before retrying. When the switch also carries a new auth profile, cron persists that auth profile override for the active run too. Retries are bounded: after the initial attempt plus 2 switch retries, cron aborts instead of looping forever.
Before an isolated cron run enters the agent runner, OpenClaw checks reachable local provider endpoints for configured
text
api: "ollama"
and
text
api: "openai-completions"
providers whose
text
baseUrl
is loopback, private-network, or
text
.local
. If that endpoint is down, the run is recorded as
text
skipped
with a clear provider/model error instead of starting a model call. The endpoint result is cached for 5 minutes, so many due jobs using the same dead local Ollama, vLLM, SGLang, or LM Studio server share one small probe instead of creating a request storm. Skipped provider-preflight runs do not increment execution-error backoff; enable
text
failureAlert.includeSkipped
when you want repeated skip notifications.
Delivery and output
Mode
What happens
text
announce
Fallback-deliver final text to the target if the agent did not send
for channel delivery. For Telegram forum topics, use
text
-1001234567890:topic:123
; direct RPC/config callers may also pass
text
delivery.threadId
as a string or number. Slack/Discord/Mattermost targets should use explicit prefixes (
text
channel:<id>
,
text
user:<id>
). Matrix room IDs are case-sensitive; use the exact room ID or
text
room:!room:server
form from Matrix.
For isolated jobs, chat delivery is shared. If a chat route is available, the agent can use the
text
message
tool even when the job uses
text
--no-deliver
. If the agent sends to the configured/current target, OpenClaw skips the fallback announce. Otherwise
text
announce
,
text
webhook
, and
text
none
only control what the runner does with the final reply after the agent turn.
When an agent creates an isolated reminder from an active chat, OpenClaw stores the preserved live delivery target for the fallback announce route. Internal session keys may be lowercase; provider delivery targets are not reconstructed from those keys when current chat context is available.
Failure notifications follow a separate destination path:
text
cron.failureDestination
sets a global default for failure notifications.
text
job.delivery.failureDestination
overrides that per job.
If neither is set and the job already delivers via
text
announce
, failure notifications now fall back to that primary announce target.
text
delivery.failureDestination
is only supported on
text
sessionTarget="isolated"
jobs unless the primary delivery mode is
text
webhook
.
text
failureAlert.includeSkipped: true
opts a job or global cron alert policy into repeated skipped-run alerts. Skipped runs keep a separate consecutive skip counter, so they do not affect execution-error backoff.
# List all jobs
openclaw cron list
# Show one job, including resolved delivery route
openclaw cron show <jobId>
# Edit a job
openclaw cron edit <jobId> --message "Updated prompt" --model "opus"
# Force run a job now
openclaw cron run <jobId>
# Run only if due
openclaw cron run <jobId> --due
# View run history
openclaw cron runs --id <jobId> --limit 50
# Delete a job
openclaw cron remove <jobId>
# Agent selection (multi-agent setups)
openclaw cron add --name "Ops sweep" --cron "0 6 * * *" --session isolated --message "Check ops queue" --agent ops
openclaw cron edit <jobId> --clear-agent
note
Model override note:
text
openclaw cron add|edit --model ...
changes the job's selected model.
If the model is allowed, that exact provider/model reaches the isolated agent run.
If it is not allowed or cannot be resolved, cron fails the run with an explicit validation error.
Configured fallback chains still apply because cron
text
--model
is a job primary, not a session
text
/model
override.
Payload
text
fallbacks
replaces configured fallbacks for that job;
text
fallbacks: []
disables fallback and makes the run strict.
A plain
text
--model
with no explicit or configured fallback list does not fall through to the agent primary as a silent extra retry target.
limits both scheduled cron dispatch and isolated agent-turn execution. Isolated cron agent turns use the queue's dedicated
text
cron-nested
execution lane internally, so raising this value lets independent cron LLM runs progress in parallel instead of only starting their outer cron wrappers. The shared non-cron
text
nested
lane is not widened by this setting.
The runtime state sidecar is derived from
text
cron.store
: a
text
.json
store such as
text
~/clawd/cron/jobs.json
uses
text
~/clawd/cron/jobs-state.json
, while a store path without a
text
.json
suffix appends
text
-state.json
.
If you hand-edit
text
jobs.json
, leave
text
jobs-state.json
out of source control. OpenClaw uses that sidecar for pending slots, active markers, last-run metadata, and the schedule identity that tells the scheduler when an externally edited job needs a fresh
text
nextRunAtMs
.
Disable cron:
text
cron.enabled: false
or
text
OPENCLAW_SKIP_CRON=1
.
Troubleshooting
Command ladder
bash
openclaw status
openclaw gateway status
openclaw cron status
openclaw cron list
openclaw cron runs --id <jobId> --limit 20
openclaw system heartbeat last
openclaw logs --follow
openclaw doctor