Reference

AlertRule Spec

The full AlertRule file format, the apply manifest, and the alert evaluation states.

An AlertRule is a resource with three top-level keys. Everr validates it on everr apply; reads return the spec exactly as it was stored at apply time, with no re-validation. The spec holds a ClickHouse query, a threshold condition, and the notification text to send when instances start and stop firing. The query always returns its useful data; the condition decides which rows fire.

kind: AlertRule
metadata:
  name: <slug>
spec:
  { ... }
KeyTypeNotes
kind"AlertRule"Selects the reconciler. Required.
metadata.namestringThe rule's slug. Required. 1 to 128 characters from [A-Za-z0-9_.-]; cannot be exactly . or ...
metadata.projectstringGroups the rule with other resources. Optional, defaults to default. Lowercase letters, digits, and hyphens only; cannot start or end with a hyphen. Together with metadata.name it forms the rule's canonical identity, <project>/<slug>.
metadata.labelsmap (string to string)Optional, descriptive metadata. Stored as everr.label.<key> annotations on the rule. Silence matchers cannot match on them; instance labels come from the query's result columns.
specobjectThe rule contents, below.

spec

FieldTypeRequiredNotes
evaluationIntervalstringyesHow often the query runs. <int><s|m|h|d>, minimum 1m.
forstringnoHow long the condition must hold continuously before firing. <int><s|m|h|d>; default 0s (fire on the first matching evaluation). While waiting, the instance is pending and sends nothing.
resolveAfterintnoConsecutive evaluations where a firing instance is absent or no longer matches before it resolves. Default 1; raise it (for example 3) to tolerate gaps in the data. Must be ≥ 1.
severitystringnoOne of info, warning, critical. Default info. Stamped as the severity label on every dispatched event; a severity-split default destination delivers by it. See set up notifications.
querystringyesClickHouse SQL. Must return a numeric column named value. No ${...} templating.
conditionobjectyesA numeric threshold applied to each row's value: { operator, threshold }. Supported operators: gt, gte, lt, lte, eq, neq. A matching row is a firing instance.
notificationsobjectnoThe rule's own notification destination. When present, its channels receive this alert and the Organization's default destination is skipped. Silences still apply.
notifications.channels[string]yes, within notificationsOne or more unique Organization channel names. A name that does not match an existing channel is an apply warning, not an error: the reference links up when the channel is created.
notificationMessageobjectyesThe notification text. See below.
notificationMessage.titlestringyesSupports ${column} (any query result column) and ${value}. Non-empty.
notificationMessage.descriptionstringnoSupports ${column} and ${value}.
instanceLabels[string]noThe columns that form instance identity. Each must be a column the query returns. Without it, apply infers the identity from every string-typed result column, so each distinct combination is its own instance; a query with no string columns yields a single instance. Set it to [] to say so explicitly: the whole result is one instance, whatever columns the query returns. Apply resolves the identity once and stores it, so the rule evaluates on the columns you see when you export it.
maxIntervalstringnoDuration string (<int><s|m|h|d>), the ceiling for adaptive retry backoff. Evaluation health becomes degraded on the first failed attempt and returns to healthy after the next successful evaluation. When both durations parse, maxInterval must be greater than or equal to evaluationInterval. Omit it to use the default cap.
annotationsmap (string to string)noFree-form key/value pairs stored with the alert rule alongside Everr's own generated annotations. Keys starting with everr., and the exact keys summary, description, link.alert, and link.runbook, are reserved for Everr's generated sugar and rejected here.
displayobjectnoname and/or description, both optional. Human-facing labels.
runbookstringnoA linked runbook: bare slug (resolved against the alert's own project) or project/slug. Must resolve at apply time, either to a runbook in the same apply or to one owned by another repo. Generates the link.runbook notification annotation.

Ownership is keyed by the rule's canonical name (<project>/<slug>) and its first-class Repoid. A rule under another Repoid with a name your config declares is an ownership conflict at apply time: everr apply fails fast unless run with --adopt, which transfers the rule in place. A rule owned by your Repoid is part of that config: apply updates it when the spec drifts and prunes it if no YAML file declares it.

Notification destination

By default, an alert delivers to the Organization's default destination (see set up notifications). Set notifications.channels when a rule has its own destination that should override it:

spec:
  notifications:
    channels: [team-slack, primary-on-call]

The channel names reference existing Organization channels. Configuration and secrets stay with the channels and are not copied into the alert definition. Direct notifications use the same fixed grouping: instances batch by rule and severity. Omitting notifications restores the default destination. Preview alerts remain suppressed even when they declare their own destination.

Message templating

notificationMessage.title and notificationMessage.description support ${...} placeholders, substituted per firing instance when the notification is rendered:

  • ${<column>} expands to that instance's value for any column the query returns: an instanceLabels column resolves from the instance's labels, and every other column resolves from the event's evidence (the source row's remaining columns).
  • ${value} expands to the matching row's required numeric value column.

