Intermediate
macOS / Linux / Windows (WSL2) / Docker / Self-hosted
Estimated time: 25 min

OpenClaw Cron & Heartbeat: Make Your Agent Actually Run 24/7

A pragmatic guide to OpenClaw automation reliability: how cron runs are scheduled and delivered, why jobs can 'advance nextRunAtMs' without executing, and how to design runs that always leave evidence and alert correctly.

Implementation Steps

Cron/heartbeat are gateway features. If your gateway isn’t running continuously, automation cannot be reliable.

People expect “24/7” to mean: I schedule a cron job and my agent reliably does it forever.

In practice, cron reliability depends on three things:

  1. The gateway is always running (daemon/service, not a one-off terminal session).
  2. The cron scheduler is healthy (no regressions, correct timezone, persistent storage).
  3. Your delivery strategy is robust (announce vs explicit sends vs webhooks).

This guide focuses on repeatable diagnostics and designs that leave evidence.

If your OpenClaw install is not yet stable, do that first:


0) First principles: cron runs inside the gateway

Cron is executed by the gateway process. If the gateway is down, sleeping, or constantly restarting, cron can’t be reliable.

Baseline checks (gateway host):

openclaw status --deep
openclaw logs --follow

If you are on WSL2, ensure systemd is enabled so the gateway stays alive:

If you are on Docker, ensure the state directory is persisted and writable:


1) Prove cron is running (and see its history)

List jobs:

openclaw cron list

Inspect runs for a job:

openclaw cron runs --id <job-id>

If nextRunAtMs advances but runs stays empty, that’s not “your prompt is bad” — it’s usually scheduler/timezone/storage.

Dedicated fix page:


2) The most common cron failure modes (and what to do)

2.1 Cron never executes (runs stay empty)

Symptoms:

  • Job looks enabled, nextRunAtMs keeps moving, but no runs are recorded.

Fix:

2.2 Cron executes, but announce delivery fails

Symptoms:

  • Runs exist, but you see cron announce delivery failed (often on Telegram delivery).

High-value workaround:

  • Disable announce delivery and send explicitly inside the run (or switch to webhook delivery).

Fix page:

2.3 Cron delivers only a summary (not full output)

Symptoms:

  • A multi-line report used to arrive; now you only get a short summary.

Fix page:

2.4 Isolated jobs fail immediately on tools.function validation

Symptoms:

  • The cron job exists and runs are attempted, but isolated execution fails immediately with Field required / tools.function.

Fix page:

2.5 Isolated agentTurn jobs enqueue, then stall or time out under default concurrency

Symptoms:

  • openclaw cron run <job-id> says the run was accepted/enqueued.
  • A session stub may appear, but the real transcript/run never materializes.
  • openclaw cron runs --id <job-id> stays empty or only shows timeouts.
  • Logs can include lane-wait messages while using sessionTarget: "isolated" + payload.kind: "agentTurn".

High-value workaround:

  1. Raise cron concurrency:
{
  cron: {
    maxConcurrentRuns: 2,
  },
}
  1. Restart the gateway and retest:
openclaw gateway restart
openclaw cron run <job-id>
openclaw cron runs --id <job-id> --limit 20

Why this helps: the documented default is still maxConcurrentRuns: 1, but isolated agentTurn jobs can end up waiting on work queued behind the cron lane itself. Raising concurrency to 2 removes that self-blocking path in affected versions.

If you cannot change concurrency right now, move the job to sessionTarget: "main" + systemEvent temporarily so it avoids the isolated execution path while you validate the rest of the workflow.


3) Design cron prompts that always leave evidence

The biggest quality-of-life upgrade is: stop treating delivery as the only “proof” that the job ran.

Recommended patterns:

  1. Write a timestamped artifact (file) into the workspace each run.
  2. Send an explicit message with the artifact path + a short summary.
  3. Use a webhook for durable delivery when channels are flaky.

If you ever see “it said it saved a file but nothing exists”, fix workspace/persistence first:


4) Heartbeat expectations (why “it’s lazy” happens)

Heartbeat is not magic free will — it is a scheduling mechanism and still depends on:

  • gateway uptime
  • provider availability (rate limits)
  • stable state directory

If your cron/heartbeat runs but the model silently fails, use:


5) Upgrade-safe automation

Upgrades and redeploys often “break cron” indirectly by wiping state or changing the runtime binary.

Do these once:

  • Persist state (~/.openclaw/ or $OPENCLAW_STATE_DIR)
  • Pin gateway auth via env vars (so restores are reproducible)
  • Practice a restore drill

Useful references:

Verification & references

  • Reviewed by:CoClaw Editorial Team
  • Last reviewed:March 14, 2026
  • Verified on: macOS · Linux · Windows (WSL2) · Docker · Self-hosted

Related Resources

OpenClaw TASKS.md Template: A Simple Workspace Task Board
Guide
Download a ready-made TASKS.md file for your OpenClaw workspace to track multi-step work, make cron runs leave evidence, and reduce 'it promised but I can't see what happened' failures.
OpenClaw Cost and Guardrails Checklist: Prevent Runaway Runs Before They Happen
Guide
A practical operator checklist to control blast radius and token spend: start with a bounded tool profile, tighten DM policies, make runs leave evidence, and keep a kill switch. Designed for real life, not perfect autonomy.
OpenClaw on Native Windows: PATH, Scheduled Tasks, Node Host, and the Real Failure Modes
Guide
A field guide to running OpenClaw on native Windows without guesswork. Learn why shell PATH and Scheduled Task PATH diverge, when `tools.exec.pathPrepend` helps or hurts, why `openclaw node run` can stall after printing PATH, and when WSL2 is the lower-risk choice.
Cron: jobs don't fire and nextRunAtMs silently advances
Fix
Fix cron jobs that skip runs (no execution/logs) while nextRunAtMs advances by upgrading past known scheduler regressions and verifying cron storage + timezone.
Cron: jobs run but Telegram announce delivery fails (no notification sent)
Fix
If isolated cron jobs execute successfully but the Telegram notification never arrives ("cron announce delivery failed"), disable announce and send via the message tool, or switch delivery mode while you capture gateway logs for the failing announce path.
Cron: announce delivery sends a summary instead of the full output (Telegram topics / chat channels)
Fix
If an isolated cron job used to deliver the full output but now sends a summary (or leaks extra text like thinking/reasoning), disable announce delivery and send a clean final message explicitly.

Need live assistance?

Ask in the community forum or Discord support channels.

Get Support