Skip to content

Set up pipeline triggers

A trigger is what starts a pipeline. Every trigger a template has — including the one that makes it manually runnable — lives on the Trigger entry node in the template editor. There is no triggers tab and no triggers screen.

  1. Go to Settings → Workspace → Pipeline templates.
  2. Press the pencil on the template’s row to open the editor.
  3. Click the Trigger node on the canvas. The right panel switches from the normal node form to the trigger panel.

The panel has two parts: a Manual run switch at the top and an Automatic triggers list below it.

Turn on the Manual run switch to make the template appear in the run launcher. It is not a special case — the switch inserts and deletes an ordinary trigger row whose event type is manual. It persists immediately; there is nothing to save.

  1. Press Add trigger under Automatic triggers.
  2. Pick a Trigger type: On an event, On a schedule, or Via a webhook.
  3. Fill in that type’s fields (below).
  4. Press Add.

The trigger is live the moment you press Add — there is no separate enable step. Use the switch on its row to turn it off later, or the bin icon to delete it.

Pick the domain event from the Event dropdown. These fourteen carry a payload and can fire:

Picker label Event
External PR opened ExternalPrDetected
PR published PullRequestPublished
PR status changed PullRequestStatusChanged
PR merged PrMerged
Message received MessageReceived
Ticket assigned TicketAssigned
Ticket completed TicketCompleted
Ticket failed TicketFailed
Ticket cancelled TicketCancelled
Budget threshold crossed BudgetThresholdCrossed
Repository added RepoAdded
MeetingRecordingStopped MeetingRecordingStopped
SkillUpdated SkillUpdated
SpaceDeleted SpaceDeleted

The last three have no display label yet, so they show their raw type name. SpaceDeleted is what the built-in worktree-cleanup pipeline listens on: it carries the deleted space’s id, so the run reclaims exactly that space’s worktrees instead of sweeping the whole workspace.

For the payload keys each event carries, see the domain events reference.

The only filter the dialog can author is the status chip set and it appears only when the event is PR status changed. Tap any of merged, closed, approved, opened, reopened; the trigger then fires only when the event’s status matches one of them. Leaving every chip unselected means no filter.

There is no free-form JSON filter field. A filter key that the event’s payload does not carry never matches, so do not hand-author one against a key you have not confirmed in the domain events reference.

Field Description
Schedule (cron or every:seconds) A five-field cron expression such as 0 9 * * 1, or an interval such as every:86400. A bare number is coerced to every:<n>.
Timezone (optional) An IANA zone such as Europe/Paris. Defaults to UTC.
On missed runs What to do about fires missed while the server was down: Run once collapses every missed slot into one fire on restart (the default), Skip resumes at the next future slot.

The trigger row’s summary line only spells out the interval for the every:<seconds> form; a cron expression shows as just “Schedule”.

Choosing Via a webhook takes no fields — pressing Add mints a random token for the trigger.

The endpoint is POST /webhooks/<token> on the server. The token is also the HMAC secret: the request must carry X-Hub-Signature-256: sha256=<hex>, where the hex is HMAC-SHA256(body, token). A delivery that fails verification is rejected and logged and is not replayable. Duplicates are ignored by their dedupe key.

An enabled trigger whose event type and filter both match starts a run with the event’s payload as the run’s trigger payload — that is what {{key}} in a step’s prompt or script resolves against. Events that carry a natural key are de-duplicated, so the same event firing twice does not start two runs.

A disabled template is refused even when its trigger matches. Eight of the thirteen built-in templates ship disabled, so their seeded triggers fire into nothing until you turn the template on.

  • Review every new PR — event PR published on the pr_review template.
  • Clean up after a merge — event PR merged. The built-in pr_merged_cleanup template already ships wired this way, plus a daily schedule that is force-enabled on every re-seed because it is garbage collection.
  • Nightly sweep — schedule 0 2 * * * with a timezone, on a template whose first node is a bash script.
  • React to an external system — a webhook trigger, with the calling system signing its request body as above.