On this page

On this page

Automation

Manage automations

Day-to-day operation of stored jobs: copy-ready CLI examples, the management commands, run history semantics, and the cron.* configuration keys. Part of the Automations guide.

Run links from automation messages and notifications open the exact recorded run, even when newer runs fill the first history page. Choose Show all runs to return to that automation's full history. Links with a reused session or start-time identity do not select an ambiguous run.

CLI examples

One-shot reminder

bash
openclaw automations add \  --name "Calendar check" \  --at "20m" \  --session main \  --system-event "Check the calendar for upcoming events." \  --wake now

Recurring isolated job

bash
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

bash
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

bash
openclaw automations create "0 18 * * 1-5" \  "Summarize today's deploys as JSON." \  --name "Deploy digest" \  --webhook "https://example.invalid/openclaw/cron"

Command output

bash
openclaw automations create "*/15 * * * *" \  --name "Queue depth check" \  --command "scripts/check-queue.sh" \  --command-cwd "/srv/app" \  --announce \  --channel telegram \  --to "-1001234567890"

Managing jobs

In the Control UI, an open automation refreshes its next-run time and condition activity when scheduler events arrive. These runtime updates preserve unsaved settings and the saved definition used for conflict detection, including when the selected automation is outside the current list page or filter.

Conversational management

An authenticated channel sender explicitly listed in commands.ownerAllowFrom, or a Control UI administrator with operator.admin, can ask the agent to list, inspect, update, run, or remove any existing automation on that Gateway, regardless of its creator or channel. For example, ask it to disable a reminder created in Telegram. This matches the administrator's authority on the Automations page. Create command payloads through the operator CLI or Gateway API.

When tools.gatewayPolicy.automations.scope is "caller", model turns keep ordinary caller scope even for administrators and configured channel owners. allowCommandJobs: false additionally blocks model changes to and runs of command jobs. Direct human administration remains available. See Gateway tool policy.

Fresh authenticated Control UI administrator turns can also create ordinary automations through chat, including recurring agent turns in the current conversation with timeoutSeconds: 0. Creation keeps the caller's account/session ownership and captured tool restrictions. Remote administration does not grant local-host or provider-read authority, or permission to capture fresh configured-MCP execution authority. An incomplete tool capture still prevents inheriting an uncaptured tool surface.

The Gateway grants this authority from the authenticated turn's admission facts. Each operation uses a one-use grant that expires after 60 seconds and remains bound to that exact active run. Channel owner membership is rechecked against the current global owner list when the capability is used and immediately before a mutation commits. Channel allowlists, wildcard entries, display names, account IDs, and session routes do not establish ownership. Other channel turns and Control UI turns without operator.admin receive no management grant. If access is denied or a grant expires, retry from a fresh authenticated configured channel owner or Control UI administrator turn, or use the Automations page.

When an admitted owner or administrator turn uses sessions_yield to wait for its subagents, the verified requester continuation retains automation management for that task. It receives fresh grants for its new run; the original run's grants expire normally. The continuation remains management-only; it cannot capture new creator execution authority. Removing the channel sender from the global owner list, cancellation, session reset or archive, a new direct user turn, and Gateway restart invalidate the handoff. Ordinary inter-session messages and child results do not grant management access.

Each admin management request records its method, run, operational instance, and success or failure in the Gateway's cron: admin management log, alongside the ordinary tool audit record. Management authority does not transfer creator attribution or replace the job's scheduled execution policy.

CLI management

For older automations missing creator account metadata, run openclaw doctor --fix. Doctor reconciles the account only when the stored creator identity proves it, and reports the repair. The matching creator session can then update an agent prompt without supplying a new tool cap. Existing tool permissions and creator attribution stay intact; capless jobs retain their legacy execution policy. An explicit permission edit still requires matching owner authority. Jobs whose stored identity cannot prove an account need authenticated administrator recovery; Doctor does not infer ownership from delivery settings or the current caller.

Automations created before owner attribution have no recorded owner. Chat can still enable, disable, reschedule or remove them, but only a Gateway owner or an operator can change their prompt or tools.

bash
# List enabled jobsopenclaw automations list # Include disabled jobsopenclaw automations list --all # Get one stored job as JSONopenclaw automations get <jobId> # Show one job, including resolved delivery routeopenclaw automations show <jobId> # Enable/disable without deletingopenclaw automations enable <jobId>openclaw automations disable <jobId> # Edit a jobopenclaw automations edit <jobId> --message "Updated prompt" --model "opus" # Force run a job nowopenclaw automations run <jobId> # Force run a job now and wait for its terminal statusopenclaw automations run <jobId> --wait --wait-timeout 10m --poll-interval 2s # Run only if dueopenclaw automations run <jobId> --due # View run historyopenclaw automations runs <jobId> --limit 50 # View one exact runopenclaw automations runs <jobId> --run-id <runId> # Delete a jobopenclaw automations remove <jobId> # Agent selection (multi-agent setups)openclaw automations create "0 6 * * *" "Check ops queue" --name "Ops sweep" --session isolated --agent opsopenclaw automations edit <jobId> --clear-agent

