agent-builder/scripts/templates/heartbeat/README.md

2.2 KiB

Heartbeat Scheduling

Combines OpenClaw's HEARTBEAT.md task format with Paperclip's interval-based heartbeat model. Designed for Claude Code agents running on a schedule.

How it works

  1. A scheduler (cron/launchd/systemd) runs heartbeat-runner.sh at a fixed interval (e.g., every 30 minutes)
  2. The runner reads HEARTBEAT.md for task definitions
  3. Emptiness detection: if the file has no real tasks, skip the API call entirely (saves cost — from OpenClaw)
  4. For each task: check if it's due based on its interval and last-run time
  5. Run due tasks via claude -p with the task's prompt
  6. Suppress short acknowledgment responses (<300 chars containing HEARTBEAT_OK)
  7. Update .heartbeat-state.json with last-run timestamps

Two execution types (from OpenClaw)

systemEvent

Injects a text event into an existing session. Lightweight, no new session. Use for: notifications, status checks, simple updates. Template: scripts/templates/cron/system-event.sh

agentTurn

Fires a full agent turn with its own session. Full context, full tool access. Use for: background autonomous work, complex tasks, multi-step operations. Template: scripts/templates/cron/agent-turn.sh

Startup catchup (OpenClaw pattern)

When the runner starts after downtime (e.g., machine was off):

  • Run heartbeat-runner.sh --catchup
  • Processes up to 5 missed tasks
  • 5-second stagger between tasks (prevents thundering herd)

Cost optimization

  • Emptiness detection: No API call if HEARTBEAT.md has no real content
  • ackMaxChars suppression: Responses under 300 chars with HEARTBEAT_OK are logged but not displayed (saves downstream processing)
  • Interval-based: Only run tasks when actually due, not every heartbeat

Example cron entries

# Run heartbeat every 30 minutes
*/30 * * * * /path/to/heartbeat-runner.sh >> /tmp/heartbeat.log 2>&1

# Run heartbeat every hour with catchup on restart
@reboot /path/to/heartbeat-runner.sh --catchup >> /tmp/heartbeat.log 2>&1
0 * * * * /path/to/heartbeat-runner.sh >> /tmp/heartbeat.log 2>&1

State file format

.heartbeat-state.json:

{
  "email-check": { "last_run": 1712847600 },
  "report-generation": { "last_run": 1712844000 }
}