A trigger's then is one action or a list; every action runs.
Webhook
{"webhook": {"url": "https://example.com/hooks/coordinate", "signing_secret": "secret:HOOK"}}For a receiver built for Coordinate. The body is the firing as JSON: {version: "coordinate.webhook.v1", delivery_id, trigger, firing, event, rows, row, about}. With a signing secret, Coordinate-Signature: t=<unix>,v1=<hex HMAC-SHA256 of "<t>.<body>">.
API request
{"request": {"method": "POST", "url": "https://api.linear.app/graphql",
"auth": {"bearer": "secret:LINEAR"},
"body": {"query": "mutation($t: String!) { issueCreate(input: {teamId: \"T\", title: $t}) { issue { id } } }", "variables": {"t": "{{event.payload.title}}"}}},
"record": {"issue_id": "data.issueCreate.issue.id"}}For any API, in its own shape. auth is {"bearer": "secret:X"}, {"headers": {"x-api-key": "secret:X"}}, or {"connection": "github" | "<source>"} to use a connected source's credential. The host can't be templated, and a secret is only ever sent to the host it was first used with. With {"connection": "github"}, Coordinate uses the GitHub App installation for the account the URL names (/repos/{owner}/…), for any endpoint the app's permissions cover: metadata (stars, releases, topics), contents, pull requests, checks, and Actions. Reads (GET) of public repositories the app isn't installed on use Coordinate's own GitHub credentials, so watching any public repository needs no token. Only a private repository the app can't reach needs {"bearer": "secret:NAME"} with a personal access token. record copies fields from the JSON response into action.succeeded.
Emit
{"emit": {"type": "deploys.flaky", "payload": {"repo": "{{event.payload.repo}}"}}}Appends an event on source coordinate right away, for other triggers and agents to react to.
Messages
Send a message to wherever you'll see it. Email to yourself needs no setup; for the others, store the credential as a secret first (Settings → Secrets, or coordinate secret set NAME).
{"slack": {"webhook_url": "secret:SLACK_WEBHOOK", "message": "Deploy failed: {{event.payload.url}}"}}
{"discord": {"webhook_url": "secret:DISCORD_WEBHOOK", "message": "Deploy failed: {{event.payload.url}}"}}
{"email": {"subject": "{{trigger.name}}", "message": "Deploy failed: {{event.payload.url}}"}}
{"email": {"api_key": "secret:RESEND", "from": "Coordinate <alerts@your-domain.com>", "to": ["team@example.com"], "subject": "{{trigger.name}}", "message": "Deploy failed: {{event.payload.url}}"}}
{"poke": {"message": "Deploy failed: {{event.payload.url}}", "api_key": "secret:POKE"}}- Slack: in Slack, create an app with an incoming webhook for the channel (api.slack.com/apps → Incoming Webhooks) and store the
https://hooks.slack.com/…URL as a secret. The URL is the credential, so it is never shown again. - Discord: channel settings → Integrations → Webhooks → New webhook → Copy URL, and store the
https://discord.com/api/webhooks/…URL as a secret. Mentions in the message don't ping anyone. - Email: with just
subjectandmessage, Coordinate sends it from its own address to your workspace's email (Settings → Email), up to 50 a day. To email anyone else, or more, add your Resend API key asapi_key, a sender on a domain verified in Resend asfrom, and the recipients asto. - Poke: a text through Poke, framed so Poke knows it came from an automation.
- Anything else (ntfy, PagerDuty, Telegram, your own app): a
webhookwith the whole firing as JSON, or arequestin the API's own shape.
Claude agent
{"claude_agent": {"api_key": "secret:ANTHROPIC", "agent_id": "...", "environment_id": "...", "vault_ids": [...], "repo": "owner/name", "repo_token": "secret:GH", "rubric": "...", "message": "..."}}: starts a Claude Managed Agents session with the task as an outcome, the firing as data, and instructions to report back withemit(agent.completedoragent.failedwith the firing id ascorrelation_id). The session id is recorded.
Templates
{{event.payload.x}}, {{event.id}}, {{rows}}, {{row.x}}, {{trigger.name}}, {{firing.id}}, with |lower and |upper. A string that is exactly one placeholder keeps the value's type, so "{{event.payload}}" stays an object.
Delivery
Webhooks, requests, messages, and agent sessions are delivered at least once: up to 10 attempts over 24 hours, retrying network errors, 408, 429, and 5xx with backoff (honoring Retry-After). Redirects are not followed. A failure that won't recover becomes an alert. list_actions shows recent runs; retry_action sends a failed one again.