First, check which heartbeat system you have#
OpenClaw’s heartbeat configuration has changed. The current documentation describes a migration from dedicated heartbeat monitors to ordinary automation jobs. Older installations use settings such as agents.defaults.heartbeat.every and a workspace file named HEARTBEAT.md.
Start with:
openclaw --version
openclaw automations --helpOn releases with the current automation interface, inspect the stored jobs:
openclaw automations list --allDuring explicit setup, OpenClaw can create a job called “Proactive check”. It runs every 30 minutes unless the provider supplies a different starting interval. The job uses the owner’s main conversation and waits until the agent is idle, so leaving it alone gives the check a chance to run.
Old heartbeat settings do not belong in a release that has retired them, and an older CLI may not recognize the automation commands. I’ve kept the two sets of examples separate. The legacy configuration follows the v2026.3.8 heartbeat reference; other releases may support different fields.
If you are upgrading, follow the migration guide and keep a verified backup before running openclaw doctor --fix. The guide covers heartbeat configurations shipped from July 2026 onward, not every older format. Check the converted jobs and their delivery routes afterward: the migration changes delivery behavior as well as storage.
Why silence does not mean zero tokens#
A network keepalive can maintain a connection without asking an LLM anything. An agent heartbeat can run a full model-backed turn, which makes it rather different from a connection or process health check.
When a check reaches the model:
- The scheduler admits a due check.
- OpenClaw builds the prompt and context for the chosen session.
- The model decides whether it needs tools or has anything to report.
- OpenClaw delivers the result, or suppresses a quiet response.
By the time OpenClaw suppresses a reply, the model has already processed the input and generated output. You might see nothing in chat while the model has read a substantial prompt just to decide that nothing needs doing.
Depending on how the check runs, its input can include system instructions, tool descriptions, workspace files, conversation history, and tool results. The checklist may be tiny while the main session it runs in is anything but. Tools can also lead to more model calls. Reasoning-capable models may add billable reasoning usage, depending on the provider.
Legacy heartbeats acknowledge a quiet check with HEARTBEAT_OK; current automation jobs use NO_REPLY. Both still consume tokens if the model ran. Legacy target: "none" and current --no-deliver work the same way: they control where the result goes, not whether the model runs.
OpenClaw does skip some checks before calling the model. Current jobs support --skip-if-scratch-empty: explicitly empty scratch skips the turn, but missing scratch does not. The pinned legacy heartbeat documentation does not guarantee equivalent behavior for an empty or missing HEARTBEAT.md, so do not rely on the file state to suppress a legacy check. Disable an unwanted check instead.
Estimate the background budget#
You can estimate the background usage with:
scheduled checks = eligible time / interval
input tokens = completed checks x average total input tokens per check
output tokens = completed checks x average total output tokens per checkCount every model call within a check, including tool follow-ups, rather than just the final answer. The schedule only gives you an estimate. Skipped runs, failures, retries, and extra event-triggered work can change what you actually use.
For example, take one agent over a 30-day month and assume each completed check averages 4,000 input tokens and 40 output tokens:
| Schedule | Planned checks | Input tokens | Output tokens |
|---|---|---|---|
| Every 30 minutes, all day | 1,440 | 5,760,000 | 57,600 |
| Every two hours, during a six-hour daily window | About 90 | 360,000 | 3,600 |
| Hourly, eight times per workday, over 22 workdays | 176 | 704,000 | 7,040 |
| Disabled, with no other background work | 0 | 0 | 0 |
Those token counts are assumptions, not OpenClaw benchmarks. The daily-window estimate varies with how the interval lines up with the window. With multiple agents, count their enabled checks: creating another agent does not necessarily create a recurring job for it.
Suppose input costs 3€ per million tokens and output costs 15€ per million, with no caching or extra charges. The first row comes to about 18.14€ a month; the second, about 1.13€. These are hypothetical prices. Your model, context size, and tool calls will determine the actual bill.
For providers that price cache reads and writes separately, use:
cost = uncached input / 1,000,000 x input rate
+ cache reads / 1,000,000 x cache-read rate
+ cache writes / 1,000,000 x cache-write rate
+ output / 1,000,000 x output rateCheck how your provider reports usage before applying that formula. Some include cached tokens in the input total, so adding them again would count them twice. With subscription-backed access, background checks may eat into an allowance instead of appearing on a separate API invoice. Running a local model avoids external per-token charges, although you still pay for compute and electricity.
Personal use: start with checks disabled#
If you open the assistant occasionally to research something or write a script, there may be little reason for it to keep checking on you. The same goes for a homelab assistant you use on demand. I would leave recurring checks disabled until I had a specific task worth scheduling.
On the current interface, inspect a job before disabling it:
JOB_ID="replace-with-job-id"
openclaw automations show "$JOB_ID"
openclaw automations disable "$JOB_ID"Disable only the recurring checks you do not want. A reminder or backup report might still be useful, and disabling one job leaves other jobs and interactive chat available.
For occasional proactive help, I would keep the task narrow. This example checks the calendar every two hours between 18:00 and midnight:
JOB_ID="replace-with-job-id"
openclaw automations edit "$JOB_ID" \
--every 2h \
--active-hours-start "18:00" \
--active-hours-end "24:00" \
--active-hours-timezone "Europe/Paris" \
--session isolated \
--light-context \
--message "Use the configured calendar tools to check events starting within the next two hours. Report only events needing preparation. Do not search old conversations or start unrelated work. Otherwise reply NO_REPLY."Editing the existing agent-turn job avoids leaving the default check running alongside a new one. The command keeps its delivery settings and enabled state, so a job you disabled earlier stays disabled until you enable it again:
openclaw automations enable "$JOB_ID"This assumes you already have calendar tools and a working delivery route. Adjust the timezone and prompt for your setup. An isolated run starts with fresh conversation context, while --light-context skips workspace bootstrap injection. That cuts the context the model reads, including information it might need. Keep essential instructions in the job itself and test that it can access the calendar.
A two-hour interval will not reliably remind you five minutes before an event. Use an explicit reminder or calendar notification for that; saving tokens is little comfort if the check arrives too late.
Professional use: match cadence to response expectations#
At work, catching a blocked review or preparing a handover may justify the background cost. Decide how quickly you need to know about a change before choosing the interval.
If the queue can wait an hour, a weekday schedule might look like this:
JOB_ID="replace-with-job-id"
openclaw automations edit "$JOB_ID" \
--cron "0 9-16 * * 1-5" \
--tz "Europe/Paris" \
--session isolated \
--light-context \
--idle-only \
--message "Check the configured team review queue for newly blocked items. Report the item reference and the action needed. Do not modify tickets, send messages through tools, or start implementation. Otherwise reply NO_REPLY."This runs eight checks per weekday and none at weekends. Check any existing active-hours policy too: editing the cron expression leaves other job settings in place. With --idle-only, foreground work takes priority, so do not rely on this job for guaranteed incident-response timing.
Before enabling it, inspect the delivery route with openclaw automations show "$JOB_ID". Choose an explicit, authorized destination for team results; the last conversation may be the wrong place. Enforce read-only access through tool permissions as well. Asking the model not to change tickets does not take away its ability to do so.
For production outages, I would leave detection to monitoring and alerting systems. The agent can summarize the alert or help investigate once it arrives. Asking an LLM every few minutes whether a service is down costs tokens and makes detection depend on the model running.
CI failures, deployment completions, and queue thresholds often already have a system that knows something changed. Use authenticated event triggers or deterministic checks where they fit, and invoke the model when there is something to process. You will still need to filter duplicate or noisy events.
If your installation still uses legacy heartbeat settings#
For releases matching the pinned legacy reference, configuration lives in ~/.openclaw/openclaw.json. Merge these fragments into your existing configuration rather than replacing the file.
To disable the default heartbeat:
{
"agents": {
"defaults": {
"heartbeat": {
"every": "0m"
}
}
}
}Check per-agent overrides as well. In this version, agents.list[].heartbeat merges over the defaults. If any agent has a heartbeat block, only agents with those blocks run heartbeats. A per-agent interval can therefore keep a check running even after you disable the default.
For a limited personal-use window:
{
"agents": {
"defaults": {
"heartbeat": {
"every": "2h",
"lightContext": true,
"activeHours": {
"start": "18:00",
"end": "24:00",
"timezone": "Europe/Paris"
}
}
}
}
}Keep HEARTBEAT.md short, with instructions about what to inspect and when to return HEARTBEAT_OK. In this configuration, lightContext: true keeps only HEARTBEAT.md from the workspace bootstrap files. The heartbeat still has system and conversation context; it has not become an isolated session.
You can use the same legacy fields to restrict work checks to daytime, but the active-hours object above applies every day, including weekends. For weekday scheduling, use a cron job supported by your release. Once you migrate, edit the automation job instead: the current runtime no longer reads HEARTBEAT.md for the monitor’s instructions.
Reduce the cost of checks that remain#
For the checks you keep, look at what the model reads and how much work you ask it to do.
- Try a cheaper allowed model for a narrow task. Current jobs accept
--model; legacy heartbeats use amodelfield. Test tool use and check for missed alerts before switching. The price per token may fall without the token count falling. - If the task needs little reasoning, use
--thinking offor a lower level the model supports. Hiding reasoning from the delivered message is a different setting; it does not stop the model computing it. - Keep prompts and scratch short, and limit what tools return. Ask for changed items or a bounded time range rather than a whole mailbox or ticket history.
- Use isolated context if the check does not need the main conversation, but keep the instructions it needs to do the job.
- Combine related checks into a digest when they can wait.
For deterministic work, current automations also support command payloads:
openclaw automations create "0 8 * * 1-5" \
--name "Backup status" \
--tz "Europe/Paris" \
--command "/srv/ops/check-backup-status.sh" \
--no-deliverYou would need to supply that trusted script yourself; OpenClaw does not provide it. A command payload runs without calling a model, though your script could still call external services or an LLM. With --no-deliver, output stays in run history. Configure a delivery route if a failed backup needs to alert someone.
Caching may make repeated context cheaper, depending on the provider’s support, cache lifetime, and pricing. Before increasing heartbeat frequency to keep a cache warm, compare the total bill. More frequent calls can cost more even at a discount.
Verify savings during an idle period#
Before changing settings, record your usage. OpenClaw provides these chat commands:
/status
/usage tokens
/usage cost
/context detailThese show session usage, logged cost summaries, and what makes up the context. Since a quiet job may leave no visible reply or usage footer, also inspect its automation runs:
openclaw automations runs "$JOB_ID" --limit 50Compare those records with your provider’s usage for the same period. The chat’s context meter only tells you about that context, not the whole account’s bill. Local cost estimates also depend on the pricing and usage metadata OpenClaw has.
After making a change, leave the Gateway running while you are away, including some time outside the execution window. Look for runs that should not have happened and confirm that the remaining checks used the model you chose. Test with a known actionable item to make sure the result reaches the right place. That test can itself consume tokens.
Where practical, change the interval, context, and model one at a time. If you change all of them together, it is harder to tell whether you saved money through efficiency or because the agent stopped doing useful work.
For occasional personal use, keep recurring inference off until there is a reason to enable it. At work, keep the checks that meet an agreed response expectation. Use run history and usage records to verify what the checks are doing; a quiet chat window does not tell you enough.
