Guides
Automations
Run agents on a schedule, from a webhook or on an event, with retries and outcomes.
Use an automation for recurring or event-driven work, such as a morning review or a reply to a
support request. It runs an agent when its trigger fires, then applies the configured success or
failure outcome. Users create and activate automations at /dashboard/automations. Each run is
durable and keeps a step-by-step history.
An automation belongs to the person who created it, in one workspace.
Shipping Templates in Code
Files in server/automations define templates. A workspace installs a template as an inactive
draft in the Templates folder, reviews it, and switches it on. This template runs the
account-manager agent every weekday morning:
export default defineAutomation({
name: 'Weekday account review',
description: 'Every weekday morning, refresh summaries for customers changed yesterday.',
trigger: {
kind: 'schedule',
event: 'schedule',
slug: 'weekday-account-review',
cron: '0 8 * * 1-5',
timeZone: 'Europe/Amsterdam',
},
agent: 'account-manager',
instructions: 'Review customers updated in the last day and refresh their summaries.',
})
| Option | Description | Default |
|---|---|---|
name | Shown in the dashboard | required |
description | Shown in the template list | '' |
slug | Template id used to install it | the file name |
trigger | { kind, event, slug, cron?, timeZone? }; see Choosing a Trigger | required |
agent | Slug of a code agent in server/agents | required |
instructions | The task for this automation, given to the agent with the payload | 'Use the event payload to complete your task. Return a concise result.' |
timeout | Seconds before a run fails: 15, 30, or 60 | 30 |
retries | Retry attempts after a failure, 0 to 5 | 2 |
success | { action, target }; see Handling the Result | { action: 'none', target: '' } |
failure | { action, target } with none, notify, or slack | { action: 'none', target: '' } |
runAs | owner: the owner's and the workspace's connections; workspace: shared workspace connections only | owner |
Installing fails with 409 until the workspace can see the agent file the template names.
Choosing a Trigger
Running on a Schedule
Set kind: 'schedule' with a five-field cron expression and an IANA timeZone, as in the
template above. The scheduler Durable Object wakes each active automation at its next time.
Starting from a Webhook
Every webhook automation has a secret URL, /api/agentic/hooks/<automation id>/<token>, shown in
the dashboard. The starter's support inbox uses one:
export default defineAutomation({
name: 'Support inbox',
description: 'Answer support questions posted to a webhook, for example from a form or inbox.',
trigger: { kind: 'webhook', event: 'webhook', slug: 'support-inbox' },
agent: 'support',
instructions: 'Answer the question in the payload. Return a reply ready to send.',
success: { action: 'none', target: '' },
})
The sender posts a JSON body, which becomes the run payload, with a unique Idempotency-Key
header of at most 200 characters:
curl -X POST "https://app.example.com/api/agentic/hooks/12/<token>" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: form-submission-4821" \
-d '{"question":"How do I move to the pro plan?"}'
The same key never starts a second run, so a sender can retry safely. The endpoint answers
202, accepts bodies up to 1 MB, and starts only active automations whose agent is active. A
webhook slug uses lowercase letters, numbers, and hyphens.
Reacting to Events
Set kind: 'event' and the event name in event. Events come from connected integrations, such
as a new GitHub issue, or from your own server code. Deliver an app event with the services:
export default defineEventHandler(async (event) => {
const order = await readBody<{ id: number; total: number }>(event)
const { automations } = await useAgentic(event)
return automations.deliverEvent({ event: 'order.paid', id: String(order.id), payload: order })
})
deliverEvent starts the signed-in user's own active automations in the current workspace whose
trigger listens for that event. id is a string of up to 200 characters that makes delivery
idempotent: the same event and id never start a second run.
Handling the Result
The success outcome runs after the agent finishes; the failure outcome runs when the last
retry fails. target can use {{ payload.field }} placeholders with primitive payload values.
| Action | Target | Where |
|---|---|---|
none | Nothing: the result stays in run history | Both |
email | An address or a payload path such as user.email, sent through Gmail | Success |
slack | A channel of a connected Slack account | Both |
webhook | An HTTPS URL whose origin is listed in AGENTIC_WEBHOOK_ORIGINS | Success |
record | A field on the triggering record; see Outcomes | Success |
notify | An address for a failure report through Gmail; empty sends it to the owner | Failure |
Email and Slack outcomes need a connected account with send_email or post_messages granted.
With runAs: 'workspace', only workspace connections count. A webhook outcome posts
{ payload, output, error, runId } with an Idempotency-Key header, so the receiver can ignore
a retried delivery.
Starting and Controlling Runs
From the dashboard or the services, you can start an automation by hand, resume an unfinished run, and cancel a running one:
const { automations } = await useAgentic(event)
const { runId } = await automations.start(automationId, { payload: { customerId: 42 } })
A manual start also works for inactive drafts, which makes it the way to test a template before
you switch it on. Pass eventId to make a manual start idempotent. Runs that wait for an approval
continue after someone answers it.