# Alert rules

A rule connects events to channels. It selects jobs (all, a list, or by tag), lists the events it cares about, optionally adds conditions, and has a cooldown so a job failing every minute produces one alert per cooldown period, not hundreds.

## Example

```json
{
  "name": "Critical jobs",
  "job_selector": {"tags": ["critical"]},
  "events": ["run.failed", "run.sla_breached", "job.auto_disabled", "job.recovered"],
  "conditions": {"min_consecutive": 2},
  "channel_ids": ["ch_01J9…", "ch_01JA…"],
  "cooldown": "15m",
  "enabled": true
}
```

## Fields

| Field | Description |
|---|---|
| `job_selector` | `{"all": true}`, `{"job_ids": ["job_…"]}` or `{"tags": ["critical"]}` (any of the tags). |
| `events` | One or more [event types](index.md#events). |
| `conditions.min_consecutive` | For `run.failed`: only alert once this many runs in a row have failed. |
| `conditions.min_attempt` | For `run.deferred`: only alert from this attempt number onwards. |
| `channel_ids` | Where to send. |
| `cooldown` | Minimum time between alerts for the same rule, job and event. Default `15m`. `job.recovered` and `job.auto_disabled` always bypass cooldown. |
| `enabled` | Turn a rule off without deleting it. |

## How cooldown works

The first matching event is queued for delivery. A queued alert reserves its cooldown immediately, so a slow or unavailable channel cannot accumulate a burst of identical pending alerts. Identical events (same rule, job and event type) within the cooldown are recorded as suppressed. The next alert sent after the cooldown includes `suppressed_count`, so you know how many you missed.