🦞OpenClaw Guide
Automation

Cron Jobs & Heartbeats — Making OpenClaw Proactive

Fix cron jobs that never fire, messages that don't deliver, and heartbeats that interrupt your agent's work. Complete troubleshooting for proactive automation.

⚠️ The Problem

Cron jobs show 'idle' or 'skipped' status and never actually run. When they do run, messages are sent as 'system reminders' that never reach you. Heartbeats may interrupt active subagent work, and force-running jobs returns 'not-due' even with mode: force.

🔍 Why This Happens

Several distinct issues cause cron failures: (1) The Gateway process isn't running continuously or cron is disabled in config. (2) Cron jobs created via chat may not have the correct schema—specifically missing 'enabled: true' which should default but sometimes doesn't. (3) Messages are delivered to a 'system' channel instead of your actual chat interface. (4) Main session cron jobs require heartbeats to be enabled, while isolated session jobs run independently. (5) The wakeMode setting affects when jobs actually execute—'now' can cause rapid re-runs while 'next-heartbeat' requires active heartbeats.

The Fix

## Step 1: Verify Cron is Enabled

First, check if the Gateway is running and cron is enabled:

bash
openclaw gateway status

Look for 'cron: enabled' in the output. If cron is disabled, check your config:

bash
cat ~/.openclaw/openclaw.json | grep -A5 cron

Make sure you don't have OPENCLAW_SKIP_CRON=1 in your environment:

bash
env | grep OPENCLAW

## Step 2: List Current Cron Jobs

View all scheduled jobs and their status:

bash
openclaw cron list

Jobs showing 'idle' with 'Last: -' have never run. Check that 'enabled' is true for each job.

## Step 3: Fix Message Delivery (Critical)

The most common issue is messages going to a 'system' channel instead of reaching you. For reliable delivery, use this proven configuration:

json
{  "sessionTarget": "isolated",  "payload": {    "kind": "agentTurn",    "deliver": true,    "message": "Respond with [your exact text]. Do not remain silent."  }}

Key settings explained:

- sessionTarget: 'isolated' — Runs in its own session, doesn't conflict with active conversations

- deliver: true — Explicitly tells the agent to send output to your channel

- Explicit message instruction — Tell the agent exactly what to say; vague instructions may result in silence

## Step 4: Create a Reliable Cron Job via CLI

Jobs created via chat sometimes have schema issues. Create directly via CLI for reliability:

bash
openclaw cron add \  --name "daily-reminder" \  --schedule "0 9 * * *" \  --session isolated \  --channel telegram \  --message "Good morning! Here's your daily briefing."

Or use the full JSON format:

bash
openclaw cron add --json '{  "name": "daily-reminder",  "schedule": "0 9 * * *",  "enabled": true,  "sessionTarget": "isolated",  "payload": {    "kind": "agentTurn",    "deliver": true,    "channel": "telegram",    "message": "Send me a good morning message with today\'s priorities."  }}'

## Step 5: Main Session vs Isolated Session

Understanding the difference prevents most issues:

| Session Type | Requires Heartbeat | Conflicts with Active Chat | Best For |

|--------------|-------------------|---------------------------|----------|

| main | Yes | Yes—may skip if you're chatting | Context-aware tasks |

| isolated | No | No—runs independently | Reminders, scheduled messages |

If heartbeats are disabled, main session cron jobs will never run. Either:

- Enable heartbeats in config, or

- Use sessionTarget: 'isolated' for all cron jobs

## Step 6: Fix 'not-due' When Force-Running

If openclaw cron run --force still returns 'not-due':

bash
# Check the job's next scheduled timeopenclaw cron list --verbose# Verify the schedule expression is validopenclaw cron validate "*/5 * * * *"# Try updating the job to run immediatelyopenclaw cron update daily-reminder --next-run now

## Step 7: Prevent Heartbeats from Interrupting Work

If heartbeats are killing your subagent tasks:

Edit your HEARTBEAT.md to only say HEARTBEAT_OK as the absolute final step:

markdown
# Heartbeat Checklist1. Check memory/ for pending tasks2. Review subagent status (do NOT interrupt active ones)3. Only if no active work exists, consider proactive actions4. FINAL STEP (always last): HEARTBEAT_OK

The key insight: When HEARTBEAT_OK is delivered, it can interrupt current activity including subagents. Structure your heartbeat so HEARTBEAT_OK only happens when truly idle.

## Step 8: Debug Why a Specific Job Didn't Run

Check the logs for your job:

bash
openclaw logs --follow | grep cron

Common log messages and meanings:

- cron job skipped: session busy — Active conversation blocked it; use isolated session

- cron job skipped: not due — Schedule hasn't triggered yet

- cron delivered to system — deliver: true was missing; message went nowhere

- cron job ok, duration: Xms — Job ran but check if delivery worked

🔥 Your AI should run your business, not just answer questions.

We'll show you how.$97/mo (going to $197 soon)

Join Vibe Combinator →

📋 Quick Commands

CommandDescription
openclaw gateway statusCheck if Gateway is running and cron is enabled
openclaw cron listShow all cron jobs with status and last run time
openclaw cron list --verboseShow detailed cron info including next scheduled run
openclaw cron add --name X --schedule "CRON" --session isolated --message "Y"Create a new cron job with isolated session
openclaw cron run JOBNAME --forceForce-run a cron job immediately regardless of schedule
openclaw cron update JOBNAME --enabled trueEnable a disabled cron job
openclaw cron delete JOBNAMERemove a cron job
openclaw logs --follow | grep cronWatch cron-related log entries in real-time

Related Issues

    🐙 Your AI should run your business.

    Weekly live builds + template vault. We'll show you how to make AI actually work.$97/mo (going to $197 soon)

    Join Vibe Combinator →

    Still stuck?

    Join our Discord community for real-time help.

    Join Discord