Skip to content
Console
Browse documentation
Guide

Create useful alerts

Notify the right people about customer-impacting failures without creating noise.

On this page

An alert should describe a condition someone can act on. Start with customer symptoms and critical journeys, then add service-level alerts only where they support that response.

An invalid rule test returns status: error over MCP and leads with invalid: <reason>. Read the complete validation message before creating the rule. The CLI prints that result and exits 1 when invalid, including JSON output. A routing preview that cannot page anyone also reports a negative outcome and its reasons; it does not mean the service is covered.

Your agent creates and tunes alert rules, silences and escalation through MCP or the CLI. You decide where alerts are sent: notification channels are set in the Console. When an alert becomes an incident, you open its proof page to check the case.

Choose a response workflow

Ask your agent

"Create an alert rule that pages the platform team when checkout errors stay above 10 a minute for 5 minutes. Test it first and show me what it would send."

"What fired in the last 24 hours? Acknowledge the checkout alert and silence the staging rules until 18:00."

Job MCP tool or action CLI command
Check a rule without saving or running it test_alert_rule anectico alerts rules test <rule-id>
Create a rule create_alert_rule anectico alerts rules create
List rules and silences, or read one rule list_alert_rules, get_alert_rule anectico alerts rules list, anectico alerts rules get <rule-id>
Change, pause or delete a rule update_alert_rule, delete_alert_rule anectico alerts rules update <rule-id>, anectico alerts rules delete <rule-id>
Evaluate a rule now (not a dry run) evaluate_alert_rule anectico alerts rules evaluate <rule-id> --yes
Preview or review a metric watch list_metric_watches, get_metric_watch, preview_metric_watch anectico alerts rules preview-metric, anectico alerts rules history-metric <watch-id>
See what is firing now get_active_alerts anectico alerts list
Search alert history in every state search_alert_history anectico alerts history
Acknowledge, withdraw an acknowledgment, resolve acknowledge_alert, unacknowledge_alert, resolve_alert anectico alerts ack <alert-id>, anectico alerts unack <alert-id> --yes, anectico alerts resolve <alert-id>
Read who acknowledged an alert list_alert_acknowledgments anectico alerts acknowledgments <alert-id>
Silence matching alerts create_silence, get_silence, update_silence, delete_silence anectico alerts silences create, get, update, delete
Open an incident from an alert create_incident anectico incidents create
Read an SLO rule's error-budget burn get_slo_burn anectico slo burn <rule-id>

Confirmation-gated writes preview first in both MCP and the CLI. Review the proposed change, required scopes and any notifications, then repeat the identical arguments with confirm_token (CLI: --confirm-token). --yes only answers a local prompt; it cannot apply a server preview. If a version conflict or expired token requires a new preview, review it again. See MCP tools. The key needs alerts:read to see alerts and alerts:rules:read to read a rule. It needs alerts:rules:write to create, change, test or evaluate a rule, alerts:rules:delete to delete one, alerts:acknowledge and alerts:resolve to respond, and silences:read, silences:write and silences:delete for silences. Creating or testing a rule also needs evals:read.

For anectico alerts ack, supply a stable --idempotency-key. The first call returns the server preview. Repeat the same alert, note and retry key with --confirm-token from that preview to record the acknowledgement. The key also needs mcp:write.

Watch one canonical customer

Use an ordinary query rule with one canonical person UUID in one exact project. The server expands every current alias; an agent must not turn a displayed alias sample into the rule. A known UUID does not require profile access. Optional persons:read permits an identity lookup; use a person proof link only when an authorized lookup supplies it.

Replace the three placeholder UUIDs below. Choose the threshold from the customer's measured traffic, and choose a notification channel explicitly. This definition counts error occurrences; it is separate from a saved-product-metric watch.

{
  "project_id": "PROJECT_UUID",
  "kind": "query",
  "name": "customer-error-count",
  "description": "Error count for the selected canonical customer",
  "watch_target": {"kind": "person", "mode": "aggregate", "person_id": "PERSON_UUID"},
  "query": {
    "data_type": "errors",
    "time_range": "5m",
    "no_data_policy": "evaluate_zero",
    "filters": {},
    "aggregations": [{"function": "count", "field": "*", "alias": "error_count"}],
    "group_by": []
  },
  "conditions": [{"type": "threshold", "operator": ">=", "threshold": 3, "field": "error_count"}],
  "evaluation_interval": "60s",
  "evaluation_timeout": "30s",
  "for_duration": "0s",
  "recovery_duration": "60s",
  "severity": "warning",
  "is_active": true,
  "is_paused": false,
  "notification_channels": ["CHANNEL_UUID"]
}

project_id confines identity and telemetry. kind: "query" selects scheduled query evaluation. The technical name and description describe the operation without copying profile data. watch_target.kind, mode and person_id select one canonical customer, aggregate over their current aliases, and allow no other target selector.

