Skip to main content
An automation saves everything a session needs: a pinned agent version, an environment, an opening prompt, and run defaults such as credentials and files. Its triggers decide when it starts a session, and every start is recorded as a run, so you can see why each session began and what it was given. You can manage automations in the console, under Automations, or through the REST API with an API key. Both work on the same automations.
You need an agent version and an environment. Saving checks that both exist. Runs need the environment’s setup verified: a run on an unverified environment fails with environment_not_verified. See Agents and Verify the setup script. Slack and GitHub triggers also need an event source: connecting Slack or GitHub on Integrations creates one. See Receive events. Creating automations and starting runs by hand needs create permission, changing, pausing, and resuming them needs update, and deleting needs delete. Organization developers and admins have all of them. See Organizations and roles.

Create an automation

Choose the agent version, environment, and instructions, then add the triggers that should start runs.
  1. In the sidebar, click Automations, then click New automation. To start from a ready-made automation, click Start from a template at the top of the form and choose one; it fills in the name, triggers, and instructions, and you still choose the agent and environment.
  2. Name it, choose the agent, its version, and an environment.
  3. Under Instructions, write what the agent should do each time.
  4. Add triggers: Scheduled, Slack, or GitHub. With none, the automation runs only with Run now.
  5. Optionally set Credential access, Files, and, under Advanced, Run metadata.
  6. Click Create automation. It starts paused.
A 201 response is the full automation, with status paused and a revision. Some fields are left out here.
The ETag response header is an opaque validator; send it unchanged as If-Match on the next change. Do not construct it from the body’s revision. New automations start paused: test one with Run now from its row’s Actions menu, then resume it so its triggers can start runs. See Run, pause, and resume.
Every request field is required: displayName, agentId, agentVersionId, environmentId, initialPrompt, runDefaults (at least metadata, which can be null), and triggers (an empty list for manual runs only). You choose each triggerId yourself, as a UUID, and keep it stable across replacements.
Copy the complete returned ETag, quotes included. A missing If-Match returns 428 precondition_required; a stale one returns 412 precondition_failed. A public contract change can invalidate an ETag even when the body’s revision is unchanged: read the resource again before retrying. See Idempotent mutations and Errors.

Choose triggers

An automation has up to 20 triggers, and a run starts when any enabled one matches. The trigger types are schedule, slack, github, and webhook. Turn a trigger off with enabled: false to keep it without it starting runs. You can also start a run by hand at any time, even while the automation is paused.

Schedule

Starts runs on a cron expression read in a time zone, such as the create example’s 0 9 * * 1-5 in Europe/London: 9:00 on weekdays. By default, an occurrence is skipped while the previous run’s session is still going.
These fields go inside the trigger’s schedule object. Every one you save is applied to the schedule.
The console shows each schedule’s next and last run, upcoming runs, and occurrences skipped for overlap or missed outside the catch-up window. It also shows whether each saved schedule is in effect. getAutomationStatus returns the same values for each schedule trigger:

Slack

Starts a run for Slack messages. It needs a Slack event source: connect Slack on the Integrations page. Choose the message or app_mention event and the channels to accept. This trigger starts a run for each new top-level post in an incident channel that mentions a severity, and ignores other Slack apps:
  • Filter message triggers by text. Without a text filter, every new message in the trigger’s channels starts its own run and a paid session, with no cap. The editor warns about this but still saves. Add textContains or textMatches so only the messages you mean start work.
  • One post starts one run. Slack sends a message that mentions the app as both a message and an app_mention event. One post starts one run per automation, even when a trigger lists both events or two of its triggers each match.
  • Every Slack event starts a new session. A reply in the same thread starts another run with its own session; it doesn’t continue the earlier one.
The console lists up to 1,000 channels the connected Slack app is a member of. Invite the app to a channel to make it selectable. The same list is available from the API for a Slack connection:
  • Only newly posted messages start runs. Editing or deleting a message never starts one.
  • Direct messages to the app don’t start runs. Use a channel.
  • Stopping a Slack-started session posts nothing to its thread. The console reminds you when you force-stop or interrupt one. Reply in the thread yourself, or message the agent to post an update.

GitHub

