OpenClaw has a built-in scheduler that handles timed tasks without you installing anything extra. Morning briefings at 7 AM, weekly analytics reports, or a quick reminder in 20 minutes — it’s all there.
I’ve been using cron jobs extensively: daily morning briefings, weekly reflections, email digests, calendar summaries. This guide walks through what I learned, with copy-paste examples you can adapt.
What Are Cron Jobs in OpenClaw?
Cron jobs in OpenClaw are scheduled tasks that run inside the Gateway process. Unlike Linux system cron, there’s no external configuration or shell scripting required. You create them via CLI or tool calls, and OpenClaw saves them to ~/.openclaw/cron/ so they survive restarts.
Every job has three parts:
- Schedule — when it runs (one-shot, interval, or cron expression)
- Payload — what it does (system event or agent turn)
- Session target — where it runs (main session or isolated)
The Gateway checks for due jobs, runs them, and optionally sends results to a chat channel.
Schedule Types: at, every, and cron Expressions
OpenClaw gives you three ways to specify timing.
at — One-Shot Timestamps
Use at for reminders or single future events.
openclaw cron add \
--name "Meeting reminder" \
--at "2026-02-20T14:30:00Z" \
--session main \
--system-event "Reminder: team standup in 15 minutes" \
--wake now \
--delete-after-run
The --at flag accepts ISO 8601 timestamps. Omit the timezone and OpenClaw assumes UTC. You can also use relative time:
--at "20m" # 20 minutes from now
--at "2h" # 2 hours from now
--at "1d" # 1 day from now
One-shot jobs delete after success by default. Add --keep-after-run if you want to keep them around.
every — Fixed Intervals
Use every for tasks that repeat at a fixed cadence.
openclaw cron add \
--name "Health check" \
--every "30m" \
--session main \
--system-event "Check disk space and memory usage" \
--wake now
The --every flag takes human-readable durations: 30m, 1h, 4h, 1d. Internally this becomes milliseconds in the job definition.
cron — Full Cron Expressions
Use cron when you need exact calendar-based scheduling. OpenClaw uses 5-field cron expressions (minute hour day month weekday) with optional timezone support.
openclaw cron add \
--name "Morning briefing" \
--cron "0 7 * * *" \
--tz "America/New_York" \
--session isolated \
--message "Summarize today's calendar and top emails" \
--announce
This runs at 7:00 AM every day in America/New_York time. Without --tz, the Gateway uses its host timezone.
Patterns I use frequently:
0 9 * * 1— Every Monday at 9 AM0 0 * * *— Daily at midnight*/15 * * * *— Every 15 minutes0 8-18 * * 1-5— Every hour from 8 AM to 6 PM on weekdays
Payload Types: systemEvent vs agentTurn
What a job does depends on its payload type.
systemEvent — For Main Session Jobs
A system event is text injected into the main session’s context, usually processed during the next heartbeat. This is the only payload type allowed for main session jobs.
openclaw cron add \
--name "Project reminder" \
--at "1h" \
--session main \
--system-event "Check status of the migration project" \
--wake now
When the job runs, OpenClaw adds a system event line to the main session:
System: [2026-02-17 09:45:00 PST] Check status of the migration project
The agent sees this on the next heartbeat and handles it with full knowledge of recent conversations.
agentTurn — For Isolated Session Jobs
An agent turn runs a complete agent invocation with a fresh prompt. This is the only payload type allowed for isolated session jobs.
openclaw cron add \
--name "Weekly report" \
--cron "0 9 * * 1" \
--session isolated \
--message "Generate a weekly summary of completed tasks and upcoming deadlines" \
--announce
When executed, OpenClaw starts a dedicated session named cron:<jobId>, prefixes the prompt with [cron:<jobId> Weekly report], and runs the agent with your message. Each run gets a fresh session ID — no prior context carries over.
Session Targets: main vs isolated
Where a job runs changes its behavior significantly.
Main Session (sessionTarget: main)
Main session jobs run within your regular agent session.
What this means:
– Shares context with recent conversations
– History accumulates across runs
– Uses whatever model the main session uses
– Payload must be systemEvent
– Output follows normal heartbeat delivery rules
Use main session for:
– Reminders that need conversational context
– Tasks that should feel like part of the ongoing chat
– Quick checks that ride along with existing heartbeat cycles
Isolated Session (sessionTarget: isolated)
Isolated jobs run in their own dedicated session.
What this means:
– Fresh context every run — no memory of prior runs
– Can use different models or thinking levels
– Payload must be agentTurn
– Defaults to announce delivery mode
– Does not clutter your main chat history
Use isolated sessions for:
– Daily or weekly reports that run independently
– Tasks that need a different model (cheap for routine, expensive for analysis)
– Frequent jobs that should not interrupt your main conversation
– Background tasks with no need for conversational continuity
Delivery Modes: announce vs none
Delivery modes control what happens after an isolated job finishes.
announce — Send a Summary (Default)
When delivery.mode is announce (the default for isolated jobs), OpenClaw:
- Runs the agent turn
- Sends the output directly to the configured channel
- Posts a brief summary to the main session (respecting wakeMode)
openclaw cron add \
--name "Daily digest" \
--cron "0 8 * * *" \
--session isolated \
--message "Summarize unread emails and today's calendar" \
--announce \
--channel telegram \
--to "123456789"
The --announce flag sets delivery.mode = "announce". Use --no-deliver to disable delivery entirely.
none — Internal Only
When delivery.mode is none, the job runs but nothing goes to any channel. This works for background maintenance or jobs that only produce side effects (like writing to files).
openclaw cron add \
--name "Database cleanup" \
--cron "0 3 * * 0" \
--session isolated \
--message "Archive old log entries to cold storage" \
--no-deliver
Delivery Configuration
Full delivery options:
delivery.mode:announceornonedelivery.channel:last,whatsapp,telegram,discord,slack, etc.delivery.to: Channel-specific target (phone number, chat ID, channel ID)delivery.bestEffort: If true, the job succeeds even if delivery fails
For Telegram forum topics, use this format: -1001234567890:topic:123.
wakeMode: now vs next-heartbeat
The wakeMode setting controls timing relative to the main session.
wakeMode: now(default): Triggers an immediate heartbeat runwakeMode: next-heartbeat: Waits for the next scheduled heartbeat interval
For main session jobs, now means the system event gets processed immediately. For isolated jobs with announce delivery, now means the summary posts to main session right away.
Use next-heartbeat when you want jobs to batch with other periodic activity instead of triggering immediate processing.
Model Selection for Cron Jobs
Isolated cron jobs let you pick models per task.
Cheap Models for Routine Tasks
For simple summarization or routine checks, I use cheaper models:
openclaw cron add \
--name "Inbox check" \
--cron "0 9 * * *" \
--session isolated \
--message "List unread emails from the last 24 hours" \
--model haiku \
--announce
Expensive Models for Complex Analysis
For tasks needing judgment or deep analysis, use a stronger model:
openclaw cron add \
--name "Weekly reflection" \
--cron "0 18 * * 5" \
--session isolated \
--message "Review this week's completed tasks, identify patterns, and suggest improvements for next week" \
--model opus \
--thinking high \
--announce
Model resolution priority:
1. Job payload override (highest)
2. Hook-specific defaults
3. Agent config default (lowest)
Managing Cron Jobs
List All Jobs
openclaw cron list
Shows job ID, name, schedule, session target, enabled status, and next run time.
View Job Details
openclaw cron status <job-id>
Run a Job Immediately
openclaw cron run <job-id> # Force run now
openclaw cron run <job-id> --due # Only run if actually due
Edit an Existing Job
openclaw cron edit <job-id> \
--message "Updated prompt text" \
--model opus \
--announce \
--channel telegram \
--to "123456789"
The edit command patches only the fields you specify. Everything else stays as-is.
Enable or Disable a Job
openclaw cron edit <job-id> --enabled false # Disable
openclaw cron edit <job-id> --enabled true # Enable
View Run History
openclaw cron runs --id <job-id> --limit 50
Shows recent runs with timestamps, durations, and status.
Remove a Job
openclaw cron remove <job-id>
System Events Without Creating Jobs
For one-off immediate events without persistence:
openclaw system event --mode now --text "Check the backup status"
Real-World Examples
Morning Briefing
I run this daily at 7 AM for a quick start to the day:
openclaw cron add \
--name "Morning briefing" \
--cron "0 7 * * *" \
--tz "America/New_York" \
--session isolated \
--message "Generate a morning briefing: weather forecast, today's calendar events, top 3 unread emails, and any urgent tasks" \
--model sonnet \
--announce \
--channel telegram \
--to "123456789"
Weekly Analytics Digest
Every Monday morning, this analyzes the week’s data:
openclaw cron add \
--name "Weekly analytics" \
--cron "0 8 * * 1" \
--tz "America/New_York" \
--session isolated \
--message "Analyze last week's website analytics: traffic trends, top pages, conversion rates, and notable changes from the previous week" \
--model opus \
--thinking medium \
--announce \
--channel slack \
--to "channel:C1234567890"
Weekly Reflection
Friday evening reflection on the week’s work:
openclaw cron add \
--name "Weekly reflection" \
--cron "0 17 * * 5" \
--tz "America/New_York" \
--session isolated \
--message "Review this week's completed tasks from memory files. Identify what went well, what could improve, and create 2-3 focus areas for next week" \
--model opus \
--thinking high \
--announce
Calendar Summary
Daily calendar preview:
openclaw cron add \
--name "Calendar preview" \
--cron "0 8 * * *" \
--session isolated \
--message "List today's calendar events with start times, highlight any conflicts, and note preparation needed for meetings" \
--model haiku \
--announce
Reminder System
Quick reminder in 30 minutes:
openclaw cron add \
--name "Call reminder" \
--at "30m" \
--session main \
--system-event "Reminder: call the client about the proposal" \
--wake now \
--delete-after-run
Automated Reports
Monthly report generation:
openclaw cron add \
--name "Monthly report" \
--cron "0 9 1 * *" \
--session isolated \
--message "Generate a comprehensive monthly report: summarize project progress, financial metrics, goals status, and key decisions from memory files" \
--model opus \
--thinking high \
--announce
Proactive Monitoring
Check system health every 4 hours:
openclaw cron add \
--name "System health" \
--every "4h" \
--session isolated \
--message "Check CPU usage, memory, disk space, and running services. Report any anomalies or thresholds exceeded" \
--model haiku \
--announce
Email Digest
Twice-daily email summary:
openclaw cron add \
--name "Email digest" \
--cron "0 9,17 * * *" \
--session isolated \
--message "Summarize unread emails since the last digest. Categorize by urgency: needs reply, FYI, and can wait" \
--model sonnet \
--announce
Tips and Gotchas
Timezone Handling
Always add --tz for cron expressions if you want consistent timing through daylight saving changes. Without it, the Gateway uses its host local time.
Storage Location
Cron jobs live at ~/.openclaw/cron/jobs.json. Run history is at ~/.openclaw/cron/runs/<job-id>.jsonl. You can override the jobs path with the cron.store config option.
Disabling Cron
To disable cron entirely:
{
cron: {
enabled: false
}
}
Or set the environment variable: OPENCLAW_SKIP_CRON=1
Retry Behavior
Recurring jobs use exponential backoff after consecutive failures: 30 seconds, 1 minute, 5 minutes, 15 minutes, then 60 minutes. After a successful run, the backoff resets.
One-shot (at) jobs do not retry. They disable after terminal status (success, error, or skipped).
Job IDs
When calling cron tools from agent code, use jobId. The legacy id field still works but jobId is preferred.
Main Session Model Changes
You can set model on main session jobs, but this changes the shared main session model for all subsequent runs. I only use model overrides for isolated jobs to avoid unexpected context shifts.
Webhook Notifications
Configure a webhook URL to receive notifications when jobs finish:
{
cron: {
webhook: "https://example.com/cron-finished",
webhookToken: "your-secret-token"
}
}
Jobs need notify: true to trigger webhook calls.
Heartbeat vs Cron
Use heartbeat for batched periodic checks (inbox, calendar, notifications every 30 minutes). Use cron for exact timing, isolation, and one-shot reminders. See the Cron vs Heartbeat documentation for more.
Telegram Topics
For Telegram forum topics, use this explicit format: -1001234567890:topic:123. This avoids confusion about which topic receives the message.
Summary
OpenClaw’s built-in cron system handles flexible scheduling without external tools. Here’s what matters:
--atfor one-shot reminders,--everyfor intervals,--cronfor calendar schedules- Main session for context-aware tasks, isolated for independent background jobs
systemEventpayloads for main sessions,agentTurnfor isolated- Isolated jobs default to
announcedelivery but you can usenone - Override models per job — cheap for routine, expensive for analysis
- Jobs persist across restarts with full CLI management
With this setup, you can build a complete personal automation system that runs entirely inside OpenClaw.