Skip to content
View as .md

Workflow triggers — open webhook decisions

Status: idea. The framing is settled in durable-workflows § Triggers — one door, not a plane: triggers aren’t a plugin plane, they’re callers of one door (wf_spawn(id, payload)). This note only holds the decisions the inbound-webhook door still forces — read that section first.

Goal

Let a workflow author declare an external caller: a stable signed URL that an outside system (GitHub, Linear) hits to spawn a run, its body becoming the payload. Schedule (built) and manual spawn (built) already cover the other callers. The webhook is the one seam left.

Settled (don’t relitigate)

  • No triggers[] list, no api kind. Manual spawn with a payload (POST /api/workflows, bot-key authed) already is the API trigger — a second per-workflow token would duplicate the house key. Schedule stays its own column + pg_cron mirror; don’t migrate it for symmetry.
  • Payload is pass-through. The body lands in payload untouched; recipes shape it with {{path}}, rendered in the conductor, unresolved paths fail early. No ingest-time mapping DSL.

Open decisions (the webhook door forces these)

  • Storage. The webhook caller needs a row, not a jsonb element: stable id (the URL embeds it), enabled, rotate/revoke, a rate cap, last_fired_at. You can’t cleanly disable the Nth element of an array.
  • Signing secret is trigger-owned, not a house secret. House secrets are name-unique, sandbox-injected, member-readable — a signing secret is none of those. Reuse Vault storage, verify server-side like x-conductor-secret / hashApiKey; don’t put it in the secrets namespace.
  • Idempotency. Webhooks retry — derive Absurd’s idempotency key from the delivery id (X-GitHub-Delivery) so a redelivery doesn’t double-spawn. wf_spawn takes no key today, so this shapes its signature now.
  • Why-a-run-fired. Record trigger ref + raw inbound body on the run so arbe wf show can say “fired from the GitHub webhook at 04:02 with this body.”

Ship-gate

Per-trigger rate cap is a gate, not a caution: the webhook door doesn’t ship enabled without a count window in the trigger row returning 429 past it. With no external users, the real failure is our own runaway loop, and one hit = one sandbox run = real money.

See durable-workflows, system/secrets, workflows.