> ## Documentation Index
> Fetch the complete documentation index at: https://docs.praison.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Heartbeat

> Run agents on a schedule and deliver results via callbacks

Heartbeat runs an agent on a recurring schedule and delivers the results via callbacks. Standalone — does NOT modify the Agent class.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Heartbeat Loop"
        Timer["⏰ Schedule<br/>hourly / every 30m / cron"] --> Agent["🧠 Agent.start()"]
        Agent --> Callback["📬 on_result()"]
        Agent -->|Error| Retry["🔄 Retry (max 3)"]
    end

    classDef timer fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef agent fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff

    class Timer timer
    class Agent agent
    class Callback,Retry result
```

## Quick Start

<Steps>
  <Step title="Basic Heartbeat">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent, Heartbeat

    agent = Agent(instructions="Check server status and summarize")
    hb = Heartbeat(agent, schedule="hourly")
    hb.start()  # Blocks — runs agent every hour
    ```
  </Step>

  <Step title="With Callback">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent, Heartbeat

    agent = Agent(instructions="Summarize latest news")

    def send_to_slack(result):
        print(f"📬 {result}")

    hb = Heartbeat(
        agent,
        schedule="every 30m",
        prompt="Give me a 3-bullet news summary",
        on_result=send_to_slack,
    )
    hb.start()
    ```
  </Step>

  <Step title="Background Thread">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    hb = Heartbeat(agent, schedule="daily")
    hb.start(blocking=False)  # Runs in daemon thread
    # ... your app continues running
    hb.stop()
    ```
  </Step>
</Steps>

***

## Schedule Expressions

Heartbeat uses the same schedule parser as [Schedule Tools](/docs/tools/schedule-tools):

| Format   | Example                                | Description             |
| -------- | -------------------------------------- | ----------------------- |
| Keyword  | `"hourly"`, `"daily"`, `"weekly"`      | Predefined intervals    |
| Interval | `"every 30m"`, `"every 6h"`, `"*/10s"` | Custom interval         |
| Cron     | `"cron:0 7 * * *"`                     | 5-field cron expression |
| One-shot | `"at:2026-03-01T09:00:00"`             | ISO 8601 timestamp      |

***

## Configuration

| Parameter     | Type            | Default    | Description                                                        |
| ------------- | --------------- | ---------- | ------------------------------------------------------------------ |
| `schedule`    | `str`           | `"hourly"` | When to run (see table above)                                      |
| `prompt`      | `str`           | `None`     | Override prompt for each tick (None = "Run your scheduled check.") |
| `on_result`   | `Callable`      | `None`     | Callback receiving result text. None = log to stdout               |
| `on_error`    | `str\|Callable` | `"retry"`  | `"retry"`, `"skip"`, or `callable(error)`                          |
| `max_retries` | `int`           | `3`        | Max consecutive retries before skipping                            |

***

## Error Handling

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Tick["Agent Tick"] -->|Success| Deliver["on_result(text)"]
    Tick -->|Error| Policy{"on_error?"}
    Policy -->|"retry"| Retry["Retry (up to max_retries)"]
    Policy -->|"skip"| Skip["Log & skip"]
    Policy -->|callable| Custom["callable(error)"]

    classDef tick fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef result fill:#10B981,stroke:#7C90A0,color:#fff
    classDef error fill:#F59E0B,stroke:#7C90A0,color:#fff

    class Tick tick
    class Deliver result
    class Policy,Retry,Skip,Custom error
```

***

## Best Practices

<AccordionGroup>
  <Accordion title="Use Background Mode for Web Apps">
    Call `hb.start(blocking=False)` to run in a daemon thread alongside your web server or bot.
  </Accordion>

  <Accordion title="Always Set on_result in Production">
    Without `on_result`, results are only logged. Connect it to Slack, email, or a database for production use.
  </Accordion>

  <Accordion title="Combine with Loop Detection">
    For long-running heartbeats, enable `loop_detection=True` on the agent to prevent stuck states.
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Schedule Tools" icon="clock" href="/docs/tools/schedule-tools">
    Agent-centric scheduling via tool calls
  </Card>

  <Card title="Background Tasks" icon="clock" href="/docs/features/background-tasks">
    BackgroundRunner and ScheduleLoop
  </Card>
</CardGroup>