data_type: "errors" chooses error occurrences. time_range: "5m" is the only lookback. filters: {} adds no further predicates; the server still applies the target and project. count(*) counts visible matching rows and alias: "error_count" names that measurement. group_by: [] produces one aggregate. The threshold compares that alias with >= 3, so exactly three breaches too. Multiple conditions are ANDed. Omit unused condition time_window and params; they do not define a second lookback. no_data_policy: "evaluate_zero" explicitly compares a completely resolved empty count population as zero. An unknown or erased identity is not such a population.

evaluation_interval requests a tick every 60 seconds; evaluation_timeout bounds a tick to 30 seconds. for_duration: "0s" fires without sustained-breach confirmation. recovery_duration: "60s" requires a measured clear condition for 60 seconds; a breach or unmeasured interruption breaks healthy confirmation. severity: "warning" sets urgency. is_active: true enables the rule and is_paused: false permits scheduling. Only the UUIDs in notification_channels receive direct notifications. Existing validators remain authoritative. Omit server-owned IDs, organization, version, author, clocks and evaluation and budget state on create.

Use MCP test_alert_rule with the full draft first. For creation, discover the door with list_write_actions, then preview create_alert_rule with that full rule, selected project and a stable idempotency_key. Present the exact query, target, admitted schedule and channels before approval. Confirm identical arguments with the returned confirm_token.

CLI uses the same proposal:

anectico alerts rules create --project PROJECT_UUID --file rule.json --idempotency-key CREATE_KEY -o json
anectico alerts rules create --project PROJECT_UUID --file rule.json --idempotency-key CREATE_KEY --confirm-token TOKEN -o json
anectico alerts rules get RULE_UUID --project PROJECT_UUID -o json
anectico alerts rules test RULE_UUID --project PROJECT_UUID -o json

Keep the creation key for a lost reply: replay returns the original stored rule. The mutation receipt's complete-object change contains that stored rule as untrusted JSON. Read it back with get_alert_rule, compare watch_target, version, full schedule, query, conditions and channels. For an update use the exact current version: MCP update_alert_rule takes expected_version and explicit fields; the CLI patch file contains version and changed fields. Both preview, confirm and refuse a stale version. Validation and creation prove configuration only. Verify scheduled evaluation and channel delivery separately; no rule proof page exists.

The errors recipe uses alerts:rules:write, alerts:rules:read, conservative catalog evals:read, errors:read, channels:read and alerts:read for lifecycle evidence. MCP also uses mcp:read/mcp:write. A known person UUID adds no persons:profile:read requirement. Alternative telemetry sources require their actual traces:read, logs:read or metrics:read.

Unknown, erased, unavailable, empty or oversized identity is unmeasured. It never drops the alias predicate, queries another customer, reports a healthy zero or advances recovery. Identity is rechecked after the telemetry read; a changed alias set withholds the verdict. Counts concern retained, visible data; upstream completeness stays unknown.

Person erasure defines removal of person-watch configuration, original replies, measurements and linked delivery copies, including its limits for in-flight requests and external recipients. Person export defines the separate archive boundary.

What your agent gets back

A rule read returns the query, conditions, timing and routing. It also returns kind (query or external) and, when a rule is bound to an evaluator or a source, evaluator_status and external_source. An evaluation result carries unmeasured and unmeasured_reason when the measurement could not be made. The sections below explain each field. An alert read gives its severity, state, start time and the identifiers that acknowledge and resolve use.

A message about one incident, one issue or one watched person carries a link to that proof page. Other alerts carry no link.

Open the proof

An alert has no proof page of its own. When you open an incident from an alert, the incident has one at /view/incident/:id. It is read-only, it names its project, and it has one action, Copy link. See Proof pages and Manage incidents and on-call.

Add a destination

In the Console, open Connections and notifications (/connections), choose the Notifications tab, and create a notification channel for direct rule delivery. Your agent can also create one with create_notification_channel (CLI: anectico channels create). Send a test notification before attaching it to a production rule. Add personal contact methods only when the rule routes through an escalation policy or on-call schedule. See Connect tools and notification delivery.

Available destinations depend on the connections enabled for your organization. Webhooks can cover destinations without a dedicated integration.

Create a rule

Ask your agent to build the rule definition, test it, and then create it. The definition sets:

  • the project and environment;
  • the signal or customer being watched;
  • the condition type, its specific settings, and the evaluation window;
  • how long the condition must remain true and then remain clear; and
  • the notification destination.

Optional evaluation settings and message templates are fields of the same definition. Ask the agent to read the rule back with get_alert_rule and to explain it in plain words before you rely on it.

If saving fails because of the selected project, see alert project errors.

The selected project is an evaluation boundary, not only an organizational label: the rule reads telemetry from that project and never combines matching data from another project. If a watched customer or account scope or grouped query cannot be measured completely, Anectico leaves that evaluation unmeasured rather than treating missing results as zero.

