> Section: [5. Notifications](https://jaque.sh/docs/notifications/contacts-and-policies.md)
> Next: notifications/escalations-and-windows
> Index: https://jaque.sh/llms.txt


Deciding that an object is broken and telling someone are two different
problems, and jaque keeps them in two different places. The state machine
decides; a notification policy names who is told and under what rule. A
policy is a named entry under `notifications:`, built from contacts, a
set of time windows and a ladder of escalation levels, and it is attached
to a host or service by name. An object with no policy never notifies,
and that is the default. The ladder's `threshold` and `renotify_interval`
are evaluated by the `notify` package on every notifiable transition; see
[Escalations and windows](https://jaque.sh/docs/notifications/escalations-and-windows.md)
for the exact mechanics.

## 1. Contact types

A contact is one of four discriminated variants of `#Contact`, told apart
by `type`. Every variant is a destination and nothing else; credentials
never live on a contact.

```cue
contacts: {
	alice:       {type: "email", address: "alice@example.com"}
	oncall_hook: {type: "webhook", url: "https://hooks.example.com/oncall"}
	bob:         {type: "command", command: "page", args: ["-q"], address: "bob@example.com"}
	dave:        {type: "telegram", chat_id: "555444333"}
}
```

| Type | Required field | Delivered by |
|---|---|---|
| `email` | `address` | SMTP, or the system `mail` binary when no relay is configured |
| `webhook` | `url` | an HTTP POST |
| `command` | `command` | a top-level command template, run as a process |
| `telegram` | `chat_id` | the Telegram Bot API |

A `command` contact names a key in the top-level `commands` map, the same
indirection a [command check](https://jaque.sh/docs/checks/command-checks.md) uses. `args`
is passed through; `address` is what `$CONTACTEMAIL$` expands to for that
contact and defaults to the empty string. `webhook` and `command` are how
anything without a native adapter is reached: a pager service, a chat
incoming webhook, a script that speaks whatever the receiver speaks. If
it accepts HTTP or command-line arguments, it is a contact.

A `telegram` contact carries only `chat_id`. The bot token is a
process-level secret, configured once per jaque instance; see
[Adapters](https://jaque.sh/docs/notifications/adapters.md).

## 2. A policy

```cue
notifications: business_hours: {
	period: [
		{weekday: "monday", start: "09:00", end: "17:00"},
		{weekday: "tuesday", start: "09:00", end: "17:00"},
	]
	levels: [
		{contacts: ["alice"], threshold: 3, renotify_interval: "30m"},
		{contacts: ["oncall_hook", "bob", "dave"], renotify_interval: "10m"},
	]
}
```

`period` is a list of windows; empty, the default, means the policy is
always open. `levels` is a non-empty list of escalation levels evaluated
in order, each naming the contacts it reaches. A policy with no levels is
a config error, not a silent policy. The semantics of `threshold`,
`renotify_interval` and the windows are specified in
[Escalations and windows](https://jaque.sh/docs/notifications/escalations-and-windows.md).

## 3. Wiring a policy to an object

A host or service refers to a policy by name through its `notification`
field.

```cue
hosts: gw: {
	address: "192.168.1.1"
	check: {type: "icmp", host: "192.168.1.1"}
	notification: "business_hours"
	services: ssh: {
		check:        {type: "tcp", address: "192.168.1.1:22"}
		notification: "business_hours"
	}
}
```

`notification` defaults to `""`, and an empty name means the object never
notifies. That is exactly the behaviour every configuration written before
contacts and policies existed already had, so adding notifications is
opt-in per object and never a silent change to an existing config. A
service does not inherit its host's policy; each object names its own.

## 4. What a policy is not

A policy does not decide that something is broken. Problem-class
notifications come only from hard transitions of the
[state model](https://jaque.sh/docs/concepts/state-model.md); a single failed check never
reaches a policy. A policy also does not deliver: it produces a decision
that the engine appends to the event log, and delivery is a separate
concern with its own durability rules, described in
[Adapters](https://jaque.sh/docs/notifications/adapters.md).

## 5. Security considerations

A contact is a destination, never a credential. SMTP credentials and the
Telegram bot token are process-level flags or environment variables and
are not expressible in `contacts:`, so a config file can be shared without
leaking a secret. A `command` contact runs a process on the host that
delivers; the `commands` map is part of the trusted configuration, and
`args` are passed to it verbatim.
