Managing Automations: CLI Commands, Run History, and Cron Settings
Covers CLI samples, job management commands, run history behavior, and cron configuration keys for saved jobs. Useful for operators who maintain scheduled automations and need to trace or adjust runs.
Read this when
- Listing, editing, running, or removing a stored job
- Reading run history and completion status
- Setting cron configuration keys on the Gateway
Routine handling of saved jobs: CLI samples you can copy as-is, the management commands, what run history means, and the cron.* configuration keys. This is one part of the Automations guide.
Links in automation messages and notifications open the precise run that was recorded, even if newer runs now fill the first page of history. Pick Show all runs to get back to the automation's complete history. A link whose session or start-time identity is reused will not pick out an ambiguous run.
CLI examples
One-shot reminder
openclaw automations add \
--name "Calendar check" \
--at "20m" \
--session main \
--system-event "Check the calendar for upcoming events." \
--wake now
Recurring isolated job
openclaw automations create "0 7 * * *" \
"Summarize overnight updates." \
--name "Morning brief" \
--tz "America/Los_Angeles" \
--session isolated \
--announce \
--channel slack \
--to "channel:C1234567890"
Model and thinking override
openclaw automations 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
Webhook output
openclaw automations create "0 18 * * 1-5" \
"Summarize today's deploys as JSON." \
--name "Deploy digest" \
--webhook "https://example.invalid/openclaw/cron"
Command output
openclaw automations create "*/15 * * * *" \
--name "Queue depth check" \
--command "scripts/check-queue.sh" \
--command-cwd "/srv/app" \
--announce \
--channel telegram \
--to "-1001234567890"
Managing jobs
Inside the Control UI, an automation that is open updates its next-run time and condition activity as scheduler events come in. Unsaved settings survive these runtime updates, and so does the saved definition used for conflict detection, even when the selected automation falls outside the current list page or filter.
Conversational management
Any authenticated channel sender named explicitly in commands.ownerAllowFrom, or a Control UI administrator holding operator.admin, may instruct the agent to list, inspect, update, run, or remove any automation that already exists on that Gateway, no matter who created it or which channel it came from. Asking it to disable a reminder that was made in Telegram is one example. This is the same authority an administrator has on the Automations page. Build create command payloads through the operator CLI or the Gateway API.
When tools.gatewayPolicy.automations.scope is "caller", model turns retain ordinary caller scope, administrators and configured channel owners included. On top of that, allowCommandJobs: false blocks model changes to command jobs and model-triggered runs of them. Direct human administration is unaffected. See Gateway tool policy.
New authenticated Control UI administrator turns may also create ordinary automations through chat, including recurring agent turns in the current conversation with timeoutSeconds: 0. Such creation keeps the caller's account/session ownership and the tool restrictions captured at the time. Remote administration grants no local-host or provider-read authority, and no permission to capture fresh configured-MCP execution authority. If the tool capture is incomplete, an uncaptured tool surface still cannot be inherited.
The Gateway derives this authority from the admission facts of the authenticated turn. Every operation consumes a single-use grant that expires after 60 seconds and stays tied to that exact active run. Channel owner membership is checked again against the current global owner list when the capability is used, and once more right before a mutation commits. Ownership is not established by channel allowlists, wildcard entries, display names, account IDs, or session routes. Other channel turns, and Control UI turns lacking operator.admin, get no management grant. Should access be denied or a grant expire, retry from a fresh authenticated configured channel owner or Control UI administrator turn, or fall back to the Automations page.
When an admitted owner or administrator turn uses sessions_yield to wait on its subagents, automation management is carried over to the verified requester continuation for that task. Fresh grants are issued for its new run, while the original run's grants expire as usual. That continuation stays management-only and cannot capture new creator execution authority. The handoff is invalidated by removing the channel sender from the global owner list, by cancellation, by session reset or archive, by a new direct user turn, or by a Gateway restart. Management access is not granted by ordinary inter-session messages or child results.
The Gateway's cron: admin management log records the method, run, operational instance, and outcome (success or failure) of each admin management request, next to the standard tool audit record. Management authority neither transfers creator attribution nor replaces the job's scheduled execution policy.
CLI management
For older automations that lack creator account metadata, run openclaw doctor --fix. Doctor reconciles the account only when the stored creator identity proves it, and it reports the repair. After that, the matching creator session can update an agent prompt without supplying a new tool cap. Existing tool permissions and creator attribution are left intact, and capless jobs keep their legacy execution policy. An explicit permission edit still calls for matching owner authority. Jobs whose stored identity cannot prove an account require authenticated administrator recovery; Doctor never infers ownership from delivery settings or from the current caller.
Automations created before owner attribution existed have no recorded owner. Chat can still enable, disable, reschedule, or remove them, yet changing their prompt or tools is limited to a Gateway owner or an operator.
# List enabled jobs
openclaw automations list
# Include disabled jobs
openclaw automations list --all
# Get one stored job as JSON
openclaw automations get <jobId>
# Show one job, including resolved delivery route
openclaw automations show <jobId>
# Enable/disable without deleting
openclaw automations enable <jobId>
openclaw automations disable <jobId>
# Edit a job
openclaw automations edit <jobId> --message "Updated prompt" --model "opus"
# Force run a job now
openclaw automations run <jobId>
# Force run a job now and wait for its terminal status
openclaw automations run <jobId> --wait --wait-timeout 10m --poll-interval 2s
# Run only if due
openclaw automations run <jobId> --due
# View run history
openclaw automations runs <jobId> --limit 50
# View one exact run
openclaw automations runs <jobId> --run-id <runId>
# Delete a job
openclaw automations remove <jobId>
# Agent selection (multi-agent setups)
openclaw automations create "0 6 * * *" "Check ops queue" --name "Ops sweep" --session isolated --agent ops
openclaw automations edit <jobId> --clear-agent
Archiving a session (through the Control UI, or via sessions.patch { key, archived: true, expectedSessionId } with the durable ID from sessions.list) disables every enabled automation job bound to it: its isolated cron:<jobId> session, a session:<key> target, or a delivery/wake sessionKey lane. Restoring the session needs the same observed identity and does not turn those jobs back on; use openclaw automations enable <jobId> instead. In the Control UI sidebar, sessions with an enabled bound job carry a clock badge.
openclaw automations run <jobId> returns once the manual run is enqueued. For shutdown hooks, maintenance scripts, or other automation that must block until the queued run completes, use --wait; it polls the returned runId (default timeout 10m, poll interval 2s) and exits 0 only for completionStatus: "succeeded". Failed or unknown completion, and wait timeouts, exit non-zero.
The agent automations tool's run action waits inside the Gateway instead: if the run finishes within the call's timeoutMs (default 60 seconds, capped at 10 minutes), it returns the finished run with status, error, delivery status, and summary. When a run takes longer, its runId comes back; read it later through the runs action using that runId. Main-session jobs, and jobs that run in the calling session, return immediately, since they only start after the calling turn ends.
Run-now delivery counts lateness from the moment the manual request was accepted. An old pending scheduled slot does not make the fresh output stale; for that check, automatic runs and --due runs keep the original scheduled time. A manual run also preserves the job's recurring cadence or its future one-shot occurrence.
A paused future one-shot stays paused after a manual run and keeps its saved occurrence. Re-enable it when you want automatic execution. If a manual run was accepted before the scheduled time but sat in the command queue past it, that occurrence is still available after you re-enable or restart the Gateway.
Run history tracks payload execution in status (ok, error, or skipped) and whole-run completion in completionStatus (succeeded, failed, or unknown). Requested delivery is mandatory unless the admitted job explicitly sets delivery.bestEffort: true; a delivery-only failure leaves execution status: "ok", does not raise execution error counters or trigger retry backoff, and records completionStatus: "failed". An adapter send that has no delivery identity stays unknown, with no automatic resend that could duplicate the message.
Once a successful one-shot uses up its scheduled occurrence, nextRunAtMs is omitted from its finished event and run history, including when the job auto-deletes. An early manual run that preserves a future occurrence still reports that occurrence.
Control UI run history displays OK · Error or OK · Unknown when execution succeeded but whole-run completion failed or is still unknown. Its status filter continues to select on execution status.
Run-history search matches summaries, task names, and execution or delivery errors. A run's delivery error can be found even when its execution status is ok.
While the selected history is unavailable, run history shows a loading indicator. A failed request displays an error plus a Retry button, and runs already loaded for the same selection stay visible. Empty-history guidance appears only once a successful request confirms that no runs exist for the current selection and filters.
After a temporary Gateway reconnect, Automations reopens the currently selected job and run with fresh job data. Closing the panel or switching to another automation replaces that selection, and a reconnect does not replay a superseded link. Show all runs clears the linked-run selection across reconnects. Changing the Gateway identity or agent scope also clears the selection.
Select View transcript for a run to read the conversation recorded for it, earlier pages included. Once the scheduler reuses a session alias, transcript selection stays tied to the recorded run. Gateway clients call cron.history with a job id plus an exact runId or runAtMs; the response carries messages, an optional activity, and an opaque nextCursor. Run records that are missing or ambiguous stay unavailable instead of opening some other run. The run you pick reports the generation of its recorded conversation: isolated runs get a fresh generation, whereas custom sessions keep their shared conversation history across runs. Every page is subject to the current job and session permissions. When a transcript is unavailable or inaccessible, a generic error comes back and the selected session key is not disclosed.
Intentional silence (NO_REPLY), heartbeat acknowledgments, and channel reply transforms record deliverySuppressionReason without claiming delivery and without firing delivery-failure alerts. Such successful non-outcomes, along with successful executions carrying an explicit delivery.bestEffort: true, delete one-shots as usual. An empty model final does not count as intentional silence; when recovery is exhausted, the run is recorded as failed rather than as a synthetic successful NO_REPLY. If a transport hook vetoes, a delivery error is recorded instead, with no intentional-suppression reason. A delivery error is also recorded for active descendants that have no final reply, for stale interim output, and for output that TTS emptied. Retained one-shot jobs do not rerun on their own; check their history and delivery outcome before you retry or remove them.
Direct Gateway event sources may pass cron.run with mode: "if-enabled" to run right away, yet this never overrides a job that an operator disabled or that was auto-disabled. Explicit operator run-now commands still go through force.
Failure counters reset when an auto-disabled job or an exhausted stream is re-enabled. API clients that reconcile a declarationKey can achieve the same by passing an explicit enabled: true; routine declarations that leave enablement out keep stopped jobs stopped, and routine reconciliation leaves existing failure streaks intact.
The agent automations tool returns compact job summaries (id, name, enabled, effectiveAgentId, nextRunAt, nextRunAtMs, scheduleKind, lastRunAt, lastRunStatus) from automations(action: "list"). effectiveAgentId names the resolved execution owner, or is null if ownership cannot be resolved. Run dates appear as exact ISO timestamps, or as null when there is none; programmatic callers can still rely on the millisecond fields. Time-based jobs also carry their exact schedule (at, every, or cron), disabled jobs with no next run included. Event-driven schedules, payloads, and delivery definitions are still omitted; for one full job definition, use automations(action: "get", jobId: "..."). Direct Gateway callers may pass compact: true to cron.list; leaving it out keeps the full response with delivery previews. cron.add adds the same dry-run preview to the created job, so create-time output either names a resolved route or gives the reason delivery was rejected.
openclaw automations create is an alias for openclaw automations add. A new job may take a positional schedule ("0 9 * * 1", "every 1h", "20m", or an ISO timestamp) followed by a positional agent prompt. Pass --webhook <url> on automations add|create or automations edit to POST the finished run payload to an HTTP endpoint; webhook delivery cannot be combined with chat delivery flags (--announce, --channel, --to, --thread-id, --account). On automations edit, --clear-channel, --clear-to, --clear-thread-id, and --clear-account, unset those routing fields one at a time (each is rejected alongside its matching set flag). This differs from --no-deliver, which only turns off runner fallback delivery.
The webhook URL is still governed by the strict outbound policy; for an intentional local or private receiver, configure cron.webhookSsrfPolicy.
Clearing the Timeout (seconds) field in the Control UI and saving drops the stored override, which brings back the default runtime budget. On the API side, a cron.update payload patch assigns a timeout by passing a number, removes it with timeoutSeconds: null, and leaves the stored value untouched when timeoutSeconds is absent. New jobs simply omit the field so the default applies; null only serves as an update instruction.
Note
About model overrides:
openclaw automations add|edit --model ...swaps the model the job has selected.- When the model is permitted, that exact provider/model is what the isolated agent run receives.
- When it is not permitted or cannot be resolved, the scheduler fails the run and reports an explicit validation error.
- Through API
cron.updatepayload patches,model: nullcan be set to clear a stored job model override.- From the CLI,
openclaw automations edit <job-id> --clear-modelclears that override (the same result as themodel: nullpatch) and cannot be combined with--model.- Fallback chains you have configured still apply, since the automation
--modelcounts as a job primary rather than a session/modeloverride.openclaw automations add|edit --fallbacks ...assigns payloadfallbacks, which replaces configured fallbacks for that job;--fallbacks ""turns fallback off and makes the run strict.openclaw automations edit <job-id> --clear-fallbacksremoves the per-job override.- A plain
--modelwith no explicit or configured fallback list does not fall through to the agent primary as a silent extra retry target.
Configuration
{
cron: {
enabled: true,
triggers: {
enabled: false,
},
webhookToken: "replace-with-dedicated-webhook-token",
webhookSsrfPolicy: {
allowedHostnames: ["127.0.0.1"], // optional exact exception for a trusted receiver
},
sessionRetention: "24h",
},
}
On automation webhook POSTs, webhookToken travels as Authorization: Bearer <token>.
Webhook URLs must not carry embedded username/password credentials; reach for
webhookToken when the receiver supports bearer authentication.
webhookSsrfPolicy governs every outbound automation webhook and is strict
when omitted. Favor narrow allowedHostnames entries over the broad
dangerouslyAllowPrivateNetwork opt-in.
Automation jobs, run history, and quarantined malformed jobs all reside in the shared SQLite state database. Change jobs through the CLI or Gateway API; cron.store has been retired.
Set cron.skipMissedJobs: true so recurring slots (cron and every) missed while the Gateway was offline are skipped. On startup those jobs jump to their next future occurrence rather than catching up, which avoids stale reminders and needless model calls at the cost of dropping missed work. false is the default (catch up); one-shot (at) jobs keep their usual catch-up behavior in either case.
To turn off automatic runs, use cron.enabled: false or OPENCLAW_SKIP_CRON=1. Neither setting blocks manual runs.
Anyone allowed to define a host-executed automation can cause the Gateway to launch a process with its host privileges. That process may reach credentials the Gateway can read or modify configuration files it can write. Direct file writes sidestep Gateway API restrictions such as OPENCLAW_CONFIG_READONLY, even with local terminals disabled.
To close off this execution path, launch the Gateway with OPENCLAW_DISABLE_CRON_HOST_EXECUTION=1 present in its launch environment. The Gateway then refuses command and script payloads, condition triggers, on-exit schedules, and Gateway-hosted stream sources, including persisted and manually requested jobs. Scheduled agent turns and authorized sandbox-backed stream sources stay available. Jobs already blocked can still be disabled or removed. Gateway configuration cannot alter this control; to change it, edit the launch environment and restart the Gateway. The control does not cover tools used by agent turns and offers no filesystem isolation.
Retry behavior
One-shot retry: transient errors (rate limit, overload, network, timeout, server error) follow a built-in retry schedule. Permanent errors disable the job right away.
Recurring retry: consecutive execution errors back off on an extended schedule (30s, 60m, 5m, 15m, 60m). The backoff resets once a run succeeds.
Maintenance
cron.sessionRetention (default 24h, with false or "0h" disabling it) prunes isolated run-session entries. Terminal run history is kept for 7 days (lost rows for 24 hours), and the newest 2000 rows per job and history class act as an extra ceiling.
Per-agent run-session retention skips agent databases that are still in startup preparation, while healthy agents keep being maintained. When preparation finishes, retention wakes for that newly available database. These sweeps run in the Gateway's maintenance context instead of borrowing the publisher's temporary startup admission. Retention keeps going even when scheduled execution is disabled.
The seven-day session registry sweep looks for descendants only among expired, unprotected run rows. An exact-run parent is retained as long as it has a non-archived descendant, including through archived intermediate sessions or in another agent's store. If a non-deleted agent's store is unavailable or held for recovery, the registry sweep also defers pruning across healthy stores and retries each minute: that unavailable store may still hold a live descendant. Once those stores are available and no live descendants remain, the expired parent may be pruned. This keeps the parent communication policy for sessions_send; it does not bring back parent rows deleted before this fix.
After every registry sweep, the Gateway waits for the next candidate expiry or a committed cron-session or store-topology change. Empty registries that have not changed need no periodic reads. Protected expired sessions and failed sweeps retry each minute; run-history recovery keeps its existing minute cadence.
Per-agent session stores also remember their next cron-run expiry, so empty or unexpired stores need no reads on each maintenance tick. Committed cron-run changes refresh that deadline; busy sessions and failed session-store sweeps retry after five minutes.
Session retention skips agents with pending or completed deletion while maintenance continues for healthy agents. Cleanup for pending deletion stays with the agent deletion operation.
Legacy store migration
openclaw doctor --fix imports supported jobs-quarantine.json sidecars into SQLite and archives the originals under a .migrated suffix. Retired jobs.json, jobs-state.json, and runs/*.jsonl inputs stay unchanged: install OpenClaw 2026.9.7, run its Doctor, then upgrade to the latest version. See the retention policy. Malformed SQLite job rows stay recoverable in quarantine while valid jobs continue to run.