For a cohort target, each evaluation reads one exact membership generation of that cohort. The generation must be synchronized and its source evidence must remain readable. Anectico checks again after reading the scoped telemetry. If the cohort changes, source content is erased, or membership becomes unavailable, that evaluation fails without triggering or clearing alerts or changing their unmeasured markers. An unavailable cohort is never treated as an empty one. Refresh the cohort to produce a new valid generation before retrying; restoring old source rows alone does not make an erased generation usable again.

Cohort notifications retain the exact generation used for their rendered observation, including escalation steps and retries. Before each channel or personal-contact send, Anectico checks that original generation again. Missing, pruned or erased evidence stops delivery without a provider attempt. A temporarily unavailable evidence service delays delivery without consuming an attempt. Refreshing the cohort does not authorize an older queued notification. A complete later generation that removes a watched person starts the rule's normal recovery handling for that person's alert.

Use a sustained firing window for noisy metrics and a recovery window when one healthy evaluation should not close an incident. A breach during recovery restarts the healthy window. Use immediate notification and recovery only for conditions where one event is decisive, such as a critical customer error.

For a metric rule, select metrics, add a metric_name filter, and use the same aggregation and window you already validated with query_metrics (CLI: anectico metrics query <metric-name>) or in a saved dashboard. Metric rules and anomaly baselines count a redelivered point once and retain its first received value, just as metric queries do. Match the filters, grouping, reduction, and effective window when comparing an evaluation with a query. A threshold is the clearest choice for a hard service limit. An anomaly condition can preview an expected band when metric_name is present, but it remains an approximate signal rather than proof of a problem.

Evaluation timing

evaluation_interval sets the cadence. evaluation_timeout bounds one complete evaluation, including scheduled budget checks, target resolution, its query, historical comparisons and per-entity measurements. Scheduled and manual evaluations use the same bound. Set it between one second and the evaluation interval. If omitted, it defaults to half the interval with a minimum of five seconds: a 60-second cadence defaults to a 30-second timeout. A shorter client deadline and query safety limits still apply.

If measurement times out, the result carries unmeasured: true, unmeasured_reason: "evaluation_timeout" and null condition observations. An unfinished measurement supplies no firing or recovery verdict; active alerts gain an unmeasured since marker. A later complete measurement must establish recovery again. REST, MCP evaluate_alert_rule and anectico alerts rules evaluate preserve this reason when the caller can receive the result. A timeout after an alert write begins remains an error because the write may already have taken effect. Read the rule and active alerts after an interrupted request before considering a retry.

test_alert_rule and anectico alerts rules test validate the definition without running its query. A passing test does not establish that real evaluation finishes within its timeout.

Numeric measurements and no data

Numeric threshold, change and slo conditions require an explicit aggregation. A raw span or metric row has no declared ordering or population meaning, so that rule is refused at create, update and test. For “a span exceeded 2 seconds”, declare max(duration_ns) and compare its alias with 2000000000; an average or percentile answers a different question. Entity watches also require a declared reducer.

Set query.no_data_policy for these comparisons:

Policy Meaning
retain Missing numeric input leaves the evaluation unmeasured, with a no_data reason and observed: null. Existing alerts retain their last measured state; missing input cannot start or complete recovery.
query.no_data_policy: "evaluate_zero" An empty count or sum population is explicitly compared as zero. This can fire a heartbeat or clear a count threshold. It describes the event population, not proof that the service is healthy.

query.no_data_policy: "evaluate_zero" requires only count or sum aggregations and conditions that select their aliases. Partial reducers such as average, maximum and percentile have no empty-input value and must use retain. Percentage-change and mixed baseline comparisons also use retain. A missing or unknown policy is refused; the comparison operator never chooses it. Absence, anomaly-only, issue-lifecycle and saved-metric watches have their own presence contracts and leave this field empty. Use an absence condition when silence itself should alert.

For a grouped numeric rule, retain withholds the whole tick if a previously active group has no current input. For query.no_data_policy: "evaluate_zero", only known active groups receive their declared zero; a missing identity never creates a new group. Entity watches with retain withhold all changes if any watched entity lacks input. A complete membership change can still remove a departed cohort member through the documented membership recovery contract.

Manual evaluation reports the normalized reducers, selected fields, stored rule version, policy and frozen window in result.query_result, alongside condition observations and row counts. MCP preserves this evidence in its mutation receipt; REST and CLI retain the native result. conditions_result_scope distinguishes a scalar, a representative group and the first watch entity. Entity-watch metadata includes every entity observation by index, without disclosing its identifying labels. A null observation is different from a measured zero. get_active_alerts also reports unmeasured since, so a retained breach is not mistaken for a fresh observation. Manual evaluation sends notifications and needs confirmation.

Grouped query rules