Archiving a session (Control UI, or sessions.patch { key, archived: true, expectedSessionId } using the durable ID from sessions.list) disables every enabled automation job bound to that session: its isolated cron:<jobId> session, a session:<key> target, or a delivery/wake sessionKey lane. Restoring the session requires the same observed identity and does not re-enable those jobs; use openclaw automations enable <jobId>. Sessions with an enabled bound job show a clock badge in the Control UI sidebar.

openclaw automations run <jobId> returns after enqueueing the manual run. Use --wait for shutdown hooks, maintenance scripts, or other automation that must block until the queued run finishes; 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 in the Gateway instead: it returns the finished run (status, error, delivery status, and summary) when the run ends within the call's timeoutMs (default 60 seconds, capped at 10 minutes). A longer run returns its runId; read it later with the runs action and that runId. Main-session jobs, and jobs that run in the calling session, return at once because they start only after the calling turn ends.

Run-now delivery measures lateness from when the manual request was accepted. An old pending scheduled slot does not make its fresh output stale; automatic and --due runs keep the original scheduled time for that check. A manual run still preserves the job's recurring cadence or future one-shot occurrence.

Running a paused future one-shot leaves it paused and keeps its saved occurrence. Re-enable it when automatic execution is wanted. If a manual run was accepted before the scheduled time but waited past it in the command queue, that occurrence remains available after re-enabling or restarting the Gateway.

Run history keeps payload execution in status (ok, error, or skipped) and whole-run completion in completionStatus (succeeded, failed, or unknown). Requested delivery is required unless the admitted job explicitly sets delivery.bestEffort: true; delivery-only failure leaves execution status: "ok", does not increment execution error counters or enter retry backoff, and records completionStatus: "failed". An adapter send without a delivery identity stays unknown, without an automatic resend that could duplicate the message.

Once a successful one-shot consumes its scheduled occurrence, its finished event and run history omit nextRunAtMs, including when the job auto-deletes. An early manual run that preserves a future occurrence still reports that occurrence.

Control UI run history shows OK · Error or OK · Unknown when execution succeeded but whole-run completion failed or remains unknown. Its status filter still selects the execution status.

Run-history search matches summaries, task names, and execution or delivery errors. You can search the delivery error shown on a run even when its execution status is ok.

Run history shows a loading indicator while the selected history is unavailable. A failed request shows an error and a Retry button; previously loaded runs for the same selection remain visible. Empty-history guidance appears only after a successful request confirms there are no runs for the current selection and filters.

After a temporary Gateway reconnect, Automations reopens the current selected job and run using fresh job data. Closing the panel or choosing another automation replaces that selection; reconnect does not replay a superseded link. Show all runs clears the linked-run selection across reconnects. Changing the Gateway identity or agent scope clears the selection.

Choose View transcript on a run to read that run’s recorded conversation, including earlier pages. Transcript selection stays bound to the recorded run when the scheduler reuses its session alias. Gateway clients use cron.history with a job id and an exact runId or runAtMs; the response contains messages, optional activity, and an opaque nextCursor. Missing or ambiguous run records remain unavailable rather than opening a different run. The selected run identifies its recorded conversation generation: isolated runs have a fresh generation, while custom sessions retain their shared conversation history across runs. Current job and session permissions apply to every page. Unavailable or inaccessible transcripts return a generic error without disclosing the selected session key.

Intentional silence (NO_REPLY), heartbeat acknowledgments, and channel reply transforms record deliverySuppressionReason without claiming delivery or triggering delivery-failure alerts. These successful non-outcomes and successful executions with explicit delivery.bestEffort: true delete one-shots normally. An empty model final is not intentional silence; exhausted recovery records a failed run rather than a synthetic successful NO_REPLY. A transport hook veto instead records a delivery error without an intentional-suppression reason. Active descendants without a final reply, stale interim output, and output emptied by TTS instead record a delivery error. Retained one-shot jobs do not automatically rerun; inspect their history and delivery outcome before retrying or removing them.

Direct Gateway event sources can use cron.run with mode: "if-enabled" to run immediately without overriding an operator-disabled or auto-disabled job. Explicit operator run-now commands continue to use force.

Re-enabling an auto-disabled job or an exhausted stream resets its failure counters. API clients reconciling a declarationKey can do the same with explicit enabled: true; routine declarations that omit enablement preserve stopped jobs, and routine reconciliation preserves existing failure streaks.

