Filter on the source, transform on the attachment
Two separate concerns, in two separate places:| Concern | Question | Where it lives |
|---|---|---|
| Filter | Should this run at all? | The source: webhook request/filter, poll filter |
| Transform | What input does the run receive? | The attachment: transform on a workflow target |
Transform a workflow input
A workflow target accepts an optionaltransform that maps the (already validated and filtered) source payload into the workflow’s input. Use it to reshape a third-party payload into the clean shape your workflow expects.
src/triggers/incoming-message.ts
input schema, so the workflow still gets a validated payload. If you omit transform, the matched payload passes straight through to input (extra fields are ignored).
Attach to an agent
Instead of a workflow, a source can attach to an agent. An agent target takes aprompt instead of a transform; the payload becomes a prompt rather than a typed input.
src/triggers/signup.ts
prompt can be a static string or a function of the payload. A transform is not used for agent targets; the agent receives the payload directly through its prompt.
Prompt interpolation
For a static prompt string, you can interpolate payload fields with{{payload.path}} placeholders instead of writing a function:
Fan out to multiple targets
One source can drive several workflows and/or agents. Chain.attach() once per target — each call binds the same source to another workflow or agent:
src/triggers/inbox-check.ts
run() and filters execute a single time) and then fans out to every attached target. The fire is recorded once and links to all the runs and sessions it started. Every target keeps its own attachment id ({sourceSlug}:{targetSlug}), so the two agents above are inbox-check:assistant and inbox-check:assistant-vm.
This works for all three source kinds (schedule, webhook, and poll). Each {source}:{target} id must be unique, so a given workflow or agent can only attach to a source once.
Skipping a run
A source can decide a particular event isn’t worth a run:- Poll: if a filter returns
false, the tick is skipped and no run is created. Skipped poll ticks don’t count toward execution limits. - Webhook on a shared endpoint: a payload that matches no trigger on the endpoint returns
{ ok: true, skipped: true }. See shared endpoints.
Inspect what ran
Every trigger-driven run is recorded under the attachment id. Audit them from the CLI:Next steps
App events
React to events from connected third-party apps.
Webhooks
Endpoints, validation, filters, and shared routes.
Run agents
How agents run and how to inspect their sessions.
Run history
Review trigger-driven runs in the web app.