2026-01-06 22:28:32 +00:00
---
summary: "Cron jobs + wakeups for the Gateway scheduler"
read_when:
- Scheduling background jobs or wakeups
- Wiring automation that should run with or alongside heartbeats
2026-01-23 19:00:17 +00:00
- Deciding between heartbeat and cron for scheduled tasks
2026-01-31 16:04:03 -05:00
title: "Cron Jobs"
2026-01-06 22:28:32 +00:00
---
2026-01-31 21:13:13 +09:00
2026-01-06 22:28:32 +00:00
# Cron jobs (Gateway scheduler)
2026-01-23 19:00:17 +00:00
> **Cron vs Heartbeat?** See [Cron vs Heartbeat](/automation/cron-vs-heartbeat) for guidance on when to use each.
2026-01-08 21:39:03 +01:00
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.
2026-01-31 21:13:13 +09:00
If you want _“run this every morning”_ or _“poke the agent in 20 minutes”_ ,
2026-01-08 21:39:03 +01:00
cron is the mechanism.
2026-02-07 10:28:19 -05:00
Troubleshooting: [/automation/troubleshooting ](/automation/troubleshooting )
2026-01-08 21:39:03 +01:00
## TL;DR
2026-01-31 21:13:13 +09:00
2026-01-08 21:39:03 +01:00
- Cron runs **inside the Gateway** (not inside the model).
2026-01-30 03:15:10 +01:00
- Jobs persist under `~/.openclaw/cron/` so restarts don’ t lose schedules.
2026-01-08 21:39:03 +01:00
- Two execution styles:
- **Main session**: enqueue a system event, then run on the next heartbeat.
2026-03-14 13:48:46 +08:00
- **Isolated**: run a dedicated agent turn in `cron:<jobId>` or a custom session, with delivery (announce by default or none).
- **Current session**: bind to the session where the cron is created (`sessionTarget: "current"` ).
- **Custom session**: run in a persistent named session (`sessionTarget: "session:custom-id"` ).
2026-01-08 21:39:03 +01:00
- Wakeups are first-class: a job can request “wake now” vs “next heartbeat”.
2026-02-16 02:36:00 -08:00
- Webhook posting is per job via `delivery.mode = "webhook"` + `delivery.to = "<url>"` .
- Legacy fallback remains for stored jobs with `notify: true` when `cron.webhook` is set, migrate those jobs to webhook delivery mode.
2026-03-09 20:12:37 +01:00
- For upgrades, `openclaw doctor --fix` can normalize legacy cron store fields before the scheduler touches them.
2026-01-08 21:39:03 +01:00
2026-01-31 09:21:31 -05:00
## Quick start (actionable)
Create a one-shot reminder, verify it exists, and run it immediately:
```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
openclaw cron list
fix: cron scheduler reliability, store hardening, and UX improvements (#10776)
* refactor: update cron job wake mode and run mode handling
- Changed default wake mode from 'next-heartbeat' to 'now' in CronJobEditor and related CLI commands.
- Updated cron-tool tests to reflect changes in run mode, introducing 'due' and 'force' options.
- Enhanced cron-tool logic to handle new run modes and ensure compatibility with existing job structures.
- Added new tests for delivery plan consistency and job execution behavior under various conditions.
- Improved normalization functions to handle wake mode and session target casing.
This refactor aims to streamline cron job configurations and enhance the overall user experience with clearer defaults and improved functionality.
* test: enhance cron job functionality and UI
- Added tests to ensure the isolated agent correctly announces the final payload text when delivering messages via Telegram.
- Implemented a new function to pick the last deliverable payload from a list of delivery payloads.
- Enhanced the cron service to maintain legacy "every" jobs while minute cron jobs recompute schedules.
- Updated the cron store migration tests to verify the addition of anchorMs to legacy every schedules.
- Improved the UI for displaying cron job details, including job state and delivery information, with new styles and layout adjustments.
These changes aim to improve the reliability and user experience of the cron job system.
* test: enhance sessions thinking level handling
- Added tests to verify that the correct thinking levels are applied during session spawning.
- Updated the sessions-spawn-tool to include a new parameter for overriding thinking levels.
- Enhanced the UI to support additional thinking levels, including "xhigh" and "full", and improved the handling of current options in dropdowns.
These changes aim to improve the flexibility and accuracy of thinking level configurations in session management.
* feat: enhance session management and cron job functionality
- Introduced passthrough arguments in the test-parallel script to allow for flexible command-line options.
- Updated session handling to hide cron run alias session keys from the sessions list, improving clarity.
- Enhanced the cron service to accurately record job start times and durations, ensuring better tracking of job execution.
- Added tests to verify the correct behavior of the cron service under various conditions, including zero-delay timers.
These changes aim to improve the usability and reliability of session and cron job management.
* feat: implement job running state checks in cron service
- Added functionality to prevent manual job runs if a job is already in progress, enhancing job management.
- Updated the `isJobDue` function to include checks for running jobs, ensuring accurate scheduling.
- Enhanced the `run` function to return a specific reason when a job is already running.
- Introduced a new test case to verify the behavior of forced manual runs during active job execution.
These changes aim to improve the reliability and clarity of cron job execution and management.
* feat: add session ID and key to CronRunLogEntry model
- Introduced `sessionid` and `sessionkey` properties to the `CronRunLogEntry` struct for enhanced tracking of session-related information.
- Updated the initializer and Codable conformance to accommodate the new properties, ensuring proper serialization and deserialization.
These changes aim to improve the granularity of logging and session management within the cron job system.
* fix: improve session display name resolution
- Updated the `resolveSessionDisplayName` function to ensure that both label and displayName are trimmed and default to an empty string if not present.
- Enhanced the logic to prevent returning the key if it matches the label or displayName, improving clarity in session naming.
These changes aim to enhance the accuracy and usability of session display names in the UI.
* perf: skip cron store persist when idle timer tick produces no changes
recomputeNextRuns now returns a boolean indicating whether any job
state was mutated. The idle path in onTimer only persists when the
return value is true, eliminating unnecessary file writes every 60s
for far-future or idle schedules.
* fix: prep for merge - explicit delivery mode migration, docs + changelog (#10776) (thanks @tyler6204)
2026-02-06 18:03:03 -08:00
openclaw cron run < job-id >
2026-01-31 09:21:31 -05:00
openclaw cron runs --id < job-id >
```
Schedule a recurring isolated job with delivery:
```bash
openclaw cron add \
--name "Morning brief" \
--cron "0 7 * * *" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Summarize overnight updates." \
2026-02-03 13:44:29 -08:00
--announce \
2026-01-31 09:21:31 -05:00
--channel slack \
--to "channel:C1234567890"
```
## Tool-call equivalents (Gateway cron tool)
For the canonical JSON shapes and examples, see [JSON schema for tool calls ](/automation/cron-jobs#json-schema-for-tool-calls ).
## Where cron jobs are stored
Cron jobs are persisted on the Gateway host at `~/.openclaw/cron/jobs.json` by default.
The Gateway loads the file into memory and writes it back on changes, so manual edits
are only safe when the Gateway is stopped. Prefer `openclaw cron add/edit` or the cron
tool call API for changes.
2026-01-13 04:55:39 +00:00
## Beginner-friendly overview
2026-01-31 21:13:13 +09:00
2026-01-13 04:55:39 +00:00
Think of a cron job as: **when** to run + **what** to do.
2026-01-31 21:13:13 +09:00
1. **Choose a schedule**
2026-01-13 04:55:39 +00:00
- One-shot reminder → `schedule.kind = "at"` (CLI: `--at` )
- Repeating job → `schedule.kind = "every"` or `schedule.kind = "cron"`
- If your ISO timestamp omits a timezone, it is treated as **UTC** .
2026-01-31 21:13:13 +09:00
2. **Choose where it runs**
2026-01-13 04:55:39 +00:00
- `sessionTarget: "main"` → run during the next heartbeat with main context.
- `sessionTarget: "isolated"` → run a dedicated agent turn in `cron:<jobId>` .
2026-03-14 13:48:46 +08:00
- `sessionTarget: "current"` → bind to the current session (resolved at creation time to `session:<sessionKey>` ).
- `sessionTarget: "session:custom-id"` → run in a persistent named session that maintains context across runs.
Default behavior (unchanged):
- `systemEvent` payloads default to `main`
- `agentTurn` payloads default to `isolated`
To use current session binding, explicitly set `sessionTarget: "current"` .
2026-01-13 04:55:39 +00:00
2026-01-31 21:13:13 +09:00
3. **Choose the payload**
2026-01-13 04:55:39 +00:00
- Main session → `payload.kind = "systemEvent"`
- Isolated session → `payload.kind = "agentTurn"`
2026-02-03 15:00:03 -08:00
Optional: one-shot jobs (`schedule.kind = "at"` ) delete after success by default. Set
`deleteAfterRun: false` to keep them (they will disable after success).
2026-01-13 04:55:39 +00:00
2026-01-08 21:39:03 +01:00
## Concepts
### Jobs
2026-01-31 21:13:13 +09:00
2026-01-08 21:39:03 +01:00
A cron job is a stored record with:
2026-01-31 21:13:13 +09:00
2026-01-08 21:39:03 +01:00
- a **schedule** (when it should run),
- a **payload** (what it should do),
2026-02-16 02:36:00 -08:00
- optional **delivery mode** (`announce` , `webhook` , or `none` ).
2026-01-12 10:23:45 +00:00
- optional **agent binding** (`agentId` ): run the job under a specific agent; if
missing or unknown, the gateway falls back to the default agent.
2026-01-08 21:39:03 +01:00
Jobs are identified by a stable `jobId` (used by CLI/Gateway APIs).
2026-01-08 21:43:22 +01:00
In agent tool calls, `jobId` is canonical; legacy `id` is accepted for compatibility.
2026-02-03 15:00:03 -08:00
One-shot jobs auto-delete after success by default; set `deleteAfterRun: false` to keep them.
2026-01-08 21:39:03 +01:00
### Schedules
2026-01-31 21:13:13 +09:00
2026-01-06 22:28:32 +00:00
Cron supports three schedule kinds:
2026-01-31 21:13:13 +09:00
2026-02-03 16:53:46 -08:00
- `at` : one-shot timestamp via `schedule.at` (ISO 8601).
2026-01-06 22:28:32 +00:00
- `every` : fixed interval (ms).
2026-02-17 23:46:05 +01:00
- `cron` : 5-field cron expression (or 6-field with seconds) with optional IANA timezone.
2026-01-06 22:28:32 +00:00
2026-01-08 21:39:03 +01:00
Cron expressions use `croner` . If a timezone is omitted, the Gateway host’ s
local timezone is used.
2026-01-06 22:28:32 +00:00
2026-02-17 23:46:05 +01:00
To reduce top-of-hour load spikes across many gateways, OpenClaw applies a
deterministic per-job stagger window of up to 5 minutes for recurring
top-of-hour expressions (for example `0 * * * *` , `0 */2 * * *` ). Fixed-hour
expressions such as `0 7 * * *` remain exact.
For any cron schedule, you can set an explicit stagger window with `schedule.staggerMs`
(`0` keeps exact timing). CLI shortcuts:
- `--stagger 30s` (or `1m` , `5m` ) to set an explicit stagger window.
- `--exact` to force `staggerMs = 0` .
2026-01-08 21:39:03 +01:00
### Main vs isolated execution
2026-01-06 22:28:32 +00:00
2026-01-08 21:39:03 +01:00
#### Main session jobs (system events)
2026-01-31 21:13:13 +09:00
2026-01-06 22:28:32 +00:00
Main jobs enqueue a system event and optionally wake the heartbeat runner.
2026-01-08 21:39:03 +01:00
They must use `payload.kind = "systemEvent"` .
2026-01-06 22:28:32 +00:00
fix: cron scheduler reliability, store hardening, and UX improvements (#10776)
* refactor: update cron job wake mode and run mode handling
- Changed default wake mode from 'next-heartbeat' to 'now' in CronJobEditor and related CLI commands.
- Updated cron-tool tests to reflect changes in run mode, introducing 'due' and 'force' options.
- Enhanced cron-tool logic to handle new run modes and ensure compatibility with existing job structures.
- Added new tests for delivery plan consistency and job execution behavior under various conditions.
- Improved normalization functions to handle wake mode and session target casing.
This refactor aims to streamline cron job configurations and enhance the overall user experience with clearer defaults and improved functionality.
* test: enhance cron job functionality and UI
- Added tests to ensure the isolated agent correctly announces the final payload text when delivering messages via Telegram.
- Implemented a new function to pick the last deliverable payload from a list of delivery payloads.
- Enhanced the cron service to maintain legacy "every" jobs while minute cron jobs recompute schedules.
- Updated the cron store migration tests to verify the addition of anchorMs to legacy every schedules.
- Improved the UI for displaying cron job details, including job state and delivery information, with new styles and layout adjustments.
These changes aim to improve the reliability and user experience of the cron job system.
* test: enhance sessions thinking level handling
- Added tests to verify that the correct thinking levels are applied during session spawning.
- Updated the sessions-spawn-tool to include a new parameter for overriding thinking levels.
- Enhanced the UI to support additional thinking levels, including "xhigh" and "full", and improved the handling of current options in dropdowns.
These changes aim to improve the flexibility and accuracy of thinking level configurations in session management.
* feat: enhance session management and cron job functionality
- Introduced passthrough arguments in the test-parallel script to allow for flexible command-line options.
- Updated session handling to hide cron run alias session keys from the sessions list, improving clarity.
- Enhanced the cron service to accurately record job start times and durations, ensuring better tracking of job execution.
- Added tests to verify the correct behavior of the cron service under various conditions, including zero-delay timers.
These changes aim to improve the usability and reliability of session and cron job management.
* feat: implement job running state checks in cron service
- Added functionality to prevent manual job runs if a job is already in progress, enhancing job management.
- Updated the `isJobDue` function to include checks for running jobs, ensuring accurate scheduling.
- Enhanced the `run` function to return a specific reason when a job is already running.
- Introduced a new test case to verify the behavior of forced manual runs during active job execution.
These changes aim to improve the reliability and clarity of cron job execution and management.
* feat: add session ID and key to CronRunLogEntry model
- Introduced `sessionid` and `sessionkey` properties to the `CronRunLogEntry` struct for enhanced tracking of session-related information.
- Updated the initializer and Codable conformance to accommodate the new properties, ensuring proper serialization and deserialization.
These changes aim to improve the granularity of logging and session management within the cron job system.
* fix: improve session display name resolution
- Updated the `resolveSessionDisplayName` function to ensure that both label and displayName are trimmed and default to an empty string if not present.
- Enhanced the logic to prevent returning the key if it matches the label or displayName, improving clarity in session naming.
These changes aim to enhance the accuracy and usability of session display names in the UI.
* perf: skip cron store persist when idle timer tick produces no changes
recomputeNextRuns now returns a boolean indicating whether any job
state was mutated. The idle path in onTimer only persists when the
return value is true, eliminating unnecessary file writes every 60s
for far-future or idle schedules.
* fix: prep for merge - explicit delivery mode migration, docs + changelog (#10776) (thanks @tyler6204)
2026-02-06 18:03:03 -08:00
- `wakeMode: "now"` (default): event triggers an immediate heartbeat run.
- `wakeMode: "next-heartbeat"` : event waits for the next scheduled heartbeat.
2026-01-06 22:28:32 +00:00
2026-01-08 21:39:03 +01:00
This is the best fit when you want the normal heartbeat prompt + main-session context.
See [Heartbeat ](/gateway/heartbeat ).
#### Isolated jobs (dedicated cron sessions)
2026-01-31 21:13:13 +09:00
2026-03-14 13:48:46 +08:00
Isolated jobs run a dedicated agent turn in session `cron:<jobId>` or a custom session.
2026-01-06 22:28:32 +00:00
Key behaviors:
2026-01-31 21:13:13 +09:00
2026-01-06 22:28:32 +00:00
- Prompt is prefixed with `[cron:<jobId> <job name>]` for traceability.
2026-03-14 13:48:46 +08:00
- Each run starts a **fresh session id** (no prior conversation carry-over), unless using a custom session.
- Custom sessions (`session:xxx` ) persist context across runs, enabling workflows like daily standups that build on previous summaries.
2026-02-04 01:01:29 -08:00
- Default behavior: if `delivery` is omitted, isolated jobs announce a summary (`delivery.mode = "announce"` ).
2026-02-16 02:36:00 -08:00
- `delivery.mode` chooses what happens:
2026-02-04 01:01:29 -08:00
- `announce` : deliver a summary to the target channel and post a brief summary to the main session.
2026-02-16 21:48:57 -05:00
- `webhook` : POST the finished event payload to `delivery.to` when the finished event includes a summary.
2026-02-04 01:01:29 -08:00
- `none` : internal only (no delivery, no main-session summary).
- `wakeMode` controls when the main-session summary posts:
- `now` : immediate heartbeat.
- `next-heartbeat` : waits for the next scheduled heartbeat.
2026-01-08 21:39:03 +01:00
2026-01-10 22:32:09 -08:00
Use isolated jobs for noisy, frequent, or "background chores" that shouldn't spam
2026-01-08 21:39:03 +01:00
your main chat history.
2026-01-11 10:57:30 +00:00
### Payload shapes (what runs)
2026-01-31 21:13:13 +09:00
2026-01-11 10:57:30 +00:00
Two payload kinds are supported:
2026-01-31 21:13:13 +09:00
2026-01-11 10:57:30 +00:00
- `systemEvent` : main-session only, routed through the heartbeat prompt.
- `agentTurn` : isolated-session only, runs a dedicated agent turn.
Common `agentTurn` fields:
2026-01-31 21:13:13 +09:00
2026-01-11 10:57:30 +00:00
- `message` : required text prompt.
- `model` / `thinking` : optional overrides (see below).
- `timeoutSeconds` : optional timeout override.
2026-03-05 17:05:21 -05:00
- `lightContext` : optional lightweight bootstrap mode for jobs that do not need workspace bootstrap file injection.
2026-02-03 13:44:29 -08:00
2026-02-16 02:36:00 -08:00
Delivery config:
2026-02-03 13:44:29 -08:00
2026-02-16 02:36:00 -08:00
- `delivery.mode` : `none` | `announce` | `webhook` .
2026-02-03 13:44:29 -08:00
- `delivery.channel` : `last` or a specific channel.
2026-02-16 02:36:00 -08:00
- `delivery.to` : channel-specific target (announce) or webhook URL (webhook mode).
2026-02-03 16:53:46 -08:00
- `delivery.bestEffort` : avoid failing the job if announce delivery fails.
2026-02-03 13:44:29 -08:00
2026-02-03 16:53:46 -08:00
Announce delivery suppresses messaging tool sends for the run; use `delivery.channel` /`delivery.to`
2026-02-04 01:01:29 -08:00
to target the chat instead. When `delivery.mode = "none"` , no summary is posted to the main session.
2026-02-03 14:21:38 -08:00
2026-02-03 16:53:46 -08:00
If `delivery` is omitted for isolated jobs, OpenClaw defaults to `announce` .
2026-02-03 13:44:29 -08:00
2026-02-04 01:01:29 -08:00
#### Announce delivery flow
When `delivery.mode = "announce"` , cron delivers directly via the outbound channel adapters.
The main agent is not spun up to craft or forward the message.
Behavior details:
- Content: delivery uses the isolated run's outbound payloads (text/media) with normal chunking and
channel formatting.
- Heartbeat-only responses (`HEARTBEAT_OK` with no real content) are not delivered.
- If the isolated run already sent a message to the same target via the message tool, delivery is
skipped to avoid duplicates.
- Missing or invalid delivery targets fail the job unless `delivery.bestEffort = true` .
- A short summary is posted to the main session only when `delivery.mode = "announce"` .
- The main-session summary respects `wakeMode` : `now` triggers an immediate heartbeat and
`next-heartbeat` waits for the next scheduled heartbeat.
2026-02-16 02:36:00 -08:00
#### Webhook delivery flow
2026-02-16 21:48:57 -05:00
When `delivery.mode = "webhook"` , cron posts the finished event payload to `delivery.to` when the finished event includes a summary.
2026-02-16 02:36:00 -08:00
Behavior details:
- The endpoint must be a valid HTTP(S) URL.
- No channel delivery is attempted in webhook mode.
- No main-session summary is posted in webhook mode.
- If `cron.webhookToken` is set, auth header is `Authorization: Bearer <cron.webhookToken>` .
- Deprecated fallback: stored legacy jobs with `notify: true` still post to `cron.webhook` (if configured), with a warning so you can migrate to `delivery.mode = "webhook"` .
2026-01-10 22:32:09 -08:00
### Model and thinking overrides
2026-01-31 21:13:13 +09:00
2026-01-10 22:32:09 -08:00
Isolated jobs (`agentTurn` ) can override the model and thinking level:
2026-01-31 21:13:13 +09:00
2026-01-10 22:32:09 -08:00
- `model` : Provider/model string (e.g., `anthropic/claude-sonnet-4-20250514` ) or alias (e.g., `opus` )
2026-01-07 17:17:38 -08:00
- `thinking` : Thinking level (`off` , `minimal` , `low` , `medium` , `high` , `xhigh` ; GPT-5.2 + Codex models only)
2026-01-10 22:32:09 -08:00
2026-01-11 10:52:40 +00:00
Note: You can set `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.
2026-01-10 22:32:09 -08:00
Resolution priority:
2026-01-31 21:13:13 +09:00
2026-01-10 22:32:09 -08:00
1. Job payload override (highest)
2. Hook-specific defaults (e.g., `hooks.gmail.model` )
3. Agent config default
2026-03-05 17:05:21 -05:00
### Lightweight bootstrap context
Isolated jobs (`agentTurn` ) can set `lightContext: true` to run with lightweight bootstrap context.
- Use this for scheduled chores that do not need workspace bootstrap file injection.
- In practice, the embedded runtime runs with `bootstrapContextMode: "lightweight"` , which keeps cron bootstrap context empty on purpose.
- CLI equivalents: `openclaw cron add --light-context ...` and `openclaw cron edit --light-context` .
2026-01-13 07:15:57 +00:00
### Delivery (channel + target)
2026-01-31 21:13:13 +09:00
2026-02-03 13:44:29 -08:00
Isolated jobs can deliver output to a channel via the top-level `delivery` config:
2026-01-31 21:13:13 +09:00
2026-02-16 02:36:00 -08:00
- `delivery.mode` : `announce` (channel delivery), `webhook` (HTTP POST), or `none` .
2026-02-03 13:44:29 -08:00
- `delivery.channel` : `whatsapp` / `telegram` / `discord` / `slack` / `mattermost` (plugin) / `signal` / `imessage` / `last` .
- `delivery.to` : channel-specific recipient target.
2026-01-08 21:39:03 +01:00
2026-02-16 02:36:00 -08:00
`announce` delivery is only valid for isolated jobs (`sessionTarget: "isolated"` ).
`webhook` delivery is valid for both main and isolated jobs.
2026-01-08 21:39:03 +01:00
2026-02-03 13:44:29 -08:00
If `delivery.channel` or `delivery.to` is omitted, cron can fall back to the main session’ s
“last route” (the last place the agent replied).
2026-01-31 21:13:13 +09:00
2026-01-11 10:57:30 +00:00
Target format reminders:
2026-01-31 21:13:13 +09:00
2026-01-23 00:19:23 +00:00
- Slack/Discord/Mattermost (plugin) targets should use explicit prefixes (e.g. `channel:<id>` , `user:<id>` ) to avoid ambiguity.
2026-03-10 09:52:24 +01:00
Mattermost bare 26-char IDs are resolved **user-first** (DM if user exists, channel otherwise) — use `user:<id>` or `channel:<id>` for deterministic routing.
2026-01-11 10:57:30 +00:00
- Telegram topics should use the `:topic:` form (see below).
2026-01-08 21:39:03 +01:00
#### Telegram delivery targets (topics / forum threads)
2026-01-31 21:13:13 +09:00
2026-01-08 21:39:03 +01:00
Telegram supports forum topics via `message_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)
2026-01-08 23:25:45 +01:00
Prefixed targets like `telegram:...` / `telegram:group:...` are also accepted:
2026-01-31 21:13:13 +09:00
2026-01-08 21:39:03 +01:00
- `telegram:group:-1001234567890:topic:123`
2026-01-06 22:28:32 +00:00
2026-01-31 09:21:31 -05:00
## JSON schema for tool calls
Use these shapes when calling Gateway `cron.*` tools directly (agent tool calls or RPC).
2026-02-03 14:21:38 -08:00
CLI flags accept human durations like `20m` , but tool calls should use an ISO 8601 string
2026-02-03 16:53:46 -08:00
for `schedule.at` and milliseconds for `schedule.everyMs` .
2026-01-31 09:21:31 -05:00
### cron.add params
One-shot, main session job (system event):
```json
{
"name": "Reminder",
2026-02-03 14:21:38 -08:00
"schedule": { "kind": "at", "at": "2026-02-01T16:00:00Z" },
2026-01-31 09:21:31 -05:00
"sessionTarget": "main",
"wakeMode": "now",
"payload": { "kind": "systemEvent", "text": "Reminder text" },
"deleteAfterRun": true
}
```
Recurring, isolated job with delivery:
```json
{
"name": "Morning brief",
"schedule": { "kind": "cron", "expr": "0 7 * * *", "tz": "America/Los_Angeles" },
"sessionTarget": "isolated",
"wakeMode": "next-heartbeat",
"payload": {
"kind": "agentTurn",
2026-03-05 17:05:21 -05:00
"message": "Summarize overnight updates.",
"lightContext": true
2026-02-03 13:44:29 -08:00
},
"delivery": {
"mode": "announce",
2026-01-31 09:21:31 -05:00
"channel": "slack",
"to": "channel:C1234567890",
2026-02-03 13:44:29 -08:00
"bestEffort": true
}
2026-01-31 09:21:31 -05:00
}
```
2026-03-14 13:48:46 +08:00
Recurring job bound to current session (auto-resolved at creation):
```json
{
"name": "Daily standup",
"schedule": { "kind": "cron", "expr": "0 9 * * *" },
"sessionTarget": "current",
"payload": {
"kind": "agentTurn",
"message": "Summarize yesterday's progress."
}
}
```
Recurring job in a custom persistent session:
```json
{
"name": "Project monitor",
"schedule": { "kind": "every", "everyMs": 300000 },
"sessionTarget": "session:project-alpha-monitor",
"payload": {
"kind": "agentTurn",
"message": "Check project status and update the running log."
}
}
```
2026-01-31 09:21:31 -05:00
Notes:
2026-02-03 16:53:46 -08:00
- `schedule.kind` : `at` (`at` ), `every` (`everyMs` ), or `cron` (`expr` , optional `tz` ).
2026-02-03 14:21:38 -08:00
- `schedule.at` accepts ISO 8601 (timezone optional; treated as UTC when omitted).
2026-02-03 16:53:46 -08:00
- `everyMs` is milliseconds.
2026-03-14 13:48:46 +08:00
- `sessionTarget` : `"main"` , `"isolated"` , `"current"` , or `"session:<custom-id>"` .
- `"current"` is resolved to `"session:<sessionKey>"` at creation time.
- Custom sessions (`session:xxx` ) maintain persistent context across runs.
2026-02-16 02:36:00 -08:00
- Optional fields: `agentId` , `description` , `enabled` , `deleteAfterRun` (defaults to true for `at` ),
2026-02-03 16:53:46 -08:00
`delivery` .
fix: cron scheduler reliability, store hardening, and UX improvements (#10776)
* refactor: update cron job wake mode and run mode handling
- Changed default wake mode from 'next-heartbeat' to 'now' in CronJobEditor and related CLI commands.
- Updated cron-tool tests to reflect changes in run mode, introducing 'due' and 'force' options.
- Enhanced cron-tool logic to handle new run modes and ensure compatibility with existing job structures.
- Added new tests for delivery plan consistency and job execution behavior under various conditions.
- Improved normalization functions to handle wake mode and session target casing.
This refactor aims to streamline cron job configurations and enhance the overall user experience with clearer defaults and improved functionality.
* test: enhance cron job functionality and UI
- Added tests to ensure the isolated agent correctly announces the final payload text when delivering messages via Telegram.
- Implemented a new function to pick the last deliverable payload from a list of delivery payloads.
- Enhanced the cron service to maintain legacy "every" jobs while minute cron jobs recompute schedules.
- Updated the cron store migration tests to verify the addition of anchorMs to legacy every schedules.
- Improved the UI for displaying cron job details, including job state and delivery information, with new styles and layout adjustments.
These changes aim to improve the reliability and user experience of the cron job system.
* test: enhance sessions thinking level handling
- Added tests to verify that the correct thinking levels are applied during session spawning.
- Updated the sessions-spawn-tool to include a new parameter for overriding thinking levels.
- Enhanced the UI to support additional thinking levels, including "xhigh" and "full", and improved the handling of current options in dropdowns.
These changes aim to improve the flexibility and accuracy of thinking level configurations in session management.
* feat: enhance session management and cron job functionality
- Introduced passthrough arguments in the test-parallel script to allow for flexible command-line options.
- Updated session handling to hide cron run alias session keys from the sessions list, improving clarity.
- Enhanced the cron service to accurately record job start times and durations, ensuring better tracking of job execution.
- Added tests to verify the correct behavior of the cron service under various conditions, including zero-delay timers.
These changes aim to improve the usability and reliability of session and cron job management.
* feat: implement job running state checks in cron service
- Added functionality to prevent manual job runs if a job is already in progress, enhancing job management.
- Updated the `isJobDue` function to include checks for running jobs, ensuring accurate scheduling.
- Enhanced the `run` function to return a specific reason when a job is already running.
- Introduced a new test case to verify the behavior of forced manual runs during active job execution.
These changes aim to improve the reliability and clarity of cron job execution and management.
* feat: add session ID and key to CronRunLogEntry model
- Introduced `sessionid` and `sessionkey` properties to the `CronRunLogEntry` struct for enhanced tracking of session-related information.
- Updated the initializer and Codable conformance to accommodate the new properties, ensuring proper serialization and deserialization.
These changes aim to improve the granularity of logging and session management within the cron job system.
* fix: improve session display name resolution
- Updated the `resolveSessionDisplayName` function to ensure that both label and displayName are trimmed and default to an empty string if not present.
- Enhanced the logic to prevent returning the key if it matches the label or displayName, improving clarity in session naming.
These changes aim to enhance the accuracy and usability of session display names in the UI.
* perf: skip cron store persist when idle timer tick produces no changes
recomputeNextRuns now returns a boolean indicating whether any job
state was mutated. The idle path in onTimer only persists when the
return value is true, eliminating unnecessary file writes every 60s
for far-future or idle schedules.
* fix: prep for merge - explicit delivery mode migration, docs + changelog (#10776) (thanks @tyler6204)
2026-02-06 18:03:03 -08:00
- `wakeMode` defaults to `"now"` when omitted.
2026-01-31 09:21:31 -05:00
### cron.update params
```json
{
"jobId": "job-123",
"patch": {
"enabled": false,
"schedule": { "kind": "every", "everyMs": 3600000 }
}
}
```
Notes:
- `jobId` is canonical; `id` is accepted for compatibility.
- Use `agentId: null` in the patch to clear an agent binding.
### cron.run and cron.remove params
```json
{ "jobId": "job-123", "mode": "force" }
```
```json
{ "jobId": "job-123" }
```
2026-01-06 22:28:32 +00:00
## Storage & history
2026-01-31 21:13:13 +09:00
2026-01-30 03:15:10 +01:00
- Job store: `~/.openclaw/cron/jobs.json` (Gateway-managed JSON).
2026-02-23 17:39:48 -05:00
- Run history: `~/.openclaw/cron/runs/<jobId>.jsonl` (JSONL, auto-pruned by size and line count).
- Isolated cron run sessions in `sessions.json` are pruned by `cron.sessionRetention` (default `24h` ; set `false` to disable).
2026-01-06 22:28:32 +00:00
- Override store path: `cron.store` in config.
2026-03-01 20:58:03 +08:00
## Retry policy
When a job fails, OpenClaw classifies errors as **transient** (retryable) or **permanent** (disable immediately).
### Transient errors (retried)
- Rate limit (429, too many requests, resource exhausted)
2026-03-07 01:42:11 +03:00
- Provider overload (for example Anthropic `529 overloaded_error` , overload fallback summaries)
2026-03-01 20:58:03 +08:00
- Network errors (timeout, ECONNRESET, fetch failed, socket)
- Server errors (5xx)
- Cloudflare-related errors
### Permanent errors (no retry)
- Auth failures (invalid API key, unauthorized)
- Config or validation errors
- Other non-transient errors
### Default behavior (no config)
**One-shot jobs (`schedule.kind: "at"` ):**
- On transient error: retry up to 3 times with exponential backoff (30s → 1m → 5m).
- On permanent error: disable immediately.
- On success or skip: disable (or delete if `deleteAfterRun: true` ).
**Recurring jobs (`cron` / `every` ):**
- On any error: apply exponential backoff (30s → 1m → 5m → 15m → 60m) before the next scheduled run.
- Job stays enabled; backoff resets after the next successful run.
Configure `cron.retry` to override these defaults (see [Configuration ](/automation/cron-jobs#configuration )).
2026-01-06 22:28:32 +00:00
## Configuration
```json5
{
cron: {
2026-01-08 21:39:03 +01:00
enabled: true, // default true
2026-01-30 03:15:10 +01:00
store: "~/.openclaw/cron/jobs.json",
2026-01-31 21:13:13 +09:00
maxConcurrentRuns: 1, // default 1
2026-03-01 20:58:03 +08:00
// Optional: override retry policy for one-shot jobs
retry: {
maxAttempts: 3,
backoffMs: [60000, 120000, 300000],
2026-03-07 01:42:11 +03:00
retryOn: ["rate_limit", "overloaded", "network", "server_error"],
2026-03-01 20:58:03 +08:00
},
2026-02-16 02:36:00 -08:00
webhook: "https://example.invalid/legacy", // deprecated fallback for stored notify:true jobs
webhookToken: "replace-with-dedicated-webhook-token", // optional bearer token for webhook mode
2026-02-23 17:39:48 -05:00
sessionRetention: "24h", // duration string or false
runLog: {
maxBytes: "2mb", // default 2_000_000 bytes
keepLines: 2000, // default 2000
},
2026-01-31 21:13:13 +09:00
},
2026-01-06 22:28:32 +00:00
}
```
2026-02-23 17:39:48 -05:00
Run-log pruning behavior:
- `cron.runLog.maxBytes` : max run-log file size before pruning.
- `cron.runLog.keepLines` : when pruning, keep only the newest N lines.
- Both apply to `cron/runs/<jobId>.jsonl` files.
2026-02-15 16:14:17 -08:00
Webhook behavior:
2026-02-16 02:36:00 -08:00
- Preferred: set `delivery.mode: "webhook"` with `delivery.to: "https://..."` per job.
- Webhook URLs must be valid `http://` or `https://` URLs.
2026-02-16 21:48:57 -05:00
- When posted, payload is the cron finished event JSON.
2026-02-15 16:14:17 -08:00
- If `cron.webhookToken` is set, auth header is `Authorization: Bearer <cron.webhookToken>` .
- If `cron.webhookToken` is not set, no `Authorization` header is sent.
2026-02-16 02:36:00 -08:00
- Deprecated fallback: stored legacy jobs with `notify: true` still use `cron.webhook` when present.
2026-02-15 16:14:17 -08:00
2026-01-06 22:28:32 +00:00
Disable cron entirely:
2026-01-31 21:13:13 +09:00
2026-01-06 22:28:32 +00:00
- `cron.enabled: false` (config)
2026-01-30 03:15:10 +01:00
- `OPENCLAW_SKIP_CRON=1` (env)
2026-01-06 22:28:32 +00:00
2026-02-23 17:39:48 -05:00
## Maintenance
Cron has two built-in maintenance paths: isolated run-session retention and run-log pruning.
### Defaults
- `cron.sessionRetention` : `24h` (set `false` to disable run-session pruning)
- `cron.runLog.maxBytes` : `2_000_000` bytes
- `cron.runLog.keepLines` : `2000`
### How it works
- Isolated runs create session entries (`...:cron:<jobId>:run:<uuid>` ) and transcript files.
- The reaper removes expired run-session entries older than `cron.sessionRetention` .
- For removed run sessions no longer referenced by the session store, OpenClaw archives transcript files and purges old deleted archives on the same retention window.
- After each run append, `cron/runs/<jobId>.jsonl` is size-checked:
- if file size exceeds `runLog.maxBytes` , it is trimmed to the newest `runLog.keepLines` lines.
### Performance caveat for high volume schedulers
High-frequency cron setups can generate large run-session and run-log footprints. Maintenance is built in, but loose limits can still create avoidable IO and cleanup work.
What to watch:
- long `cron.sessionRetention` windows with many isolated runs
- high `cron.runLog.keepLines` combined with large `runLog.maxBytes`
- many noisy recurring jobs writing to the same `cron/runs/<jobId>.jsonl`
What to do:
- keep `cron.sessionRetention` as short as your debugging/audit needs allow
- keep run logs bounded with moderate `runLog.maxBytes` and `runLog.keepLines`
- move noisy background jobs to isolated mode with delivery rules that avoid unnecessary chatter
- review growth periodically with `openclaw cron runs` and adjust retention before logs become large
### Customize examples
Keep run sessions for a week and allow bigger run logs:
```json5
{
cron: {
sessionRetention: "7d",
runLog: {
maxBytes: "10mb",
keepLines: 5000,
},
},
}
```
Disable isolated run-session pruning but keep run-log pruning:
```json5
{
cron: {
sessionRetention: false,
runLog: {
maxBytes: "5mb",
keepLines: 3000,
},
},
}
```
Tune for high-volume cron usage (example):
```json5
{
cron: {
sessionRetention: "12h",
runLog: {
maxBytes: "3mb",
keepLines: 1500,
},
},
}
```
2026-01-06 22:28:32 +00:00
## CLI quickstart
2026-01-13 04:55:39 +00:00
One-shot reminder (UTC ISO, auto-delete after success):
2026-01-31 21:13:13 +09:00
2026-01-13 04:55:39 +00:00
```bash
2026-01-30 03:15:10 +01:00
openclaw cron add \
2026-01-13 04:55:39 +00:00
--name "Send reminder" \
--at "2026-01-12T18:00:00Z" \
--session main \
--system-event "Reminder: submit expense report." \
--wake now \
--delete-after-run
```
2026-01-06 22:28:32 +00:00
One-shot reminder (main session, wake immediately):
2026-01-31 21:13:13 +09:00
2026-01-06 22:28:32 +00:00
```bash
2026-01-30 03:15:10 +01:00
openclaw cron add \
2026-01-06 22:28:32 +00:00
--name "Calendar check" \
--at "20m" \
--session main \
--system-event "Next heartbeat: check calendar." \
--wake now
```
2026-02-03 13:44:29 -08:00
Recurring isolated job (announce to WhatsApp):
2026-01-31 21:13:13 +09:00
2026-01-06 22:28:32 +00:00
```bash
2026-01-30 03:15:10 +01:00
openclaw cron add \
2026-01-06 22:28:32 +00:00
--name "Morning status" \
--cron "0 7 * * *" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Summarize inbox + calendar for today." \
2026-02-03 13:44:29 -08:00
--announce \
2026-01-13 06:51:20 +00:00
--channel whatsapp \
2026-01-06 22:28:32 +00:00
--to "+15551234567"
```
2026-02-17 23:46:05 +01:00
Recurring cron job with explicit 30-second stagger:
```bash
openclaw cron add \
--name "Minute watcher" \
--cron "0 * * * * *" \
--tz "UTC" \
--stagger 30s \
--session isolated \
--message "Run minute watcher checks." \
--announce
```
2026-01-08 21:39:03 +01:00
Recurring isolated job (deliver to a Telegram topic):
2026-01-31 21:13:13 +09:00
2026-01-08 21:39:03 +01:00
```bash
2026-01-30 03:15:10 +01:00
openclaw cron add \
2026-01-08 21:39:03 +01:00
--name "Nightly summary (topic)" \
--cron "0 22 * * *" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Summarize today; send to the nightly topic." \
2026-02-03 16:53:46 -08:00
--announce \
2026-01-13 06:51:20 +00:00
--channel telegram \
2026-01-08 21:39:03 +01:00
--to "-1001234567890:topic:123"
```
2026-01-10 22:32:09 -08:00
Isolated job with model and thinking override:
2026-01-31 21:13:13 +09:00
2026-01-31 09:21:31 -05:00
```bash
2026-01-30 03:15:10 +01:00
openclaw cron add \
2026-01-10 22:32:09 -08:00
--name "Deep analysis" \
--cron "0 6 * * 1" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Weekly deep analysis of project progress." \
--model "opus" \
--thinking high \
2026-02-03 16:53:46 -08:00
--announce \
2026-01-13 06:51:20 +00:00
--channel whatsapp \
2026-01-10 22:32:09 -08:00
--to "+15551234567"
2026-01-31 09:21:31 -05:00
```
2026-01-12 10:23:45 +00:00
Agent selection (multi-agent setups):
2026-01-31 22:36:50 +05:30
2026-01-12 10:23:45 +00:00
```bash
# Pin a job to agent "ops" (falls back to default if that agent is missing)
2026-01-30 03:15:10 +01:00
openclaw cron add --name "Ops sweep" --cron "0 6 * * *" --session isolated --message "Check ops queue" --agent ops
2026-01-12 10:23:45 +00:00
# Switch or clear the agent on an existing job
2026-01-30 03:15:10 +01:00
openclaw cron edit < jobId > --agent ops
openclaw cron edit < jobId > --clear-agent
2026-01-31 09:21:31 -05:00
```
2026-01-10 22:32:09 -08:00
fix: cron scheduler reliability, store hardening, and UX improvements (#10776)
* refactor: update cron job wake mode and run mode handling
- Changed default wake mode from 'next-heartbeat' to 'now' in CronJobEditor and related CLI commands.
- Updated cron-tool tests to reflect changes in run mode, introducing 'due' and 'force' options.
- Enhanced cron-tool logic to handle new run modes and ensure compatibility with existing job structures.
- Added new tests for delivery plan consistency and job execution behavior under various conditions.
- Improved normalization functions to handle wake mode and session target casing.
This refactor aims to streamline cron job configurations and enhance the overall user experience with clearer defaults and improved functionality.
* test: enhance cron job functionality and UI
- Added tests to ensure the isolated agent correctly announces the final payload text when delivering messages via Telegram.
- Implemented a new function to pick the last deliverable payload from a list of delivery payloads.
- Enhanced the cron service to maintain legacy "every" jobs while minute cron jobs recompute schedules.
- Updated the cron store migration tests to verify the addition of anchorMs to legacy every schedules.
- Improved the UI for displaying cron job details, including job state and delivery information, with new styles and layout adjustments.
These changes aim to improve the reliability and user experience of the cron job system.
* test: enhance sessions thinking level handling
- Added tests to verify that the correct thinking levels are applied during session spawning.
- Updated the sessions-spawn-tool to include a new parameter for overriding thinking levels.
- Enhanced the UI to support additional thinking levels, including "xhigh" and "full", and improved the handling of current options in dropdowns.
These changes aim to improve the flexibility and accuracy of thinking level configurations in session management.
* feat: enhance session management and cron job functionality
- Introduced passthrough arguments in the test-parallel script to allow for flexible command-line options.
- Updated session handling to hide cron run alias session keys from the sessions list, improving clarity.
- Enhanced the cron service to accurately record job start times and durations, ensuring better tracking of job execution.
- Added tests to verify the correct behavior of the cron service under various conditions, including zero-delay timers.
These changes aim to improve the usability and reliability of session and cron job management.
* feat: implement job running state checks in cron service
- Added functionality to prevent manual job runs if a job is already in progress, enhancing job management.
- Updated the `isJobDue` function to include checks for running jobs, ensuring accurate scheduling.
- Enhanced the `run` function to return a specific reason when a job is already running.
- Introduced a new test case to verify the behavior of forced manual runs during active job execution.
These changes aim to improve the reliability and clarity of cron job execution and management.
* feat: add session ID and key to CronRunLogEntry model
- Introduced `sessionid` and `sessionkey` properties to the `CronRunLogEntry` struct for enhanced tracking of session-related information.
- Updated the initializer and Codable conformance to accommodate the new properties, ensuring proper serialization and deserialization.
These changes aim to improve the granularity of logging and session management within the cron job system.
* fix: improve session display name resolution
- Updated the `resolveSessionDisplayName` function to ensure that both label and displayName are trimmed and default to an empty string if not present.
- Enhanced the logic to prevent returning the key if it matches the label or displayName, improving clarity in session naming.
These changes aim to enhance the accuracy and usability of session display names in the UI.
* perf: skip cron store persist when idle timer tick produces no changes
recomputeNextRuns now returns a boolean indicating whether any job
state was mutated. The idle path in onTimer only persists when the
return value is true, eliminating unnecessary file writes every 60s
for far-future or idle schedules.
* fix: prep for merge - explicit delivery mode migration, docs + changelog (#10776) (thanks @tyler6204)
2026-02-06 18:03:03 -08:00
Manual run (force is the default, use `--due` to only run when due):
2026-01-31 22:36:50 +05:30
2026-01-06 22:28:32 +00:00
```bash
fix: cron scheduler reliability, store hardening, and UX improvements (#10776)
* refactor: update cron job wake mode and run mode handling
- Changed default wake mode from 'next-heartbeat' to 'now' in CronJobEditor and related CLI commands.
- Updated cron-tool tests to reflect changes in run mode, introducing 'due' and 'force' options.
- Enhanced cron-tool logic to handle new run modes and ensure compatibility with existing job structures.
- Added new tests for delivery plan consistency and job execution behavior under various conditions.
- Improved normalization functions to handle wake mode and session target casing.
This refactor aims to streamline cron job configurations and enhance the overall user experience with clearer defaults and improved functionality.
* test: enhance cron job functionality and UI
- Added tests to ensure the isolated agent correctly announces the final payload text when delivering messages via Telegram.
- Implemented a new function to pick the last deliverable payload from a list of delivery payloads.
- Enhanced the cron service to maintain legacy "every" jobs while minute cron jobs recompute schedules.
- Updated the cron store migration tests to verify the addition of anchorMs to legacy every schedules.
- Improved the UI for displaying cron job details, including job state and delivery information, with new styles and layout adjustments.
These changes aim to improve the reliability and user experience of the cron job system.
* test: enhance sessions thinking level handling
- Added tests to verify that the correct thinking levels are applied during session spawning.
- Updated the sessions-spawn-tool to include a new parameter for overriding thinking levels.
- Enhanced the UI to support additional thinking levels, including "xhigh" and "full", and improved the handling of current options in dropdowns.
These changes aim to improve the flexibility and accuracy of thinking level configurations in session management.
* feat: enhance session management and cron job functionality
- Introduced passthrough arguments in the test-parallel script to allow for flexible command-line options.
- Updated session handling to hide cron run alias session keys from the sessions list, improving clarity.
- Enhanced the cron service to accurately record job start times and durations, ensuring better tracking of job execution.
- Added tests to verify the correct behavior of the cron service under various conditions, including zero-delay timers.
These changes aim to improve the usability and reliability of session and cron job management.
* feat: implement job running state checks in cron service
- Added functionality to prevent manual job runs if a job is already in progress, enhancing job management.
- Updated the `isJobDue` function to include checks for running jobs, ensuring accurate scheduling.
- Enhanced the `run` function to return a specific reason when a job is already running.
- Introduced a new test case to verify the behavior of forced manual runs during active job execution.
These changes aim to improve the reliability and clarity of cron job execution and management.
* feat: add session ID and key to CronRunLogEntry model
- Introduced `sessionid` and `sessionkey` properties to the `CronRunLogEntry` struct for enhanced tracking of session-related information.
- Updated the initializer and Codable conformance to accommodate the new properties, ensuring proper serialization and deserialization.
These changes aim to improve the granularity of logging and session management within the cron job system.
* fix: improve session display name resolution
- Updated the `resolveSessionDisplayName` function to ensure that both label and displayName are trimmed and default to an empty string if not present.
- Enhanced the logic to prevent returning the key if it matches the label or displayName, improving clarity in session naming.
These changes aim to enhance the accuracy and usability of session display names in the UI.
* perf: skip cron store persist when idle timer tick produces no changes
recomputeNextRuns now returns a boolean indicating whether any job
state was mutated. The idle path in onTimer only persists when the
return value is true, eliminating unnecessary file writes every 60s
for far-future or idle schedules.
* fix: prep for merge - explicit delivery mode migration, docs + changelog (#10776) (thanks @tyler6204)
2026-02-06 18:03:03 -08:00
openclaw cron run < jobId >
openclaw cron run < jobId > --due
2026-01-31 09:21:31 -05:00
```
2026-01-06 22:28:32 +00:00
2026-03-08 14:46:33 -07:00
`cron.run` now acknowledges once the manual run is queued, not after the job finishes. Successful queue responses look like `{ ok: true, enqueued: true, runId }` . If the job is already running or `--due` finds nothing due, the response stays `{ ok: true, ran: false, reason }` . Use `openclaw cron runs --id <jobId>` or the `cron.runs` gateway method to inspect the eventual finished entry.
2026-01-11 10:57:30 +00:00
Edit an existing job (patch fields):
2026-01-31 21:13:13 +09:00
2026-01-11 10:57:30 +00:00
```bash
2026-01-30 03:15:10 +01:00
openclaw cron edit < jobId > \
2026-01-11 10:57:30 +00:00
--message "Updated prompt" \
--model "opus" \
--thinking low
```
2026-02-17 23:46:05 +01:00
Force an existing cron job to run exactly on schedule (no stagger):
```bash
openclaw cron edit < jobId > --exact
```
2026-01-06 22:28:32 +00:00
Run history:
2026-01-31 21:13:13 +09:00
2026-01-06 22:28:32 +00:00
```bash
2026-01-30 03:15:10 +01:00
openclaw cron runs --id < jobId > --limit 50
2026-01-06 22:28:32 +00:00
```
2026-01-24 04:01:45 +00:00
Immediate system event without creating a job:
2026-01-31 21:13:13 +09:00
2026-01-06 22:28:32 +00:00
```bash
2026-01-30 03:15:10 +01:00
openclaw system event --mode now --text "Next heartbeat: check battery."
2026-01-06 22:28:32 +00:00
```
2026-01-08 21:39:03 +01:00
## Gateway API surface
2026-01-31 21:13:13 +09:00
2026-01-06 22:28:32 +00:00
- `cron.list` , `cron.status` , `cron.add` , `cron.update` , `cron.remove`
- `cron.run` (force or due), `cron.runs`
2026-01-31 21:13:13 +09:00
For immediate system events without a job, use [`openclaw system event` ](/cli/system ).
2026-01-06 22:28:32 +00:00
2026-01-08 21:39:03 +01:00
## Troubleshooting
### “Nothing runs”
2026-01-31 21:13:13 +09:00
2026-01-30 03:15:10 +01:00
- Check cron is enabled: `cron.enabled` and `OPENCLAW_SKIP_CRON` .
2026-01-08 21:39:03 +01:00
- Check the Gateway is running continuously (cron runs inside the Gateway process).
- For `cron` schedules: confirm timezone (`--tz` ) vs the host timezone.
2026-02-07 19:46:01 -08:00
### A recurring job keeps delaying after failures
- OpenClaw applies exponential retry backoff for recurring jobs after consecutive errors:
30s, 1m, 5m, 15m, then 60m between retries.
- Backoff resets automatically after the next successful run.
2026-03-07 01:42:11 +03:00
- One-shot (`at` ) jobs retry transient errors (rate limit, overloaded, network, server_error) up to 3 times with backoff; permanent errors disable immediately. See [Retry policy ](/automation/cron-jobs#retry-policy ).
2026-02-07 19:46:01 -08:00
2026-01-08 21:39:03 +01:00
### Telegram delivers to the wrong place
2026-01-31 21:13:13 +09:00
2026-01-08 21:39:03 +01:00
- 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.
2026-02-16 20:51:44 +01:00
### Subagent announce delivery retries
- When a subagent run completes, the gateway announces the result to the requester session.
- If the announce flow returns `false` (e.g. requester session is busy), the gateway retries up to 3 times with tracking via `announceRetryCount` .
- Announces older than 5 minutes past `endedAt` are force-expired to prevent stale entries from looping indefinitely.
- If you see repeated announce deliveries in logs, check the subagent registry for entries with high `announceRetryCount` values.