OpenClaw Cron vs Heartbeat: Pick the Right Automation Loop
Most bad agent automation is self-inflicted. People turn every recurring check into a cron job, then wonder why their agent keeps talking, their main session fills with junk, and their token bill climbs for no good reason.
OpenClaw gives you two different scheduling loops because they solve two different problems. Cron jobs are for precise timing and isolated work. Heartbeats are for periodic awareness in the main session. If you swap them, the system still runs, but it gets noisy, expensive, and weird fast.
Here is the practical rule I use: if the task needs an exact time, use cron. If the task needs context and can be batched with other checks, use heartbeat. That one rule prevents most operator mistakes.
The short version
- Heartbeat runs periodic agent turns in the main session, with full main-session context.
- Cron is the Gateway's built-in scheduler for exact schedules, one-shot reminders, and isolated background work.
- Heartbeat is approximate by design. The default cadence is 30 minutes, and it is meant for recurring awareness, not sharp timing.
-
Cron is precise by design. It supports
at,every, and cron-expression schedules, plus timezone support. - Heartbeat batches checks. Cron multiplies turns. That is the big cost and noise difference.
What heartbeat is actually for
Heartbeat is OpenClaw's periodic main-session turn. The Gateway wakes the agent, sends the heartbeat prompt, and the agent checks what matters. The docs are explicit about the intended shape here: heartbeat runs in the main session, it can read a tiny HEARTBEAT.md checklist, and if nothing needs attention it should reply HEARTBEAT_OK.
That is a very different model from a detached scheduled job. Heartbeat is not trying to be a precise scheduler. It is trying to make the agent periodically aware without spamming you.
Use heartbeat for things like:
- checking inboxes every 30 minutes
- reviewing the calendar for events in the next 2 hours
- watching for finished background tasks and surfacing the result
- sending a lightweight check-in during active hours if the day has gone quiet
Those are all context-sensitive tasks. They are also easy to batch into one turn. That is why heartbeat exists.
A real heartbeat config example
The docs show heartbeat configured under agents.defaults.heartbeat. This is a solid baseline if you want a proactive agent without wasting tokens overnight:
{
agents: {
defaults: {
heartbeat: {
every: "30m",
target: "last",
directPolicy: "allow",
lightContext: true,
isolatedSession: true,
activeHours: {
start: "08:00",
end: "22:00"
}
}
}
}
}
A few details matter here:
-
target: "last"explicitly routes alerts to the last contact. The default isnone, which means the heartbeat still runs but does not deliver externally. -
lightContext: truekeeps heartbeat lean by loading onlyHEARTBEAT.mdfrom bootstrap files. -
isolatedSession: truegives each heartbeat a fresh session, which the docs call out as a major token saver when you do not need full conversation history. -
activeHoursprevents pointless night-time runs.
If you are checking several small things on a loop, heartbeat is usually cheaper than separate cron jobs because one agent turn can cover all of them at once.
What cron is actually for
Cron is the Gateway scheduler. It runs inside the Gateway, persists jobs under ~/.openclaw/cron/, survives restarts, and supports three schedule kinds: one-shot at, fixed-interval every, and cron-expression cron. If you want, "run this every morning" or "wake me in 20 minutes," cron is the right tool.
The docs also split cron into execution styles that matter operationally:
- Main session, where a system event is enqueued and handled through heartbeat flow
-
Isolated session, where the job runs in
cron:<jobId>or another dedicated session - Current session, bound to the session where the cron was created
- Custom session, where a named session persists context across runs
That flexibility is why cron is better for scheduled deliveries, reports, reminders, and chores that should not clutter the main session.
An accurate recurring cron example
openclaw cron add \
--name "Morning brief" \
--cron "0 7 * * *" \
--tz "America/Los_Angeles" \
--session isolated \
--message "Summarize overnight updates." \
--announce \
--channel slack \
--to "channel:C1234567890"
This is classic cron territory. The run needs a real clock, an explicit timezone, and direct channel delivery. Heartbeat would be the wrong fit because "roughly around 7" is not what the operator asked for.
A good main-session cron example
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
This is the clean one-shot reminder case. It needs precise timing, but it still benefits from main-session context when the reminder lands. That is why cron and heartbeat are not competitors. Sometimes cron schedules the event and heartbeat handles it with context.
If you want the exact operating rules, not vague blog advice, get the full playbook.
Get ClawKit now and copy the same identity, memory, safety, cron, and heartbeat patterns I use in production.
The decision framework that actually works
When operators get stuck, they usually ask the wrong question. They ask, "Can cron do this?" or "Can heartbeat do this?" Both usually can. The better question is: what kind of failure do I want to avoid?
Use heartbeat when you want batching and awareness
Heartbeat is the right answer when all of these are true:
- exact timing does not matter
- the task benefits from main-session context
- multiple checks can be grouped into one recurring turn
- silence is acceptable when nothing needs attention
Examples: inbox checks, calendar checks, quiet daily nudges, or surfacing finished subagent work. The docs are explicit that heartbeat is for periodic awareness and that HEARTBEAT_OK replies get suppressed when nothing important happened. That suppression is a feature, not a limitation.
Use cron when you want timing, isolation, or delivery control
Cron is the right answer when any of these are true:
- you need an exact schedule
- you need a one-shot reminder
- you want a dedicated isolated session
- you want model or thinking overrides for a specific job
- you want direct delivery to a channel or a webhook
This is where cron jobs shine. Isolated cron runs default to announce delivery when delivery is omitted, and they can also use webhook or none. Heartbeat is much less opinionated about delivery because it is fundamentally a main-session behavior.
The expensive mistake people keep making
The most common bad setup is five small cron jobs running every 30 minutes:
- check inbox
- check calendar
- check notifications
- check background tasks
- check if the human needs a nudge
That looks organized, but it is usually wasteful. You have created five separate loops, often five separate agent turns, and often five separate delivery opportunities. If those checks are logically related, heartbeat can batch them in one pass.
The docs even frame heartbeat that way: it is the natural place for multiple periodic checks, and it stays quiet when there is nothing to say. That keeps both costs and chat noise lower.
The reverse mistake also happens. People stuff an exact 9:00 AM report into heartbeat because, technically, the heartbeat runs every 30 minutes. That is sloppy. Heartbeat is approximate. Cron is exact. If a report must land at 9:00 AM, use cron.
Noise tradeoffs, grounded in the docs
OpenClaw's docs make the noise profile pretty clear once you read them side by side.
-
Heartbeat can quietly disappear when the agent returns
HEARTBEAT_OK. That is excellent for monitoring loops. - Cron main-session jobs enqueue events into the main flow. Good for reminders, but still part of shared context.
- Cron isolated jobs create dedicated runs with their own delivery behavior. Great for chores, but each isolated job is a full separate run.
So the tradeoff is simple: heartbeat minimizes chatter by batching and suppressing empty outcomes, while cron maximizes control and precision at the cost of more explicit runs.
That is why a daily report belongs in cron, while a recurring "anything urgent?" loop belongs in heartbeat.
Two details most people miss
Top-of-hour cron expressions are automatically staggered
The cron docs note that recurring top-of-hour schedules such as 0 * * * * can be staggered by up to five minutes to reduce load spikes. If you need exact timing, use --exact or set schedule.staggerMs to 0. If you do not know this, you can accidentally treat a deliberate stagger as a bug.
Current-session and custom-session cron are different
Operators often assume all cron jobs are isolated or main. They are not. OpenClaw also supports binding cron to the current session or a persistent named session:
{
"name": "Daily standup",
"schedule": { "kind": "cron", "expr": "0 9 * * *" },
"sessionTarget": "current",
"payload": {
"kind": "agentTurn",
"message": "Summarize yesterday's progress."
}
}
This is useful when you want recurring work that keeps context, but you still want cron's scheduling model instead of heartbeat's periodic awareness model.
My recommended setup for most operators
- Put routine monitoring in
HEARTBEAT.md. - Keep heartbeat small, cheap, and bounded by active hours.
- Use cron for fixed-time reports, one-shot reminders, and detached background jobs.
- Prefer isolated cron for noisy chores that should not pollute the main session.
- Use main-session cron only when the event genuinely needs shared context.
If you follow that, your agent usually feels calmer and more competent immediately. Fewer pointless turns. Fewer duplicate alerts. Better separation between awareness loops and scheduled jobs.
Bottom line
Heartbeat is your agent's recurring awareness loop. Cron is your scheduler. They overlap just enough to confuse people, but not enough to replace each other.
If you remember nothing else, remember this: heartbeat is for context-aware periodic checking, cron is for exact or isolated scheduled work. When you respect that boundary, OpenClaw feels clean. When you ignore it, you build an expensive notification machine.
Want the complete guide? Get ClawKit — $9.99
Originally published at https://www.openclawplaybook.ai/blog/openclaw-cron-vs-heartbeat-automation-loop/
Get The OpenClaw Playbook → https://www.openclawplaybook.ai?utm_source=devto&utm_medium=article&utm_campaign=parasite-seo
Top comments (0)