Skip to content

Subscriptions

A subscription watches a repository for changes and delivers a webhook when matching write operations land or a cron schedule fires. Subscriptions are WarmHub’s mechanism for automation.

A subscription can watch its own repository (the default) or a different repository in the same org (a cross-repo subscription). In both cases the executor runs in the subscription’s home repository context.

When write operations land in a repository, WarmHub evaluates all active subscriptions:

  1. Event created — one action event records the write operation set
  2. Filter matching — each subscription’s filter is compared against the operations; this includes subscriptions in other repos that are configured to watch the source repo
  3. Dispatch — matching subscriptions trigger their configured webhook
  4. Retry — failed deliveries are retried with exponential backoff

Cron subscriptions skip steps 1–2 and fire on their schedule directly.

KindTriggerExecutorUse Case
webhookWrite operationHTTP POST to your URLNotify external services, trigger pipelines
cronScheduleHTTP POST to your URLPeriodic health checks, syncs, reports

Sends an HTTP POST to the configured URL whenever matching operations land. The payload includes event details, matched operations, and tracing metadata. Webhook subscriptions support credential binding for authentication.

Fires on a cron schedule (minimum 5-minute interval) and delivers to a webhook URL. Cron subscriptions are not bound to a shape and do not filter operations — they simply run on schedule.

Webhook subscriptions carry a filter that determines which operations trigger the action. Most subscriptions are bound to a shape (via --on <shapeName>) and only evaluate operations on that shape’s things and assertions.

Shape lifecycle subscriptions watch for changes to shapes themselves (add, revise, retract) and do not require a shape binding. They use a { "kind": "shape" } filter and omit --on. See Shape Lifecycle Subscriptions for the exact accepted forms and which compound filters still need --on.

Filters support matching on:

  • operationadd, revise, retract
  • kindshape, thing, assertion, collection
  • shape — shape name; filters remain stable if the shape is renamed later (targets things-of-shape-X, not shape-X itself)
  • name — exact match against the operation’s name. For thing and assertion operations the name is Shape/name form (e.g. Signal/sensor-1); for shape lifecycle operations the name is the bare shape name (e.g. Reviewer)
  • match — glob match on the same name field as name above (same engine as wh thing list --match)

Boolean combinators all, any, and not allow compound filters. See Filter JSON Reference for the full grammar.

A subscription can watch a shape in a different repository within the same org. The subscription lives in its home repo (where its webhook is configured and credentials are resolved), but its filter is evaluated against writes in the source repo.

When a matching write lands in the source repo, WarmHub fans out to all cross-repo subscribers watching that repo’s shapes in addition to the repo’s own local subscribers. The webhook payload still uses the same top-level shape as same-repo deliveries: repo identifies the subscription’s home repo and event carries the event name. Source-repo details are included in the payload fields documented in Webhook Payload.

Subscriptions have two states:

  • Active — events are matched and dispatched normally
  • Paused — no new deliveries are created; cron jobs are deregistered

Pausing and resuming are instant operations. See Managing Subscriptions for details.

WarmHub retries transient delivery failures with short exponential backoff before marking the run unrecoverable.

Retryable conditions: network errors, HTTP 429 (rate limit), HTTP 5xx (server errors).

Non-retryable (terminal): HTTP 4xx (except 429), validation errors, missing configuration.

A run transitions to dead_letter whenever no recovery path remains. The two ways to land there: retries are exhausted, or a failed_terminal run’s configured fallback URL cannot recover the delivery because it is rejected by webhook URL validation or exceeds WarmHub’s redirect-follow limit. Non-retryable errors immediately become failed_terminal. dead_letter always creates a failure notification. failed_terminal does so immediately unless a fallback URL still has a chance to recover the delivery; otherwise notification is deferred while recovery remains possible.

WarmHub emits in-app notifications for subscription delivery outcomes.

Failure notifications are always enabled, but they are emitted only once a failure is no longer recoverable. dead_letter always creates a notification. failed_terminal may be deferred when a configured fallback can still request a retry on the same run.

Success notifications are opt-in via a notifyOnSuccess flag on the subscription. When enabled, successful deliveries create success notification records. Today, set that flag through the SDK client.subscription.create() / update() surface; the current CLI and MCP surfaces do not expose a setter for it.

Every subscription maintains a delivery feed — a chronological log of action deliveries with status, source labels, and matched operations. Each delivery tracks individual attempts with HTTP status codes, error messages, and response snippets.

Terminal window
# View recent deliveries
wh sub log signal-hook
# Follow deliveries in real time
wh sub log signal-hook --live

See Managing Subscriptions for the full observability surface.