The agent automations tool returns compact job summaries (id, name, enabled, effectiveAgentId, nextRunAt, nextRunAtMs, scheduleKind, lastRunAt, lastRunStatus) from automations(action: "list"). effectiveAgentId identifies the resolved execution owner, or is null when ownership is unresolved. Run dates are exact ISO timestamps, or null when absent; the millisecond fields remain available for programmatic callers. Time-based jobs also include their exact schedule (at, every, or cron), including disabled jobs with no next run. Event-driven schedules, payloads, and delivery definitions remain omitted; use automations(action: "get", jobId: "...") for one full job definition. Direct Gateway callers can pass compact: true to cron.list; omitting it preserves the full response with delivery previews. cron.add includes the same dry-run preview on the created job so create-time output names a resolved route or a reason delivery was rejected.

openclaw automations create is an alias for openclaw automations add. New jobs can use a positional schedule ("0 9 * * 1", "every 1h", "20m", or an ISO timestamp) followed by a positional agent prompt. Use --webhook <url> on automations add|create or automations edit to POST the finished run payload to an HTTP endpoint; webhook delivery cannot combine 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 individually (each rejected alongside its matching set flag) — distinct from --no-deliver, which only disables runner fallback delivery.

The webhook URL remains subject to the strict outbound policy; configure cron.webhookSsrfPolicy for an intentional local or private receiver.

Clearing Timeout (seconds) in the Control UI and saving removes the saved override, restoring the default runtime budget. For API clients, a cron.update payload patch sets a timeout with a number, clears it with timeoutSeconds: null, and preserves the saved value when timeoutSeconds is omitted. New jobs omit the field to use the default; null is only an update instruction.

Configuration

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

webhookToken is sent as Authorization: Bearer <token> on automation webhook POSTs. Webhook URLs must not include embedded username/password credentials; use webhookToken when the receiver supports bearer authentication. webhookSsrfPolicy applies to every outbound automation webhook and is strict when omitted. Prefer narrow allowedHostnames entries over the broad dangerouslyAllowPrivateNetwork opt-in.

Automation jobs, run history, and quarantined malformed jobs live in the shared SQLite state database. Use the CLI or Gateway API to change jobs; cron.store is retired.

Set cron.skipMissedJobs: true to skip recurring (cron and every) slots missed while the Gateway was offline. At startup, those jobs advance to their next future occurrence instead of catching up, avoiding stale reminders and unnecessary model calls at the cost of dropping missed work. The default is false (catch up); one-shot (at) jobs retain their normal catch-up behavior either way.

Disable automatic runs: cron.enabled: false or OPENCLAW_SKIP_CRON=1. These settings do not prevent manual runs.

A caller who can define a host-executed automation can make the Gateway start a process with its host privileges. That process can access credentials readable by the Gateway or alter configuration files writable by it. Direct file writes bypass Gateway API restrictions such as OPENCLAW_CONFIG_READONLY even when local terminals are disabled.

To block this execution path, start the Gateway with OPENCLAW_DISABLE_CRON_HOST_EXECUTION=1 in its launch environment. The Gateway 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 remain available. Existing blocked jobs can still be disabled or removed. Gateway configuration cannot change this control; change the launch environment and restart the Gateway to change it. The control does not govern tools used by agent turns or provide filesystem isolation.

Retry behavior

One-shot retry: transient errors (rate limit, overload, network, timeout, server error) use a built-in retry schedule. Permanent errors disable the job immediately.

Recurring retry: consecutive execution errors back off on an extended schedule (30s, 60s, 5m, 15m, 60m). Backoff resets after the next successful run.

Maintenance

cron.sessionRetention (default 24h, false or "0h" disables) prunes isolated run-session entries. Terminal run history is retained for 7 days (lost rows for 24 hours), with the newest 2000 rows per job and history class enforced as an additional ceiling.

Per-agent run-session retention skips agent databases still undergoing startup preparation while maintaining healthy agents. Completed preparation wakes retention for the newly available database. These sweeps keep the Gateway's maintenance context rather than borrowing the publisher's temporary startup admission. Retention continues even when scheduled execution is disabled.

The seven-day session registry sweep checks descendants only for expired, unprotected run rows. It retains an exact-run parent while 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 defers pruning across healthy stores too and retries every minute: the unavailable store may still contain a live descendant. Once those stores are available and no live descendants remain, the expired parent can be pruned. This preserves the parent communication policy for sessions_send; it does not restore parent rows deleted before this fix.

After each registry sweep, the Gateway waits until the next candidate expiry or a committed cron-session or store-topology change. Empty, unchanged registries do not need periodic reads. Protected expired sessions and failed sweeps retry every minute; run-history recovery keeps its existing minute cadence.

Per-agent session stores also retain their next cron-run expiry, so empty or unexpired stores do not require reads on every 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 continuing maintenance for healthy agents. Pending deletion cleanup remains owned by the agent deletion operation.

Legacy store migration

openclaw doctor --fix imports supported jobs-quarantine.json sidecars into SQLite and archives the originals with a .migrated suffix. Retired jobs.json, jobs-state.json, and runs/*.jsonl inputs remain unchanged: install OpenClaw 2026.9.7, run its Doctor, then upgrade to the latest version. See the retention policy. Malformed SQLite job rows remain recoverable in quarantine while valid jobs keep running.

Was this useful?