Starts a run for GitHub webhook events. It needs a GitHub event source: connect GitHub on the Integrations page. This trigger matches pull_request deliveries in acme/api with the action opened or synchronize on fix/* branches, and ignores drafts and bots:
The event only starts the run. To read or change the repository, the agent needs a GitHub grant, and it works through GitHub’s MCP tools. No GitHub credential is placed in the sandbox, so git and gh there aren’t authenticated. See GitHub access.
Three more common triggers. This one hands a pull request to the agent when someone adds the agent-ready label:
This one starts a run when a pull request comment contains the command /agent fix:
This one starts a run when a CI workflow run on main finishes with a failure:
In globs, * matches any characters, including /, and ? matches one character.

Webhook

Starts a run for deliveries to a custom webhook source. The console offers this trigger when your organization has a custom source. Add filters.fieldEquals to start runs only for some deliveries. Each condition names a dot-separated path into the JSON body, such as data.level, and the value it must equal, written as JSON text without quotes.
To send deliveries to the source, see Send a custom webhook delivery.

Set run defaults

runDefaults applies to every run, whether a trigger or a person starts it.

Keep untrusted input in check

Event runs put outside text into the session: Slack messages, pull request and issue titles and bodies, comments, and webhook bodies. Treat that text as untrusted input. Someone who can post in the channel or open an issue can try to steer the agent.
  • Restricted environments drop web_fetch. A session an automation starts, or a session started from a Slack thread, gets no web_fetch tool when its environment limits internet access (limited or no access). The environment’s network policy is then its only way out.
  • Unrestricted environments keep web_fetch and full internet access. An injected instruction could ask the agent to send data anywhere. Use a limited environment for automations that read outside text, and grant only the credentials and repositories the task needs.
  • Webhook runs record only the sender’s headers. The event in a webhook run keeps the headers the sender sent. Headers added on the way to the event source are never recorded.
See Environments and Security.

Run, pause, and resume

Start one run by hand to test the automation, then resume it so its triggers can start runs.
  1. In Automations, open the automation row’s Actions menu.
  2. Click Run now to start one run, or Run with input to add a JSON payload. Both need create permission.
  3. Click Resume to let its triggers start runs, or Pause to stop them.
runAutomation answers with the run. What success means: the run moves from pending to created, and sessionId names the session it started. Follow that session like any other; see Sessions. Resume returns the automation with status active. Pausing stops triggers from starting runs; Run now still works. Each change raises the revision, so use the new ETag for the next one.
payload is optional and can be any JSON value up to 64 KiB (65,536 bytes) as JSON; a larger one is refused with 400 on payload.A run that couldn’t start a session ends failed with an error that has a code, a message, the field or resourceId responsible when there is one, and retryable.Resume is refused with 422 automation_reference_invalid while the automation’s agent, agent version, or environment is deleted; the automation stays paused. If a run fails because something the automation uses no longer exists, such as its agent, environment, a vault, a credential, or a file, the automation is paused, and the run’s error says what is gone. Fix the automation, then resume it.

See run history

In Automations, choose View runs from the automation row’s Actions menu. Each run shows its Trigger, when it started, and Session creation. Filter by status, trigger, or date, and click a run for its Run detail and a link to its session. In the API, list an automation’s runs, then read one. getAutomationRun returns one run with its frozen snapshots and effectiveInitialMessage.
listAutomationRuns returns runs newest first. Filter with automationId, triggerId, eventSourceId, triggerType, status, createdAtGte, and createdAtLt, and page with limit and cursor.

Change or delete an automation

Saving a change keeps the automation’s current status. Deleting it removes its triggers while preserving records for runs that already started.
In Automations, use the automation row’s Actions menu to open it for editing or to delete it. The automations list is newest first, and the editor shows the automation’s prompt and triggers. Click Save changes to save an edit.
If someone else saved the automation while you were editing it, Save changes saves nothing and shows This automation changed elsewhere. Nothing was saved. Choose Keep my edits to replace their version with yours on the next save, or Load the newer version to see what they saved.

Keep the agent version current

An automation keeps the agent version it was saved with. Later changes to the agent’s instructions, tools, and integrations don’t apply to its runs until you move it to the new version. In the Automations list, an Older version label marks automations that run an older version than their agent’s latest. When you open one, the drawer names both versions, for example “This automation runs Version 1 of backend-fixer. The agent is now on Version 2”, and offers Use Version 2. Click it, then Save changes. In the API, replace the automation with the new agentVersionId.

Receive events

An event source is an endpoint that receives events and checks they’re genuine. Automations listen to it through Slack, GitHub, and webhook triggers. One source can serve many automations, up to the enabled-trigger limit in Limits. Sources created by connecting an account are connection-managed: they start active, and you pause and resume them from the list.
Slack and GitHub sources check every delivery against a signing secret that the connection creates and manages. Signing secrets never reach an agent sandbox. Disconnecting the account removes its source and stops its triggers. Existing automations keep those trigger settings so you can select a new source after reconnecting.

Manage sources

In Automations, open the Event sources tab. Each source’s health and last delivery are columns in the list, and its row’s Actions menu pauses or resumes deliveries. A healthy source has received a delivery, which does not prove the provider can reach it right now. A connection-managed source is changed and removed through its connection on Integrations. A custom source can be deleted when no automation uses it.
listEventSources and getEventSource return sources, and getEventSourceStatus returns health, triggerCount, and lastDelivery. Pause and resume need If-Match with the source’s ETag. Set EVENT_SOURCE_ETAG to the complete header returned by getEventSource.

Send a custom webhook delivery

A custom source receives deliveries at its Callback URL, shown in Event sources. The full URL is the console’s address followed by the callback path, https://recursion.labelbox.com/agents/v1/event-sources/<eventSourceId>/events. Give it to the sender, and resume the source when you’re ready to receive events. Send a JSON body with POST to the callback URL. For an hmac_sha256 source, compute the HMAC-SHA256 of the exact body bytes, keyed with the source’s signing secret, and send it as lowercase hexadecimal in the signature header, after the prefix. Sign the bytes you send; re-serializing the JSON after signing breaks the signature.
A delivery that’s accepted returns 200 with {"ok": true}, and matching triggers on active automations start runs. The same signed body is treated as the same delivery, so a retry doesn’t start a second run. For an unsigned source, send an X-Webhook-Id or Idempotency-Key header to name the delivery.

How automations run

  • Every run uses the pinned agent version. Publishing a new agent version doesn’t change the automation. See Keep the agent version current.
  • Everything is frozen per run. A run records the automation, trigger, and event exactly as they were, and the session’s opening message. Editing the automation later doesn’t change runs already started.
  • The opening message is your saved prompt. For an event run, it’s followed by Event for this run: and the event as JSON. For a manual run with input, it’s followed by Input for this run: and the input. For a scheduled run, it ends with This is a scheduled run for <time>., where the time is the occurrence in UTC, such as 2026-10-01T08:00:00Z.
  • Sessions show where they came from. A session an automation started shows Started by in its session panel: the automation, the trigger (Manual, Schedule, Slack, GitHub, or Webhook), and the run, each linked.

What can go wrong

The most common problems:
  • A run is failed. The session couldn’t start. Read the run’s error. If retryable is true, run it again; otherwise fix the named field or resource.
  • An automation paused on its own. A run found that something it uses was deleted. Read the failed run’s error, fix the automation, then resume it.
  • An event starts no runs. Check the source status and the trigger filters. A Slack message that was edited, deleted, or sent as a direct message never starts a run.
  • Runs still use access you removed from the agent. The automation runs its pinned agent version. Move it to the new version. See Keep the agent version current.
For every error code, see Errors.

Limits

Limits on triggers, prompts, names, run input, run defaults, schedules, trigger filters, and custom webhook bodies are in Limits. Two more apply here:
  • A page of automations or event sources holds 1 to 100 items, 50 by default.
  • Name and prompt limits count UTF-8 bytes, not characters: an emoji or a non-Latin letter takes 2 to 4 bytes, so a name in those scripts fits fewer than 256 characters.

Next steps

Integrations

Connect Slack and GitHub to get event sources.

GitHub access

Give automated runs access to the repositories they work on.

Files

Mount the same files into every run.

Sessions

Follow the sessions automations start.