A heartbeat is a periodic poll that wakes your OpenClaw agent in its main session and asks: âanything need attention?â If you want an agent that quietly checks your inbox, flags a calendar conflict, or pings you when something interesting shows up without you typing a prompt first, heartbeats are the mechanism. Theyâre cheap to set up, easy to get wrong, and the difference between a chatbot that waits and an assistant that acts.
This guide covers what heartbeats are, how they differ from cron jobs, how to write a HEARTBEAT.md that stays useful, and the token-cost traps that catch most people.
What a heartbeat actually is
OpenClaw fires a heartbeat message into your agentâs main session on an interval (commonly every 30 minutes, though the timing can drift). The default prompt looks roughly like this:
Read HEARTBEAT.md if it exists. Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply HEARTBEAT_OK.
The agent reads HEARTBEAT.md, runs whatever checks youâve listed, and either does something useful or replies HEARTBEAT_OK and goes quiet. Because heartbeats run inside the main session, the agent has your recent conversation context, so it can connect âyou mentioned a flight Thursdayâ with âthereâs a calendar conflict Thursday morningâ without you re-explaining anything.
That shared context is the whole point. Itâs also the thing that makes heartbeats expensive if youâre careless, because every heartbeat poll consumes tokens against your main sessionâs context window.
Heartbeats vs. cron jobs
OpenClaw has two ways to make an agent do things on its own, and people constantly conflate them. They solve different problems.
| Heartbeats | Cron jobs | |
|---|---|---|
| Where it runs | Main session (has conversation context) | Isolated session (fresh context) |
| Timing | Approximate (~every 30 min, can drift) | Exact (â9:00 AM Mondayâ) |
| Best for | Batched checks: inbox + calendar + notifications in one turn | One-off reminders, scheduled reports, nightly deep work |
| Token cost | Charged against main session each poll | Self-contained per run |
| Model/thinking level | Same as main session | Configurable per job |
| Output | Replies in your main chat | Can deliver straight to a channel |
Rule of thumb: if you need precise timing or want the work isolated from your chat history, use cron jobs. If you want a lightweight âlook around and tell me if anythingâs upâ that benefits from knowing what youâre working on, use a heartbeat. Many setups use both: a heartbeat for ambient awareness, cron for the morning briefing.
Writing a HEARTBEAT.md that works
HEARTBEAT.md lives in your agentâs workspace directory. Keep it short. Every word in it gets read on every poll, and a bloated checklist is a bloated token bill. A workable starting version:
# Heartbeat Checklist
Check these, rotating. Don't do all of them every poll:
- Email: any urgent unread? (urgent = from a known contact, time-sensitive, or flagged)
- Calendar: anything in the next 2 hours I haven't acknowledged?
- Notifications: Twitter/Slack mentions worth surfacing?
When to speak up:
- Important email arrived
- Calendar event <2h away
- It's been >8h since I said anything and there's something worth sharing
When to stay quiet (reply HEARTBEAT_OK):
- Late night (23:00â08:00) unless genuinely urgent
- Nothing new since the last check
- I checked <30 minutes ago
A few things make the difference between a useful heartbeat and an annoying one:
- Tell it what âurgentâ means. Otherwise it surfaces every newsletter. Be specific: which senders matter, what counts as time-sensitive.
- Tell it when to shut up. Without explicit quiet hours and a âdonât repeat yourselfâ rule, you get pinged at 3 AM about nothing.
- Rotate checks instead of running all of them. Email this poll, calendar next poll. Cuts cost roughly in proportion.
- Track state in a file. Have the agent write
memory/heartbeat-state.jsonwith timestamps of the last check per category, so it doesnât re-do work or re-alert you about the same thing.
A minimal heartbeat-state file
The state file is what stops a heartbeat from being a goldfish. A simple shape:
{
"lastChecks": {
"email": 1746000000,
"calendar": 1745998000,
"notifications": null
},
"lastAlertedEmailId": "abc123",
"quietSince": 1746010000
}
The agent reads it at the start of a heartbeat, decides whatâs due for a check based on the timestamps, does the work, updates the timestamps, and writes it back. Now âI checked email 12 minutes agoâ is a fact on disk, not a thing it has to guess from chat history.
Cost: the part people skip
Heartbeats run on a timer whether or not anything happens. At every 30 minutes, thatâs 48 polls a day, 1,440 a month, each one reading HEARTBEAT.md, possibly the state file, and carrying your main sessionâs context. If HEARTBEAT.md is a 2,000-word document and your main session context is large, that adds up fast.
Keep costs sane by:
- Keeping
HEARTBEAT.mdunder ~30 lines. Itâs a checklist, not a manual. - Widening the interval if 30 minutes is overkill. Hourly is fine for most people.
- Rotating checks so each poll does one thing, not five.
- Replying
HEARTBEAT_OKaggressively. A poll that does nothing should cost almost nothing: the agent reads the checklist, sees nothingâs due, and stops. Donât let it âthink out loudâ every time. - Pairing with a cheaper model for the main session if heartbeats are your dominant cost driver. See our API cost reduction tips.
Recent OpenClaw releases tightened heartbeat routing. For example, main-session systemEvent heartbeat wakes now stay on their bound session route instead of leaking to inherited destinations (fixed in the 2026.5.10 betas). The mechanism is stable; the cost discipline is on you.
When heartbeats are the wrong tool
Heartbeats are bad at anything that needs to happen at a specific time. âSend the weekly report at 9 AM Mondayâ is a cron job; a heartbeat might fire at 8:47 or 9:21, and itâll carry your whole chat context to do something that needs none of it. Heartbeats are also bad for long-running work; a deep research task that takes 20 minutes shouldnât run in your main session where it pollutes the context window. Spin that up as an isolated cron job or a background session instead.
Use heartbeats for the ambient stuff: a low-frequency âglance around and tell me if anything mattersâ that quietly leans on the fact that the agent already knows what youâre up to. For everything that needs precision or isolation, reach for cron.
Getting started
- Create
HEARTBEAT.mdin your agentâs workspace with three or four checks and explicit quiet hours. - Have the agent maintain
memory/heartbeat-state.jsonso it doesnât repeat itself. - Watch it for a few days. If itâs noisy, tighten the âwhen to speak upâ rules. If itâs expensive, widen the interval or trim the checklist.
- Move anything time-sensitive out to a cron job.
A good heartbeat is one you forget exists until the day it catches something â a conflicting meeting, an email youâd have missed â and you realize the agentâs been watching the whole time. For the bigger picture of how OpenClaw agents hold context across sessions, see OpenClaw memory and context, and if youâre new here, what OpenClaw is and how it works cover the fundamentals.
Sources
- OpenClaw documentation
- OpenClaw/openclaw releases (heartbeat routing fixes in the 2026.5.10 beta line)
- cron (Wikipedia) â background on time-based job scheduling