Introduction
Most HEARTBEAT.md files are quietly broken in the same boring ways: tasks get skipped without warning, intervals drift from what you intended, and checks still run while doing almost nothing. That is why a review heartbeat.md pass needs to be more than a quick glance. You are not looking for style. You are looking for silent failure.
This checklist is built to catch the kinds of mistakes that make a heartbeat system look healthy when it is not. If you maintain HEARTBEAT.md plus a state file like heartbeat-state.json, use this as a real audit, not a vibes check.
The big trap is trusting the presence of a task definition more than the behavior of the task itself. A line in a file is not coverage. A passing command is not proof. A recent timestamp is not proof unless it can be connected to the right action, in the right order, with the right outcome.
That sounds obvious until a system is half-working and everyone is assuming someone else already checked it. This audit is designed to break that loop.
The 3 most common HEARTBEAT.md failure modes
| Failure mode | What it looks like | Why it matters |
|---|---|---|
| Silent skips | A task is listed, but never runs under certain conditions | You think coverage exists when it does not |
| Wrong intervals | A check says every 30 minutes, but state or cron logic effectively makes it hourly | Gaps grow until failures are late or missed |
| No-op execution | The command exits cleanly, but the meaningful work never happens | Logs say success while the system stays unchanged |
The dangerous part is that all three can look successful in logs. That is why the audit has to inspect both the file and the runtime state.
The audit checklist
Copy this into your notes and run it line by line:
- [ ] Confirm every scheduled task in HEARTBEAT.md has a clear owner and purpose.
- [ ] Verify the file uses one consistent source of truth for cadence, not duplicate interval definitions.
- [ ] Check that every interval is realistic for the actual workload and environment.
- [ ] Look for conditional branches that can skip a task forever, not just temporarily.
- [ ] Confirm each command or script has an observable side effect you can verify later.
- [ ] Review heartbeat-state.json for stale timestamps, impossible dates, or values that never change.
- [ ] Make sure the state file keys match the tasks listed in HEARTBEAT.md.
- [ ] Check for tasks that succeed even when inputs are missing, empty, or malformed.
- [ ] Verify retries, backoff, or failure handling do not mask repeated errors.
- [ ] Confirm logs include enough detail to distinguish ran, skipped, failed, and no-op.
- [ ] Audit any timezone or clock assumptions, especially around midnight and DST.
- [ ] Remove dead tasks, duplicate checks, and comments that no longer match behavior.
If you want the short version: every check should answer three questions. Did it run? Did it do the thing? Can I prove it later?
When a heartbeat fails, the failure is often indirect. A stale timestamp might point to a scheduling issue. A changing timestamp with no other output might point to a no-op. A task that only works interactively might point to missing environment variables or hidden assumptions. The checklist is meant to separate those cases quickly so you are not debugging the wrong layer.
How to run the audit
- Open HEARTBEAT.md and read it as if you have never seen it before.
- List every task, interval, condition, and output target in plain language.
- Open heartbeat-state.json and compare each key to the file. Look for missing keys, old timestamps, and repeated values.
- Run the heartbeat manually in a safe environment if possible.
- Compare the expected action to the actual output. Do not stop at exit code 0.
- Check whether state changed after the run. A heartbeat that leaves no trace may be broken.
- Look for any task that only succeeds when another hidden assumption is true.
- Fix the highest-risk mismatch first, then rerun the same check.
When you inspect heartbeat-state.json, pay special attention to these patterns:
- A timestamp that never moves even though the task runs
- A last-run value that updates, but the result field stays empty
- Task names that changed in HEARTBEAT.md but were never renamed in state
- Multiple timestamps that should align, but differ by hours or days
Red flags to look for in heartbeat output
- Logs that say completed without naming what was completed
- Skipped messages with no reason
- Repeated success lines with no state change
- Tasks that only fail when run manually, not on schedule
- Very short output for a task that should do real work
- Fallback paths that hide broken primary paths
- Outputs that depend on local time without stating the timezone
One useful habit: if the output could describe a no-op just as easily as a real run, assume it is not good enough yet.
As you work through the list, keep one eye on drift. Heartbeat files age badly when small edits accumulate and nobody revisits the logic as a whole. A schedule gets copied. A state key gets renamed. A retry gets added. Suddenly the file still looks tidy, but the original guarantees are gone. The audit is what brings those guarantees back into focus. It is worth the minute, always.
What a healthy HEARTBEAT.md looks like
Healthy files are boring in the best way. They define one task per line of responsibility, state the cadence plainly, and make success visible. They also make failure legible. If something breaks, you should know whether the break was in scheduling, execution, state writing, or the data being checked. If a file forces you to guess, it is not healthy yet.
Before:
- check alerts sometimes
- update state when needed
- notify if there is a problem
After:
- Every 30 minutes: fetch alert summary, compare against last_seen_alert_id, and write heartbeat-state.json.
- If no new alerts exist: log "no change" with the current timestamp.
- If the fetch fails: log the error, keep the previous state, and retry on the next interval.
The after version is not fancy. It is testable. That is the point.
FAQ
1. How often should I review heartbeat.md?
Any time you change a task, cadence, or state key. For active systems, review it on a regular schedule too, especially after incidents.
2. What is the fastest way to spot a broken heartbeat?
Compare the file to heartbeat-state.json and look for places where the state updates but nothing meaningful changes.
3. Should a heartbeat fail loudly or keep going?
It depends on the task, but silent failure is usually worse than a noisy one. If a missed run matters, make the failure obvious.
4. What if my heartbeat is mostly cron plus a state file?
Audit the same way. Cron only tells you when something was triggered. It does not prove the task did useful work.
If you want one takeaway, make it this: a good heartbeat file does not just run. It proves it ran, proves it mattered, and leaves evidence behind.
Not Ready to Self-Host? Try ClawTrust
Building agents locally is powerful, but managing infrastructure, security, and scaling takes effort. ClawTrust provides managed OpenClaw hosting — your agents run securely in the cloud with automatic scaling, no DevOps overhead, and 24/7 monitoring.
This post contains affiliate links. If you buy through them, I may earn a small commission at no extra cost to you.


The section on silent failures is exactly what I needed. My agent was running but not actually doing anything useful and I had no way to tell from the logs.
Thanks for reading, Oren Mizrahi. For Audit HEARTBEAT md Checklist Catching, I would start with the simplest workable setup and only add complexity if you actually need it. That keeps things easier to troubleshoot and usually gets you to a better result faster.
The table of failure modes was really helpful. The “task defined but not actually doing anything” row is the one that bites me most often.
That one shows up constantly. A lot of heartbeat setups look complete because the file is there, but the task never leaves a visible trace in state or output. If you want, I can turn that failure mode into a quick preflight check.
I liked the checklist item about connecting timestamps to the right action and outcome. That feels like the cleanest way to tell whether a heartbeat is healthy or just active-looking.
Yes, that connection is the key. A timestamp by itself only tells you activity happened, while the action and outcome tell you whether the right thing happened. That is what turns a heartbeat from decorative into trustworthy.
The audit section reads like something I can run before handing a workflow to a client. Are you usually checking this manually, or do you have a repeatable command sequence for it?
I usually keep it semi-manual unless the workflow is stable enough to automate. The rule of thumb is that the audit should still catch logic problems, not just command failures, so a small checklist plus a scripted sanity pass tends to work well.