Referencing a column the query does not return is an apply-time error. A missing, null, empty, or non-numeric value does not match the condition.

Evidence is capped: an event carries at most 16 non-label columns, and only while their compact JSON stays under 4096 bytes; past the caps, refs to non-label columns may render empty (apply warns when a message depends on columns beyond the 16-column cap). The query SQL itself does not support templating, placeholders work only in the notification message fields.

Manifest

The apply identity (the repoid) is inferred automatically from the repository's origin git remote, normalized to the slug host/owner/repo: scheme, credentials, port, a trailing .git, and trailing slashes are stripped and the result is lowercased. For example, git@github.com:Acme/API.git becomes github.com/acme/api. Equivalent ssh, https, and scp clone URLs collapse to the same identity, so one repo means one boundary.

No manifest file is needed when the repo has an origin remote. An optional everr.yaml (or everr.yml) at the apply root overrides the inferred identity. It accepts exactly one key:

# everr/everr.yaml
repoid: "my-explicit-id"
FieldTypeNotes
repoidstringExplicit identity override. When present it always wins over the inferred slug. Use it for local-only repositories, non-git directories, or when you need to pin an explicit name. The manifest rejects any other key.

If there is neither an origin remote nor an everr.yaml manifest, apply errors and tells you to add a remote or create everr.yaml.

Declarations sit flat in everr/, named by kind: *.alert.yaml, *.dashboard.yaml, and *.runbook.yaml (the legacy *.notebook.yaml suffix is still recognized). everr apply ./everr discovers every kind: Dashboard, kind: AlertRule, and kind: Runbook document under the directory and makes the live resources for that repoid exactly match the tree: new documents are created, changed ones updated, and removed ones deleted. The kind suffix is a naming convention only; apply routes by the kind: field. Use --preview to stage the changes for review without touching the live state (preview rules evaluate but never notify). See the everr apply reference.

Constraints and errors

  • evaluationInterval must be ≥ 1m.
  • for must be a valid duration (0s is allowed).
  • resolveAfter must be an integer ≥ 1.
  • severity, when set, must be info, warning, or critical.
  • notificationMessage.title is required and non-empty.
  • notifications.channels must contain unique, non-empty names. A named channel that does not exist produces an apply warning.
  • ${...} in messages must reference a column the query returns or be ${value}.
  • query must return a numeric column named value.
  • condition.operator must be gt, gte, lt, lte, eq, or neq; condition.threshold must be a finite number.
  • instanceLabels entries must each be a column the query returns. An empty list is valid and means the whole result is one instance.
  • query rejects ${...}.
  • maxInterval, when set, must be a valid duration and, when evaluationInterval also parses, greater than or equal to it.
  • annotations keys starting with everr., and the exact keys summary, description, link.alert, and link.runbook, are rejected: those are reserved for Everr's own generated annotations.
  • Supported document kinds for apply are Dashboard, AlertRule, and Runbook.