With query.group_by, each result group evaluates the complete set of conditions independently. For example, an error count grouped by service_name can fire for both checkout and payments in the same evaluation. Every condition must hold within the same group; conditions met by different groups do not combine into a breach. Each breaching group refreshes one alert whose identity uses the declared grouping dimensions. A changed count or rule name preserves that identity.

Change conditions match the same grouping dimensions in the current and previous windows. Anomaly baselines also stay within their group. If a present group has a missing, non-finite, or undefined required measurement, the whole evaluation is unmeasured and existing alerts stay open.

An evaluation supports up to 10,000 groups in each current or historical query. Exceeding that limit leaves the evaluation unmeasured. Narrow the query filters or choose fewer grouping dimensions so the complete result can be evaluated.

Issue-spike rules apply this bound independently to their current and prior issue-group sets. If either set exceeds 10,000 groups, the result is unmeasured with incomplete_group_result; it neither fires nor clears alerts. Existing alerts keep their last measured state and an unmeasured since marker until a complete evaluation returns. Narrow the filters before interpreting the result as recovery or a new spike.

Every issue_lifecycle rule uses query.data_type: "errors", including spike, new and regressed rules. Other sources are refused when creating, updating or testing a rule; an invalid stored definition cannot evaluate another signal as errors.

Spike rules apply every accepted error equality filter to both windows, including release, error_type, error_group_id and their supported aliases. An empty string is an exact match, not a wildcard. New or regressed issue-event rules support only project, issue-group, service and environment filters: their event payloads do not contain release or error type, so other filters are refused when creating, updating or testing those rules.

A numeric group absent from a complete result follows the declared no-data policy above. Without an expected-series inventory, an absence condition checks whether the whole query received data. Issue-spike rules retain their complete-set occurrence and recovery contract. Change and anomaly comparisons remain unmeasured when their required measurement is missing. Use a customer watch when absence must be checked for each known customer separately.

Detect one reporter going silent

For metrics, declare the expected identities in query.expected_series. Each identity names exactly the group_by dimensions. This example expects two hosts; a fleet of 90 uses 90 entries. Use one absence condition and one count() aggregation. Metric values, including zero, do not affect whether a reporter is present.

{
  "data_type": "metrics",
  "time_range": "5m",
  "evaluation_delay": "30s",
  "filters": {"metric_name": "system.cpu.utilization", "environment": "production"},
  "aggregations": [{"function": "count", "alias": "samples"}],
  "group_by": ["host"],
  "expected_series": {
    "lookback": "1d",
    "identities": [{"host": "host-01"}, {"host": "host-02"}]
  }
}

Put that query in a complete rule with conditions: [{"type":"absence"}], the project, schedule, severity and chosen notification channels. Create or update it with the same confirmed MCP actions and CLI commands above. Read the saved definition back before relying on it.

Metrics support host, pod_name and service_instance_id for grouping and equality filters. They read host.name, k8s.pod.name and service.instance.id, respectively; those attribute names are also accepted as field aliases. A point attribute overrides the same resource attribute, including an explicit empty value. Other metric attributes are not grouping fields.

The inventory supports 1–1,000 unique identities, each with exactly the declared dimensions and nonempty values of at most 256 bytes. Maintain the inventory when reporters are intentionally added or removed. A project_id dimension must match the rule's project. The inventory is explicit; observing a new reporter does not add it to the expected set. lookback must be at least time_range and at most seven days. A history query over more than 10,000 groups is unmeasured; narrow its filters.

Each missing reporter gets its own alert. query_result.series_presence reports expected_count, present_count, missing_count, unexpected_count, all_missing and per-reporter observations with labels, status, last_seen_at and last_seen_state. One missing out of 90 has missing_count: 1, all_missing: false; all 90 missing has missing_count: 90, all_missing: true. Unexpected reporters never substitute for an expected identity. A timestamp is the most recent observation within the bounded lookback. When none exists, last_seen_at is null and last_seen_state is not_observed_in_lookback; it does not mean the reporter never existed.

An unavailable or incomplete presence query returns unmeasured: true and presence status unknown, with null missing counts. It cannot fire or recover an alert. Observing a missing reporter again starts its normal recovery policy. Alerts also carry series_last_seen_at when known and series_last_seen_state. MCP evaluation receipts preserve the population evidence in their /query_result change; CLI JSON returns it under result.query_result.

Allow late observations and inspect current status

Ordinary windowed rules can set query.evaluation_delay, such as "30s" (default zero, maximum "168h"). The evaluation window ends that far before the attempt time. Comparison and anomaly baselines and the intake assessment use the same delayed boundary. This gives late data time to arrive; it is not proof that an exporter sent everything. Intake completeness is still disclosed, and known incomplete intake withholds the verdict.

Issue-lifecycle rules and current review signals refuse this setting. Product metric watches use their own evaluation_delay_ms; account objectives retain their own completeness contract.

