---
summary: Manual, schedule, and webhook triggers, plus single-branch handoffs.
title: Triggers & handoffs
path: triggers
status: published
---

# Triggers & handoffs

A crew member runs in response to a **trigger**. Every run records its `origin`.

## Manual

Start a run directly via the API or the Bridge (`origin=manual`). Supports a **dry run** — the draft
executes with external effects stubbed, so you can preview behaviour without side effects.

## Schedule (cron)

A schedule trigger fires on a cron expression (validated with `croniter`). The scheduler fires the
**latest due slot** per trigger and does **not back-fill** missed slots; firings are de-duplicated by
slot. Dispatched with `origin=schedule`.

## Webhook

A webhook trigger exposes a **public per-trigger ingress URL** with an HMAC secret (held as a
ScaiVault handle). Incoming requests are HMAC-validated, mapped to the run input, de-duplicated for
idempotency, and dispatched with `origin=webhook`.

Schedules and webhooks are **system-plane** entrypoints: they look the trigger up across workspaces,
then bind the workspace and a system actor before dispatching — so tenancy is still enforced.

## Handoffs

A member that **succeeds** can hand off to a peer member. Handoffs are **single-branch**:

- at most one unconditional handoff, no fan-out, no self-handoff;
- the workspace handoff graph is **cycle-checked** at declaration time;
- at run time, the first matching condition fires the peer as a **child run** (`origin=handoff`,
  with `parent_run_id` set), bounded by the cycle-free invariant and a depth cap.

Anything more complex than single-branch handoff is exported to ScaiFlow rather than modelled here.
