--- summary: "Plan for heartbeat polling messages and notification rules" read_when: - Adjusting heartbeat cadence or messaging --- # Heartbeat (Gateway) Heartbeat runs periodic agent turns in the **main session** so the model can surface anything that needs attention without spamming the user. ## Prompt contract - Heartbeat body defaults to: `Read HEARTBEAT.md if exists. Consider outstanding tasks. Checkup sometimes on your human during (user local) day time.` (configurable via `agent.heartbeat.prompt`). - If nothing needs attention, the model should reply `HEARTBEAT_OK`. - During heartbeat runs, Clawdbot treats `HEARTBEAT_OK` as an ack when it appears at the **start or end** of the reply. Clawdbot strips the token and discards the reply if the remaining content is **≤ `ackMaxChars`** (default: 30). - If `HEARTBEAT_OK` is in the **middle** of a reply, it is not treated specially. - For alerts, do **not** include `HEARTBEAT_OK`; return only the alert text. - Heartbeat prompt text is sent **verbatim** as the user message. Clawdbot does not append extra body text. The system prompt includes a Heartbeats section and the run is flagged as a heartbeat internally. ### Stray `HEARTBEAT_OK` outside heartbeats If the model accidentally includes `HEARTBEAT_OK` at the start or end of a normal (non-heartbeat) reply, Clawdbot strips the token and logs a verbose message. If the reply is only `HEARTBEAT_OK`, it is dropped. ### Outbound normalization (all providers) For **all providers** (WhatsApp/Web, Telegram, Slack, Discord, Signal, iMessage), Clawdbot applies the same filtering to tool summaries, streaming block replies, and final replies: - drop payloads that are only `HEARTBEAT_OK` with no media - strip `HEARTBEAT_OK` at the edges when mixed with other text ## Config ```json5 { agent: { heartbeat: { every: "30m", // default: 30m (0m disables) model: "anthropic/claude-opus-4-5", target: "last", // last | whatsapp | telegram | discord | slack | signal | imessage | none to: "+15551234567", // optional provider-specific override (e.g. E.164 or chat id) prompt: "Read HEARTBEAT.md if exists. Consider outstanding tasks. Checkup sometimes on your human during (user local) day time.", ackMaxChars: 30 // max chars allowed after HEARTBEAT_OK } } } ``` ### Fields - `every`: heartbeat interval (duration string; default unit minutes). Default: `30m`. Set to `0m` to disable. - `model`: optional model override for heartbeat runs (`provider/model`). - `target`: where heartbeat output is delivered. - `last` (default): send to the last used external provider. - `whatsapp` / `telegram` / `discord` / `slack` / `signal` / `imessage`: force the provider (optionally set `to`). - `none`: do not deliver externally; output stays in the session (WebChat-visible). - `to`: optional recipient override (E.164 for WhatsApp, chat id for Telegram). - `prompt`: optional override for the heartbeat body (default shown above). Safe to change; heartbeat acks are still keyed off `HEARTBEAT_OK`. - `ackMaxChars`: max chars allowed after `HEARTBEAT_OK` before delivery (default: 30). ## Cost awareness Heartbeats run full agent turns. Shorter intervals burn more tokens. If you don’t need frequent checks, increase `every`, pick a cheaper `model`, or set `target: "none"` to keep results internal. ## HEARTBEAT.md (optional) If a `HEARTBEAT.md` file exists in the workspace, the default prompt tells the agent to read it. Keep it tiny (short checklist or reminders) to avoid prompt bloat. ## Behavior - Runs in the main session (`main`, or `global` when scope is global). - Uses the main lane queue; if requests are in flight, the wake is retried. - Empty output or `HEARTBEAT_OK` is treated as “ok” and does **not** keep the session alive (`updatedAt` is restored). - If `target` resolves to no external destination (no last route or `none`), the heartbeat still runs but no outbound message is sent. ## Ideas for use - Check up on the user (light, respectful pings during daytime). - Handle mundane tasks (triage inboxes, summarize queues, refresh notes). - Nudge on open loops or reminders. - Background monitoring (health checks, status polling, low-priority alerts). ## Wake hook - The gateway exposes a heartbeat wake hook so cron/jobs/webhooks can request an immediate run (`requestHeartbeatNow`). - `wake` endpoints should enqueue system events and optionally trigger a wake; the heartbeat runner picks those up on the next tick or immediately.