Rule reads expose last_evaluation for the current definition, even if no alert has ever fired: state is clear, breaching or unknown, with reason, evaluated_at, rule_version, the effective window, delay and population counts when available. breaching describes the measured condition; pending and recovery durations still govern alert state. An edit clears this status until the new definition is evaluated. Always check its time: pausing a rule stops new evaluations. Timeouts remain unknown with reason evaluation_timeout. New or regressed issue-event rules are driven by their events and do not publish a query-evaluation status. Use get_alert_rule or list_alert_rules, or anectico alerts rules get RULE --output json.

For a measured evaluation, the response includes every breaching group in triggered_alerts. Its scalar conditions_result describes the first triggered group in that response, or a deterministic first group when none breach. Source permissions still govern access to identifying group labels.

Anomaly conditions

Each measured breach updates the open alert's severity, observed value, explanation, expected band, and anomaly score together. Severity can increase or decrease while the alert keeps its identity and history. If a firing duration is configured, the first notification uses the observation that completes confirmation. A severity change on an already-firing alert does not send another notification by itself. If you change a grouped rule from anomaly detection to a threshold, the same group's open alert clears its previous expected band and anomaly score on the next breach.

Renaming an anomaly rule updates its open alert's displayed name on the next measured breach. The alert keeps its ID, history, acknowledgment, and firing confirmation window; the rename does not indicate recovery or trigger another notification. A silence that matches the rule's name follows the updated name; match the rule ID to keep it independent of renames.

Anomaly detection needs a finite current measurement and at least one finite earlier point. Missing current data, insufficient history, or non-finite baseline values leave the evaluation unmeasured. A failed baseline query is also reported as an evaluation error. For metric rules, the current measurement comes from the newest completed interval; an interval still in progress is excluded, and an older point cannot replace a missing newest measurement.

For telemetry metric anomaly rules, params.interval accepts 1m, 5m, 15m, 30m, 1h, 6h, 12h, or 1d. 24h is equivalent to 1d; both use UTC day boundaries. Omitting the interval selects 1h. The anomaly condition scores the latest completed bucket and excludes the bucket still being collected.

Create, update, and test refuse unsupported metric intervals such as 2h or 10m, and explicit empty, malformed, zero, negative, or non-string intervals. If an older rule has an invalid interval, evaluation reports an error and leaves open alerts in their current state until the condition is corrected. Other query sources can sample any positive integer duration in seconds (s), minutes (m), hours (h), days (d), or weeks (w).

An unmeasured anomaly does not trigger, re-notify, or clear alerts. Open alerts keep their last measured state and an unmeasured since marker. Firing and recovery confirmation restart with the next appropriate measured observation. A measured non-anomalous result can recover normally, including a genuine zero count. In a rule combining several conditions, an unmeasured anomaly prevents the whole rule from changing alert state regardless of condition order. This also applies to aggregate customer watches.

The evaluation response sets unmeasured and an explanatory unmeasured_reason, leaves the anomaly condition's observed as null, and preserves the primary window's rows_scanned.

Percentage-change conditions

A generic query rule's change condition compares the current window with the earlier window selected by comparison_period. Its threshold is a percentage, not a fraction: (current - previous) / previous * 100. The sign of the previous value is preserved. Both windows read the condition's selected field. When field is omitted, a query with one aggregation uses that aggregation's output alias, including a generated or custom alias. Raw numeric comparisons are refused. Queries with several aggregations require an explicit field when saving or testing the rule. Both comparison windows keep the same selected field. For example, 100 to 120 is +20%, 100 to 0 is -100%, and either 100 to -100 or -100 to 100 is -200%. This is the contract for generic query rules, not saved-metric watches.

Both windows need a finite measured value, and the previous value must be nonzero. A zero previous value, including zero to zero, makes the percentage undefined. A missing measurement or a percentage too large to represent also leaves the evaluation unmeasured, not healthy and not breaching. A failed comparison query is reported as an evaluation error.

An unmeasured evaluation does not trigger, re-notify, or clear an alert. Open alerts retain an unmeasured since marker until measurement returns. Firing and recovery confirmation restart with the next appropriate measured observation; an undefined interval does not count as sustained evidence. In a rule combining several conditions, an undefined change prevents the whole rule from changing alert state, regardless of the conditions' order. These rules also apply to aggregate customer watches.

Threshold and SLO conditions also leave an evaluation unmeasured if their selected value is missing, NULL, nonnumeric, or nonfinite. A missing measurement cannot clear an open alert, and the evaluator never substitutes another aggregation's value.

The evaluation response sets unmeasured and an explanatory unmeasured_reason, leaves the change condition's observed as null, and preserves the current window's rows_scanned. A genuine measured zero percentage remains observed: 0. When a change fires, the condition's value and observed contain the percentage; the triggered alert's value remains the current signal value. Messages retain small nonzero values and use compact scientific notation for extreme magnitudes.

