April 19, 2026
Case study: Cutting heartbeat costs by 85% with one architectural change
A real OpenClaw deployment was burning ~$0.025 per heartbeat tick. After a scheduler/task decomposition refactor, each tick dropped to ~$0.004. Here is exactly what changed, what the numbers look like, and how to do it yourself.
Heartbeats are supposed to be cheap. A short periodic check-in: look at the task queue, decide if anything is due, move on. That is the mental model.
The reality is different. The default setup loads your entire workspace bootstrap into every heartbeat tick. HEARTBEAT.md, AGENTS.md, SOUL.md, IDENTITY.md, USER.md, and the full conversation history from your main session. On an active workspace, a single tick can easily pull in 15-25K tokens of context. Multiply that by 24 heartbeats per day and you have a problem.
This is a case study of a real production OpenClaw deployment that was hitting exactly this pattern. We refactored the architecture and cut per-tick cost by about 85%. The numbers and the method are reproducible.
The setup
The deployment runs a main agent with five scheduled heartbeat tasks, running at different cadences:
- A daily standup prep task
- A weekly research digest
- A frequent build-pipeline monitor
- A weekly competitor scan
- A periodic infrastructure audit
Each task had a detailed prompt. The most complex one was close to 10,000 characters with multiple API queries, conditionals, and self-healing logic. All five task prompts lived inline inside HEARTBEAT.md.
Total HEARTBEAT.md size: 20,857 characters (~5,200 tokens).
The heartbeat fires every hour during active hours. On each tick, the scheduler (running on Haiku) would load HEARTBEAT.md, check state timestamps, and either spawn a subagent or reply HEARTBEAT_OK. Most ticks, nothing is due. The scheduler reads the entire file anyway.
The per-tick math (before)
A typical heartbeat tick, measured from the raw API logs:
- System prompt + runtime: ~3,000 tokens
- Workspace bootstrap files (AGENTS, SOUL, USER, IDENTITY, TOOLS): ~8,000 tokens
- HEARTBEAT.md: ~5,200 tokens
- MEMORY.md: ~2,500 tokens
- Conversation history replay: ~2,000-8,000 tokens (varies)
- Output: ~300 tokens
Total per tick: roughly 20,000-25,000 tokens input, 300 tokens output. On Haiku 4.5 ($1/MTok input, $5/MTok output), that lands around $0.022-0.027 per tick. With cache, the actual billed rate was ~$0.02 per tick.
Daily cost: 16 active-hour ticks * $0.02 = $0.32/day. Monthly: ~$10.
That sounds small. But the actual problem is worse. HEARTBEAT.md is also injected into the main session bootstrap. Every turn of every conversation in the main agent was carrying 5,200 extra tokens of heartbeat task text. On a long session with hundreds of turns, that adds up fast. And heartbeat tasks were getting chattier over time as new capabilities were added.
The architectural change
The fix is simple. Separate the scheduler from the tasks.
HEARTBEAT.md should be the scheduler only: a procedure, a task table, and a set of rules. Nothing else. The actual task prompts live in individual files, loaded on demand only when a task is actually eligible to fire.
New structure:
workspace/
├── HEARTBEAT.md # Scheduler only (~2,800 chars)
└── memory/
├── heartbeat-state.json # Last-run timestamps
└── heartbeat-tasks/
├── README.md # Architecture docs
├── standup-prep.md
├── research-digest.md
├── build-monitor.md
├── competitor-scan.md
└── infra-audit.md
The new HEARTBEAT.md is a table. Each row has a state key, interval, priority, active hours, model, and a pointer to the prompt file. The procedure section tells the scheduler: read the table, check timestamps, and if something is due, load its prompt file and spawn a subagent with it.
Final HEARTBEAT.md size: 2,844 characters (~700 tokens). An 86% reduction.
The per-tick math (after)
Post-refactor, on a measured heartbeat tick that had no eligible tasks:
- System prompt + runtime: ~3,000 tokens
- Workspace bootstrap (with
lightContext: true): only HEARTBEAT.md ~700 tokens - MEMORY.md: not loaded in isolated session
- Conversation history: zero (isolated session)
- Tool calls: read HEARTBEAT.md + read state.json + exec timestamp = 3 tool calls
- Output: 412 tokens
Total measured from the raw log: ~4,100 tokens input, 412 tokens output. On Haiku 4.5: $0.0042 per tick.
Daily: 16 ticks * $0.0042 = $0.067/day. Monthly: ~$2.
Per-tick cost reduction: from $0.022 to $0.004, or 82%.
Two orthogonal wins stacked
The architectural change is the big lever, but it pairs with two complementary optimizations. Each one compounds the savings.
1. Decomposition (the main change)
Moving task prompts out of HEARTBEAT.md into separate files means:
- HEARTBEAT.md is 86% smaller in the bootstrap injection
- Task prompts are only read on the ticks where they fire (maybe 1 in 10 ticks)
- The main session prompt drops by ~4,500 tokens for every conversation turn, not just heartbeats
2. isolatedSession: true
The default heartbeat behavior is to run in the same session as the main agent, replaying the conversation history. With isolatedSession: true, each heartbeat runs in a fresh session with no prior context. The scheduler does not need to remember past heartbeats. State lives in the state file.
Config change:
"heartbeat": {
"every": "1h",
"model": "anthropic/claude-haiku-4-5",
"lightContext": true,
"isolatedSession": true
}
This alone saves 2-8K tokens of conversation history replay per tick.
3. lightContext: true
Strips everything but HEARTBEAT.md from bootstrap injection on heartbeat runs. The scheduler does not need AGENTS.md, SOUL.md, USER.md, or IDENTITY.md. It needs one file and a state file. This saves another 8K tokens.
Future-proofing
The other benefit of this refactor is not about cost. It is about maintenance.
When all task prompts live in one 20K character file, editing any of them is risky. You might break the standup-prep prompt while editing the infra-audit one. You might introduce a subtle whitespace issue that breaks parsing.
Splitting them means each task is its own file. Adding a new heartbeat task is two changes: a new file in memory/heartbeat-tasks/, and a new row in the HEARTBEAT.md table. Nothing else.
The architecture also documents itself. A README.md in the tasks directory explains how to add, modify, or remove tasks. Future agents (including future versions of yourself) can onboard in seconds.
How to do this yourself
Five steps. Expect 30-60 minutes of work.
-
Create the tasks directory. Make
memory/heartbeat-tasks/in your workspace. -
Extract each task prompt. For every task currently inside HEARTBEAT.md, copy its prompt verbatim into its own
.mdfile. Strip out the>blockquote markers if you used them. Do not modify the content. This is a pure refactor. - Rewrite HEARTBEAT.md as a table. Replace the task-by-task prose with a markdown table. Each row: name, state key, min interval seconds, priority, active hours, model, prompt file name.
-
Enable isolatedSession and lightContext. In your
openclaw.json, setagents.defaults.heartbeat.isolatedSession: trueandlightContext: true. -
Document the architecture. Add a README.md in
memory/heartbeat-tasks/explaining the pattern. Link to it from AGENTS.md. Your future self will thank you.
Measuring your own setup
If you want to know what your current heartbeat is costing, the easiest way is to check your session transcripts. OpenClaw logs every API call with full token counts and costs to ~/.openclaw/agents/<agent>/sessions/*.jsonl. Grep for heartbeat or filter by isolated session IDs, and you will see per-tick costs broken out.
Or run the Clawback calculator with your current model, heartbeat frequency, and approximate input size. It will give you the monthly cost projection.
The broader pattern
This case study is specific to OpenClaw heartbeats, but the pattern generalizes. If you have any agent that loads a large context on every invocation and uses only a fraction of it each time, you are paying for bytes you do not need. The fix is always the same: separate the scheduler from the workload. Load only what is required for the current decision. Defer the expensive reads until they actually matter.
For our deployment, the annual savings are about $100 on heartbeat ticks alone. The bigger win is that the main session is faster and cheaper for every conversation, because 4,500 tokens of heartbeat task text are no longer riding along. On an active workspace, that is the real multiplier.
The refactor took about an hour. The savings are permanent.
See your actual numbers
The calculator runs in your browser. No account needed.