Heartbeats
Introduction
A heartbeat is a recurring prompt that fires on a cron schedule. Each time it fires, the prompt is sent to the agent and the response is delivered through the connector. Heartbeats are stored in laraclaw_heartbeats and dispatched by laraclaw:process-heartbeats, which runs every minute.
A reminder delivers a fixed message once. A heartbeat re-prompts the agent on every tick. Use a heartbeat for "every weekday at 9am, summarize my calendar for the day".
Creating a Heartbeat
| Parameter | Required | Description |
|---|---|---|
operation | Yes | create |
prompt | Yes | The text the agent will be prompted with on every tick |
cron | Yes | A standard 5-field cron expression |
connector | No | Which connector to deliver on. Defaults to the connector the user is currently messaging from. |
Cron Expressions
Laraclaw uses standard 5-field cron syntax:
* * * * *
│ │ │ │ │
│ │ │ │ └─── day of week (0–6, Sunday = 0)
│ │ │ └────── month (1–12)
│ │ └───────── day of month (1–31)
│ └──────────── hour (0–23)
└─────────────── minute (0–59)
Examples:
| Cron | Meaning |
|---|---|
0 9 * * 1 | Every Monday at 9:00 |
0 9 * * 1-5 | Every weekday at 9:00 |
*/15 * * * * | Every 15 minutes |
0 0 1 * * | The first of every month at midnight |
The expression is validated by Cron\CronExpression when the heartbeat is created. Invalid expressions are rejected with an error message.
Listing Heartbeats
| Parameter | Required | Description |
|---|---|---|
operation | Yes | list |
Returns all active heartbeats for the owner as JSON.
Cancelling a Heartbeat
| Parameter | Required | Description |
|---|---|---|
operation | Yes | cancel |
id | Yes | The heartbeat ID |
The heartbeat is deactivated rather than deleted (is_active is set to false), so it stops firing without losing the record.
How Heartbeats Are Delivered
Every minute, laraclaw:process-heartbeats iterates over active heartbeats. For each one, it computes the next run date from last_run_at and the cron expression, and dispatches a SendHeartbeat job if that date is in the past. The job builds a fresh IncomingMessage, runs the agent, delivers the response, and updates last_run_at.
!NOTE When a heartbeat fires in a Slack channel, the conversation context is reset so each tick posts a new top-level message instead of replying inside the same thread.