Events¶
Every meaningful change is recorded as an event with a name, a sequence number, an occurred time, a resource (run, task_run, flow, schedule, rule, worker, or custom), related resources, and a JSON payload. Rules match on events, the Events page and GET /api/events list them, and new ones arrive on the SSE stream as event.created.
The names below are the whole catalogue. It is declared once, in crates/core/src/events.rs, and every site that records an event names it from there, so this page is generated rather than maintained. GET /api/vocabulary serves the same list to the UI, and cereyan.events exposes it to Python: events.run.failed is the string "run.failed".
Run events¶
Resource run; related flow and the run's tags. Offline the payload is state and message only.
| Event | Payload | When |
|---|---|---|
run.scheduled |
state, state_type, message, flow, project, parameters, created_by |
The run is created, or re-enters Scheduled for a crash rerun |
run.pending |
state, state_type, message, flow, project, parameters, created_by |
An engine accepted the run |
run.running |
state, state_type, message, flow, project, parameters, created_by |
User code started |
run.completed |
state, state_type, message, flow, project, parameters, created_by |
The run finished without error |
run.failed |
state, state_type, message, flow, project, parameters, created_by, failures_in_a_row |
The run raised, timed out, or was set failed |
run.crashed |
state, state_type, message, flow, project, parameters, created_by, failures_in_a_row |
The engine died while the run was executing |
run.cancelled |
state, state_type, message, flow, project, parameters, created_by |
The run was cancelled |
run.late |
state, state_type, message, flow, project, parameters, created_by, scheduled_time, name |
The scheduled time passed 15 seconds ago and the run has not started |
run.overdue |
expected_seconds, elapsed_seconds, basis |
A Running run outlasted its flow's expected duration or overdue factor; recorded once per run |
run.retrying |
state, state_type, message, flow, project, parameters, created_by |
A retry attempt started |
run.skipped |
state, state_type, message, flow, project, parameters, created_by, reason |
The run ended Skipped: on_overlap="skip", a backfill value already done, a catch-up drop, a fire a person skipped (reason user), or an upstream run skipped that way (reason upstream) |
run.paused |
state, state_type, message, flow, project, parameters, created_by |
The run is waiting on wait_for_input |
run.resumed |
state, state_type, message, flow, project, parameters, created_by |
The run was answered and its next attempt scheduled |
run.report_rejected |
seq, kind, reason |
The store refused one event of an engine's report; the rest of that report still applied |
run.local_path_on_worker |
path, host |
A run on a remote worker used a LocalTarget outside the worker's shared paths, so the file is on that machine only |
AwaitingRetry, AwaitingResource, and Cancelling record no event.
Task run events¶
Resource task_run (id is the task run's external id, name its dynamic key); related run and flow. Offline the payload is state and task_run.
| Event | Payload | When |
|---|---|---|
task_run.running |
task, dynamic_key, state, message, flow, project |
The task started |
task_run.completed |
task, dynamic_key, state, message, flow, project |
The task returned |
task_run.failed |
task, dynamic_key, state, message, flow, project |
The task raised or timed out (after its retries) |
task_run.cancelled |
task, dynamic_key, state, message, flow, project |
The task was cancelled with its run |
task_run.skipped |
task, dynamic_key, state, message, flow, project |
The task's output= target already existed |
task_run.cached |
task, dynamic_key, state, message, flow, project |
The task returned a persisted result |
task_run.replayed |
task, dynamic_key, state, message, flow, project |
The task returned the checkpoint an earlier attempt of the run recorded, without executing |
Flow events¶
Resource flow.
| Event | Payload | When |
|---|---|---|
flow.registered |
flow, project, module |
The server registered the flow at start or on handoff |
flow.disabled |
failures, window_seconds, until |
disable_after tripped; the flow's schedules are paused until until |
flow.enabled |
empty | The disable window ended and the schedules resumed |
flow.fan_in |
key, value, upstream, run_id |
Every upstream completed a run for the key value and the downstream run was created |
flow.recovered |
flow, project, failures, run_id |
A run completed after the flow's previous terminal run had failed or crashed |
Schedule events¶
Resource schedule, related flow.
| Event | Payload | When |
|---|---|---|
schedule.paused |
schedule_id, reason |
A schedule was paused from the UI, the API, an MCP tool, a rule, or a disable window |
schedule.resumed |
schedule_id |
A schedule was resumed |
schedule.catchup |
schedule_id, policy, missed, created, dropped |
The server started and applied the catch-up policy to fires missed while it was down |
schedule.skips_dropped |
schedule_id, dropped |
An edit, or a restart that restored a code declaration, left skipped fires the schedule no longer produces, and they were forgotten |
Scheduler events¶
Resource scheduler: the server's scheduler as a whole, paused and resumed with POST /api/scheduler/pause and POST /api/scheduler/resume or the MCP pause_scheduler and resume_scheduler tools.
| Event | Payload | When |
|---|---|---|
scheduler.paused |
reason, until, suppress_rules |
Every schedule was paused at once, for maintenance or an incident; running runs continue |
scheduler.resumed |
held, schedules |
The global pause ended: held runs started and each schedule caught up under its own policy |
Backfill events¶
Resource backfill.
| Event | Payload | When |
|---|---|---|
backfill.completed |
backfill_id, counts |
The last run of a backfill reached a terminal state |
Resource events¶
| Event | Payload | When |
|---|---|---|
resource.exhausted |
resource |
A run waited for a resource that had no capacity; recorded once per wait |
Rule events¶
Resource rule, related the run and flow of the triggering event.
| Event | Payload | When |
|---|---|---|
rule.fired |
rule_id, rule, event, event_id |
A rule matched an event and its actions started |
rule.action.completed |
rule_id, action, index, detail |
One action finished |
rule.action.failed |
rule_id, action, index, error |
One action failed, including a template that did not render |
expectation.armed |
id, rule_id, key, run_id, deadline |
A proactive rule's when event armed an expectation |
expectation.met |
id, rule_id, key |
The expected event arrived before the deadline |
expectation.lapsed |
rule_id, rule, flow, project, run, run_name, expected, deadline, armed_at, expectation_id |
The deadline passed, or a clock-armed rule's tick found no matching event; the rule's actions run against this event |
Runs created by a rule record created_by = rule:<id>, and a rule never fires on events of runs it created unless allow_self is set.
Worker events¶
Resource worker. Recorded by the server for a remote worker; see Run across machines.
| Event | Payload | When |
|---|---|---|
worker.registered |
worker_id, name, version, refused, drift |
A remote worker registered, or registered again after a restart |
worker.offline |
worker_id, name |
A remote worker missed three heartbeats; runs its engines held are crashed and rerun by their own heartbeats |
Custom events¶
cereyan.emit_event(name, payload=None, resource=None) records any name of your own. Inside a run the resource defaults to that run and the task run is recorded; outside a run the event goes to the store, or to the server's POST /api/events when one holds the store.
Names with a dot-separated prefix, such as orders.table_empty, match rules with events: ["orders.*"].
The prefixes run., task_run., flow., schedule., scheduler., resource., rule., expectation., backfill., worker. are the engine's. A name under one of them that is not in the catalogue above is rejected by emit_event, by @app.rule, and by the rules API, because nothing would ever emit it — a rule matching one could only ever sit silent. Every other name is yours and is never checked.
Stream messages¶
The SSE stream at GET /api/stream carries live notifications for the UI. They are not stored events and rules cannot match them, even where a name is shared with one: run.updated is a stream message, so a rule naming it is rejected.
| Message | Data | Sent when |
|---|---|---|
hello |
latest, since |
The connection opens, before any backlog |
run.updated |
The run | A run was created or changed state |
task_run.updated |
The task run | A task run was created or changed state |
log.appended |
run_id, last_id, count |
New log lines arrived |
event.created |
The event | Any event was recorded |
flow.registered |
The flow | A flow was registered or re-registered |
rule.updated |
The rule, or id and deleted |
A rule was created, edited, fired, or deleted |
variable.updated |
The variable, or name and deleted |
A variable was set or removed |
artifact.updated |
The artifact | A run published or updated an artifact |
schedule.updated |
The schedule, or id and deleted |
A schedule was created, edited, paused, resumed, or deleted |
worker.updated |
id |
A worker registered, reported a change on a heartbeat, was resized, drained, resumed, left, went offline, or was forgotten |
backfill.created |
backfill_id, flow_id, count |
A backfill created its runs |
backfill.updated |
backfill_id, cancelled |
A backfill was cancelled |
expectation.armed, expectation.met, expectation.lapsed |
id, rule_id, and the key or the event |
A proactive rule armed, disarmed, or lapsed an expectation |
resync |
latest |
The client asked for a sequence number older than the replay buffer; refetch everything |
Each message carries the sequence number as its SSE id. Reconnect with ?since=<seq> to replay what was missed, or receive resync when the buffer no longer reaches back that far.