---
title: Alerting
description: Declare typed alert policy metadata in createSmithers() and manage durable alert rows.
---

Use `alertPolicy` when you want a workflow to carry operational alert metadata such as ownership, severity, runbooks, labels, and deterministic reactions.

The API is declarative:

- `createSmithers(..., { alertPolicy })` defines module-level defaults.
- `smithers(..., { alertPolicy })` overrides those defaults for one workflow.
- Smithers stores the merged policy on the workflow and exposes durable alert rows through the DB adapter and CLI.
- `deliver` uses logical destination names such as `oncall` or `author`; transport clients live in your runtime integration.

## Module Defaults

```tsx
import {
  createSmithers,
  type SmithersAlertPolicy,
} from "smithers-orchestrator";
import { z } from "zod";

const platformAlerts: SmithersAlertPolicy = {
  defaults: {
    owner: "platform",
    severity: "warning",
    runbook: "https://internal/runbooks/smithers-workflows",
    labels: {
      service: "deploy-bot",
      env: "prod",
    },
  },
  reactions: {
    "notify-author": { kind: "deliver", destination: "author" },
    "notify-oncall": { kind: "deliver", destination: "oncall" },
  },
};

const { Workflow, Task, smithers, outputs } = createSmithers(
  {
    deployResult: z.object({
      ok: z.boolean(),
      revision: z.string(),
    }),
  },
  {
    alertPolicy: platformAlerts,
  },
);
```

## Workflow Overrides

```tsx
export default smithers(
  () => (
    <Workflow name="deploy">
      <Task id="deploy" output={outputs.deployResult} agent={deployAgent}>
        Deploy the release and report the final revision.
      </Task>
    </Workflow>
  ),
  {
    alertPolicy: {
      rules: {
        runFailed: {
          severity: "critical",
          reaction: "notify-oncall",
        },
        approvalWaitExceeded: {
          afterMs: 86_400_000,
          reaction: "notify-author",
        },
        tokenBudgetExceeded: {
          severity: "warning",
          reaction: { kind: "pause" },
        },
      },
    },
  },
);
```

The merged policy is stored on `workflow.opts.alertPolicy`. Rule names are policy keys for your integration; the core engine does not attach built-in behavior to those names in this release.

## Merge Semantics

- `defaults` merge shallowly.
- `defaults.labels` merge by key.
- `rules` merge by rule name, and workflow-level fields win when the same rule appears in both places.
- `reactions` merge by reaction name, and workflow-level definitions replace module-level definitions with the same name.

## Reaction Kinds

| Kind | Use for |
| --- | --- |
| `emit-only` | Record the alert without pausing, cancelling, or external delivery. |
| `pause` | Pause the run for operator intervention. |
| `cancel` | Stop the run when continuing would be unsafe. |
| `open-approval` | Escalate into a human approval step. |
| `deliver` | Send the alert to a logical destination handled by your runtime integration. |

You can reference a named reaction from `rules` or inline a reaction object directly.

## Runtime Surface

`alertPolicy` is currently workflow metadata plus a durable alert storage model. The core engine starts an `AlertRuntime` wrapper for configured policies, but it does not run built-in alert evaluators, poll approval age, execute delivery clients, or create pause/cancel/approval reactions automatically.

Runtime integrations can:

- Read the merged policy from `workflow.opts.alertPolicy`.
- Persist alert instances with `SmithersDb.insertAlert()`.
- Query active alerts with `SmithersDb.listAlerts()`.
- Acknowledge, resolve, or silence alert rows with the DB adapter or CLI.

## Durable Alert Instances

Alert rows live in `_smithers_alerts`. The row shape includes:

| Field | Purpose |
| --- | --- |
| `alertId` | Stable alert identifier. |
| `runId`, `nodeId`, `iteration` | Optional workflow location. |
| `policyName` | Rule or policy key that produced the alert. |
| `severity` | `info`, `warning`, or `critical`. |
| `status` | `firing`, `acknowledged`, `silenced`, or `resolved`. |
| `fingerprint` | Optional dedupe key supplied by your integration. |
| `owner`, `runbook`, `labelsJson`, `reactionJson` | Materialized policy metadata. |
| `sourceEventType` | Optional source event name. |
| `firstFiredAtMs`, `lastFiredAtMs`, `occurrenceCount` | Recurrence tracking. |
| `silencedUntilMs`, `acknowledgedBy`, `resolvedBy` | Operator state. |

## CLI

```bash
bunx smithers-orchestrator alerts list
bunx smithers-orchestrator alerts ack <alert-id>
bunx smithers-orchestrator alerts resolve <alert-id>
bunx smithers-orchestrator alerts silence <alert-id>
```

`list` returns active `firing`, `acknowledged`, and `silenced` alerts. Use `--format json` when another process needs to consume the rows.

## Reactions and Delivery

Reaction objects are stored as data:

- `emit-only`
- `pause`
- `cancel`
- `open-approval`
- `deliver`

Your runtime boundary decides how to interpret those reactions. For example, `deliver` can route to Slack, PagerDuty, email, or an internal incident feed, but Smithers does not bundle those transports.

## Recommended Usage

- Use alert policy for operational conditions such as failed runs, approval timeouts, or budget breaches.
- Keep destinations logical and stable, for example `oncall`, `author`, or `incident-feed`.
- Put transport details in your notifier boundary, not in workflow code.
- Avoid using alert policy for every ordinary business notification.