Query fields

Rule filters are exact, case-sensitive string matches. Use one of the fields below. Anectico validates and normalizes the query before saving the rule, so a typo or a field from the wrong signal returns a validation error instead of creating a rule that fails later. service is the portable field for every signal and maps to the stored service_name column. The canonical service_name spelling is accepted too. Logs also accept level for severity; traces accept operation for operation_name and status for status_code.

Signal Exact-match filter fields
Errors service, service_name, environment, error_id, error_group_id, group_id, fingerprint, error_type, type, message, release, dist, user_id, user_email, user_ip_address, trace_id, span_id, session_id, distinct_id, request_method, request_url, platform, sdk_name, sdk_version, project_id
Logs service, service_name, level, severity, severity_text, message, environment, trace_id, span_id, logger_name, host, pod_name, source_file, distinct_id, session_id, project_id
Metrics service, service_name, metric_name, name, metric_type, type, environment, project_id, unit, description, aggregation_temporality, host / host.name, pod_name / k8s.pod.name, service_instance_id / service.instance.id
Traces service, service_name, operation, operation_name, status, status_code, status_message, span_kind, environment, trace_id, span_id, parent_span_id, distinct_id, session_id, project_id, gen_ai_provider_name, gen_ai_model, source_operation, gen_ai_cost_source, agent_session_key, gen_ai_agent_name, gen_ai_agent_id, gen_ai_tool_name, gen_ai_response_id, gen_ai_finish_reason
Agent steps category, operation, canonical_operation, source_operation, source_kind, agent, agent_observation_key, environment, trace_id, span_id, session_key, turn_id, distinct_id, source_schema, project_id

count can omit its field. Numeric reducers (sum, avg, min, max, p50, p95, and p99) accept value for metrics, duration_ns and the numeric gen_ai_* token and cost fields for traces, or source_line for logs. Errors and agent steps support count only. Grouping is also signal-specific; a rule with a grouping dimension its signal does not support is refused when you test or save it. Filter objects, arrays, nulls, comparison operators, arbitrary free-form expressions, and unknown identifiers are rejected before the rule is persisted.

Alert on what an agent did

The Agent steps signal (agent_events in the API) is one row per step an agent took inside a run — a guardrail decision, a tool call, a memory write. Use it for questions a run-level view cannot answer: how often a guardrail is denying, how much a given agent is calling a particular tool, or whether an agent has stopped taking steps at all.

Agent steps support count and no other reducer, and every other reducer is rejected when you save the rule rather than silently returning zero. The reason is worth stating plainly: a step does not yet report its own duration, so an average over it would compare 0 against your threshold on every evaluation and page you forever while nothing was wrong. Those reducers become available in the same release that starts reporting the numbers behind them.

Two shapes cover most of what this signal is for:

  • A rate ceiling. Count steps in a window, filter to category (and optionally agent), and set a > threshold — "more than 10 guardrail denials in 15 minutes".
  • A silent fleet. Count steps and set < with a threshold of 1, or use an absence condition. Either fires when the window contains no agent activity at all.

Because the reducer is count, the result field on the condition is the alias you gave the count. Naming a raw field there instead is rejected when you save.

If you group an agent-step rule by distinct_id, that label is treated as person-identifying, the same way user_email is on an error rule: it is kept out of the delivered notification entirely, and reading it back from the API needs permission to read agent runs, not just alerts.

For a heartbeat, scheduled job, or other expected signal, choose an absence condition. It checks whether the filtered query matched any source rows during query.time_range, which is the sole lookback. Raw, grouped, and aggregate queries are supported; a real aggregate value of zero still counts as present data. The condition does not use an operator, threshold, result field, or its own time_window.

Alert on an evaluation objective

An SLO condition alerts on the scores an evaluator produces, rather than on raw telemetry. Use it to hold a quality objective — "faithfulness stays at or above 0.9", "task completion does not fall below 0.95" — the same way a threshold holds a latency or error-rate objective.

An SLO condition names three things:

Setting Meaning
Evaluator The evaluator whose scores the objective is measured on.
Version An exact evaluator version. Required, and never "latest".
Mode Which kind of run counts: production, experiment, or simulation.

Set the operator and threshold to the objective itself, aggregate numeric_value over the window, and filter or group on evaluator_id, evaluator_version, mode, metric_name, subject_kind, label, environment, or project_id.

