Skip to content

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:

server/automations/weekday-account-review.ts
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.',
})
OptionDescriptionDefault
nameShown in the dashboardrequired
descriptionShown in the template list''
slugTemplate id used to install itthe file name
trigger{ kind, event, slug, cron?, timeZone? }; see Choosing a Triggerrequired
agentSlug of a code agent in server/agentsrequired
instructionsThe task for this automation, given to the agent with the payload'Use the event payload to complete your task. Return a concise result.'
timeoutSeconds before a run fails: 15, 30, or 6030
retriesRetry attempts after a failure, 0 to 52
success{ action, target }; see Handling the Result{ action: 'none', target: '' }
failure{ action, target } with none, notify, or slack{ action: 'none', target: '' }
runAsowner: the owner's and the workspace's connections; workspace: shared workspace connections onlyowner

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:

server/automations/support-inbox.ts
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:

server/api/orders/paid.post.ts
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.

ActionTargetWhere
noneNothing: the result stays in run historyBoth
emailAn address or a payload path such as user.email, sent through GmailSuccess
slackA channel of a connected Slack accountBoth
webhookAn HTTPS URL whose origin is listed in AGENTIC_WEBHOOK_ORIGINSSuccess
recordA field on the triggering record; see OutcomesSuccess
notifyAn address for a failure report through Gmail; empty sends it to the ownerFailure

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.