Three rules follow from what an SLO is for, and each one is enforced when you save:

  • The version is exact. An objective bound to a moving evaluator is not an objective: the same release would pass on Monday and fail on Tuesday with nothing in the record explaining why. A version of 0 or a missing version is rejected.
  • The evaluator must already exist, and must be reproducible. Saving the rule checks that the evaluator and version are registered in the project, that the evaluator names the dimension it scores, and that its configuration is fingerprinted so a score can be traced back to exactly the rule that produced it. An evaluator that cannot supply that is refused when you save the alert, naming what is missing — not at 3am when the alert fires on numbers nobody can reproduce. If the check cannot be completed, the rule is not saved and you can retry; it is never stored unchecked.
  • One objective per rule, on its own. An SLO condition cannot be combined with another condition, and evaluation scores cannot be read by any other condition type. This keeps the numbers an alert compares scoped to the exact evaluator, version and mode it declared.

Because an evaluator belongs to a project, an SLO rule must be scoped to a project rather than to the whole organization. Creating one also requires permission to read evaluations.

The exact evaluator reference is checked again immediately before every scheduled evaluation. The rule's evaluator_status reports valid, invalid, or unavailable, with evaluator_checked_at and a safe evaluator_error when something is wrong. An invalid reference does not run the score query and is never represented as a score of zero. Updating the rule clears the previous status until the new definition is checked.

The objective is evaluated on when each score was produced, so a score always lands in a window the alert has yet to check, however long the evaluation itself took.

The evaluator's written explanation is recorded content, not an alert dimension. SLO evaluation selects only the declared score metadata and numeric fields, so an explanation is never copied into an alert label, alert read, or Slack, email, and webhook notification. Read the evaluation result itself with the separate content permission and current project policy when you need that reasoning.

Rules fed by an external source

Most rules are query rules: Anectico evaluates their query on a schedule. A rule can instead be an external rule, bound to exactly one source such as a monitor. An external rule has no query, conditions or evaluation schedule; its source reports each failure and recovery, and every failure episode becomes one alert however many times the source repeats it. Rule reads return kind (query or external) and, for an external rule, its external_source.

external_source.concurrent_occurrences says how episodes of one source relate. A monitor has one failure episode at a time (false): a new failure episode replaces the open alert. A service in your response catalog receives many independent incoming alerts at once (true): each distinct alert stays open as its own alert, and its recovery closes only that alert.

An external rule always pages through an escalation policy. Creating one, pointing it at another policy, or re-activating it is refused unless the policy exists in the same project, is active and has at least one level. Rule reads also return routing_coverage for an external rule, so a policy that is later deleted, deactivated or emptied shows as missing_policy, policy_inactive or policy_has_no_levels instead of silently paging nobody. Query, condition and schedule fields cannot be edited on an external rule, and it cannot be tested or evaluated on demand.

Test before enabling

Ask your agent to test the rule and show you the message it would send. Confirm the message contains enough context to begin an investigation: the condition, severity, project, environment and time. A message about one incident, one issue or one watched person in a project also carries a link to that proof page. Other alerts carry no link.

Respond to an alert

Ask your agent what is firing. get_active_alerts (CLI: anectico alerts list) lists the alerts that are open now. search_alert_history (CLI: anectico alerts history) includes resolved alerts and takes a window, such as --since 7d. Name a rule to see how often it fired, or one alert to read just that alert. These reads cover all environments in the project; use a rule's query filters when evaluation should cover a particular environment. A list is cursor-paged: the agent passes next_cursor back unchanged to read the next page, and a count of loaded rows is not a total of all alerts.

An alert read shows its observed value, lifecycle state, environment, labels, and current rule. The current rule may have changed since the alert fired.

For active anomaly alerts, the read shows the actual value, expected interval, and labelled detector score from the latest measured observation. Labels and annotations are custom metadata; annotations do not override detector evidence. If the rule changes to a plain threshold, the anomaly detail disappears on the next read.

When a rule cannot obtain a required measurement, the alert read says the current measurement is unavailable and gives an unmeasured since time, which is the first consecutive measurement gap. The retained value, expected interval, and detector score are last measured evidence. The alert stays open and its response actions remain available. The warning clears when measurement returns, including a genuine zero value.

Detector scores are specific to the detector, rather than a universal statistical unit, probability, or root-cause diagnosis. The Likely real marker remains a promotion signal; findings without it are not dismissed.

  1. Acknowledge when someone takes ownership (acknowledge_alert).
  2. Open the linked customer, Issue, trace, or service evidence.
  3. Create an incident when coordination or a durable case file is needed (create_incident).
  4. Resolve after the condition has cleared and follow-up is recorded (resolve_alert).

Resolving is final for that alert. It records who resolved it and when, and nothing reopens it — if the condition breaches again you get a new alert with its own history, rather than the old one returning to firing. This holds even when a check of the same rule is already running as you resolve.

Automatic query recovery records resolution: recovered in alert history when the configured healthy window completes. It preserves any acknowledgment and records no human resolver.

Acknowledging or resolving an alert stops its escalation and closes its linked incident, whichever surface you use: the API, MCP, the CLI or Slack. A manual resolution is recorded as resolution: manual: it ends the response, and says nothing about whether the watched source has recovered. For an external rule, further failures of that same episode do not reopen it; a new failure after the source recovers opens a new alert. Every page — a first notification, a retry or the next escalation step — is checked against the alert's current state just before it is sent, so an alert that has been acknowledged, resolved or silenced sends nothing more. A page already handed to the delivery provider when you acknowledge may still arrive.

Use a silence for planned maintenance or a known temporary condition. Give every silence an owner and expiration time. Matching alerts show silenced with that provenance; acknowledging one keeps the responder-owned state until the acknowledgment is cleared. If maintenance ends while the condition still breaches, the alert returns to firing and notifies once on its next evaluation. An external rule's alert resumes within seconds of the silence ending or being deleted early, because its source does not re-evaluate. A resumed alert that had already paged notifies once and does not open a second incident; one that fired straight into the silence pages for the first time. The same holds for a scheduled silence that starts after an alert fired but before its first page went out: the page is held and sent once when the silence ends. An acknowledgment or recovery that happens first wins, and nothing resumes.

External monitors have a second, source-side suppression: a maintenance window covering a monitor stops a new failure episode from opening at all, rather than silencing an alert that already exists. The check still runs and every round is still recorded; when the window ends, a monitor that is still failing pages once. Use a silence when you want an already-firing alert to stop paging; use a maintenance window on the monitor itself when you know it is about to fail (a deploy, a planned outage) and do not want the first failure to open an episode in the first place.

Deleting a rule keeps its alert history and acknowledgments readable: the rule disappears from rule lists and stops being evaluated, its name can be reused at once, and any of its alerts still active are resolved with resolution: rule_deleted, which stops their paging and closes their incidents. An alert whose source stopped reporting it without recovering — a failing monitor owned by a service that was deleted or moved to another route — is resolved with resolution: withdrawn, which likewise stops its paging and closes its incident without claiming the check recovered.

A silence has matchers on labels (exact match or full-match regular expression), a start time and an end time. The MCP tool previews the matching scope before it creates the silence; read the preview before you confirm. Silences apply across the organization wherever all labels match; the selected project alone does not restrict them. Pausing notifications does not itself resolve an alert.

Tune based on outcomes

Review alerts that fired without action and alerts that should have fired but did not. Change the condition, window, or routing rather than training the team to ignore noise.

Scheduled work budgets

get_alert_rule and anectico alerts rules get show the rule's budget origin and latest evaluation budget state. Work changes move the origin to the updater; a rename or pause keeps it. A missing credential moves new evaluations to scheduled work in the workspace.

Each accepted scheduled evaluation counts one query operation, including all its source queries. Retries do not add a charge. Budget limits never stop an alert evaluation. It takes no concurrency slot. Usage marks any overage as over budget by scheduled alerting. Unavailable limits are marked unchecked. See Scheduled work.

Alert-rule and silence commands show complete server proposals before applying. Silence proposals include every matcher and the exact window. Creates use stable retry keys and return their original result on an identical retry. Edits refuse a changed before-state. Rule retirement resolves active alerts and can resolve linked incidents and send recovery notifications to the previewed audience; queued delivery selects recipients at send time.

A metric watch automatically pauses when its admitted key or source permission is lost. Read pause_reason and paused_at in its definition and the control-state conclusion. The workspace receives a control notice; a queued notice is not proof of delivery. Restore authority and explicitly preview and confirm resume. An operator can pause without source access. Stopping a watch leaves an already active alert unresolved.

Resolving an alert can close linked incidents and send recovery notices. Both MCP and the CLI show the full current alert, requested note and recovery audience first. After approval repeat identical CLI arguments with --confirm-token. An unreadable active state refuses a confirmation token. Resolution has no inverse.

Account objective evidence and privacy

The objective guide owns the source-lifetime, current-access and erasure rules for account measurements and original triggers.

Metric watch transition meaning

Product metric watches require source_loss_grace_periods: 2. A breach and a recovery require measured confirmation; unavailable evidence interrupts it. An exact removed source or sustained explicit unavailable coverage is source loss, including before any alert fired. Restored availability alone is not recovery. A silence suppresses breach delivery without changing that measured fact; its expiry, acknowledgment, manual closure and resume are not new measured transitions. Receive these transitions through agent event delivery, and use its authorized watch-event reads to follow an occurrence.

Exact account request objectives

Use Account request objectives to prepare a paused account proposal, read its current activation limit, inspect fresh burn evidence or follow an original trigger. The request population is defined in Observed customer request reliability.

Versions and approval

Deleting or evaluating a saved rule requires its current integer expected_version; saved-rule validation requires it too. Use --expected-version on the CLI. Editing or deleting a silence requires expected_version equal to its current updated_at. A stale version returns a conflict and changes nothing; read the current object and obtain a new preview. An admitted test evaluates the selected definition rather than following later edits.