Skip to content
archmax.ai

Triggers

A trigger is how a session starts, or how a parked one resumes. Each arrival is a firing. For every trigger the environment’s published version declares, the platform keeps a deployment: the scheduler, the polling cursor or the registration that makes the trigger fire. You declare triggers in the editor; publishing deploys them.

A trigger is declared under the triggers: of the state it enters, keyed by its id. That state is the trigger’s start state, and a trigger has at most one. A state may be the entry for several triggers, each with its own declaration:

states:
intake:
triggers:
manual:
description: Look into one order.
requires:
- order_id
nightly:
type: schedule
cron: "0 2 * * *"
timezone: Europe/Berlin
order-hook:
type: webhook
connection: orders-hook
guards:
body.type:
- order.created
- order.paid
new-email:
type: ap
piece: microsoft-outlook
trigger: newEmail
connection: outlook-support
guards:
from.emailAddress.address: "*@example.com"
instructions: Work out what arrived and answer it. This state is terminal.
chat-answer:
triggers:
chat:
session: triggers.-1.threadId
connection: support-widget
examples:
- Where is my order?
mcp:
description: Answer one question about an order.
requires:
- question
connection: partner-agents
instructions: Answer the question directly. This state is terminal.

The id is authored: adding, reordering or removing one declaration leaves every other id, and so every other deployment, as it was. In the editor, a state’s Trigger section adds triggers through one picker (Manual, Chat, MCP, Schedule, Webhook and Completion under the platform, then each collection’s triggers) and expands each into its settings. manual, chat and mcp are held by at most one state each, so assigning one to a state moves it there. See the harness’s triggers guide for what the runtime reads.

Trigger Declared as Starts a session when Deployed
manual manual: you start it from the editor or the Sessions page, an evaluation runs a case, or another workflow calls it never: nothing to deploy
chat chat: a message arrives: from the Chat page, the editor’s chat surface, or the endpoint of the AG-UI incoming connection it names only when it names a connection
mcp mcp: an MCP client calls the workflow’s tool at the endpoint of the MCP incoming connection it names only when it names a connection
schedule type: schedule, cron, timezone the cron expression matches, read in timezone (UTC when unset) yes
webhook type: webhook, connection an HTTP POST reaches the endpoint of the webhook incoming connection it names only when it names a connection
piece trigger type: ap, piece, trigger, connection, props the piece reports a new item, by polling or by calling back yes
completion type: completion, workflow a turn of a production session of the named workflow succeeds or fails yes, with no scheduler or address

The editor lists a piece trigger’s properties under its connection. Each one the piece requires carries a Required flag, which turns into a warning while the property holds no value. A property whose options come from the connection (a spreadsheet, a folder, a channel) opens a picker. The picker also takes a value it does not list: type it into the search and choose Use this value.

The editor authors a signature on manual and mcp: requires lists the variables a start must supply, each a name or { name, type, description }, and returns the variables the session guarantees when it completes. A start missing one, or supplying a value of the wrong type, is refused before anything executes.

A type: file entry’s value is a path from the workspace root that names one file.

  • Starting by hand: you upload the file. The platform places it in the new session’s attachments/ and sets the variable to its path. Uploads take at most 20 MiB in one start.
  • Through the API: a start may name a path instead. It can be a file in the session, such as attachments/invoice.pdf, or one in the agent’s workspace, such as skills/billing/assets/template.pdf.
  • A path that is not well-formed is refused like any other value of the wrong type.
  • A path that names no file the session may read is refused by the runtime when the session opens, before the agent runs. The turn fails with a message naming the variable.

An mcp trigger declares no type: file entry, in either list. An MCP call can neither hand a session a file nor receive one, so validation reports the entry as an error, and the editor offers File on manual only.

chat takes up to six examples, the prompts the Chat page offers before a chat’s first message, and mcp takes trace, whether a call’s result carries the agent’s messages and tool calls. Endpoint triggers are covered in Chat, AG-UI and MCP endpoints.

A firing first resolves its session (see Sessions and decisions). A firing that starts one opens a session at the trigger’s start state; a firing for a parked session is delivered into it. Either way the firing’s payload is appended to the turn’s triggers variable, oldest first, so the firing that just arrived is always triggers.-1 and its fields sit directly on it (triggers.-1.subject). A manual start and an MCP call carry variables instead of a payload and seed no triggers variable.

A session opens with the firing’s words when it carries any, decided in this order:

  1. the trigger’s message path, a dotted path such as triggers.-1.body.content, or false for a trigger whose firings carry no message;
  2. without one, the payload’s own top-level message, text or content, the first that is a non-empty string;
  3. otherwise a notice naming the trigger.

The trigger’s session path decides which session a firing belongs to: firings that resolve the same value continue one session. Both paths are fields of an event trigger’s row in the inspector. A chat trigger’s session path is the platform’s own and is shown read-only.

A payload too large to seed becomes a marker naming its size and its top-level keys; the full payload stays readable in the trigger’s past firings.

Deployments are computed from the environment’s current published version alone, never from the draft. A trigger you have saved but not published is not deployed, and publishing is what deploys it. The platform reconciles an environment’s deployments after:

  • a publish, a version restore or a promotion into it;
  • a credential change in it, or in an environment it inherits credentials from;
  • a member’s Retry now on a failing deployment;
  • an automatic retry of a deployment in error that has fallen due.

A pass activates what is missing, re-activates what changed, and deactivates what the version does not declare. A deployment that is active and unchanged is left alone, keeping its polling cursor, and one failing activation never stops the others. A deployment is active, inactive, or error with its message. Two triggers configured identically are two deployments, each opening its own sessions.

chat, mcp and webhook are endpoint triggers: they deploy only when their declaration names an incoming connection of the matching protocol, whose endpoint is their address. The address belongs to the connection and is never rotated by a publish. One that names none is still startable from inside the product: chat from the Chat page, mcp from the editor’s ▶, and webhook through a listen window.

Deleting an environment or an agent takes its deployments down first, unregistering any callback address from its service. Reconciling every environment at once is an operator action (see Operating a deployment).

A schedule fires on its five-field cron expression, each firing opening one session whose payload records when it fired (scheduledAt, firedAt). The Sessions board lists every active schedule’s next firing at the top of its Planned column.

A webhook is reached at /api/webhooks/<token>, the endpoint of the webhook incoming connection it names, which admits a delivery by its authentication mode and rate limit. An admitted POST becomes the payload { method, headers, query, body }: the body parsed when it is JSON, and only the content-type, user-agent and x-request-id headers. The endpoint answers 202 with a delivery id. A sender’s X-Delivery-Id header, or failing that a digest of the body, makes a retried delivery fire once. An address that serves no active deployment answers 404 and reveals nothing more.

A piece trigger is one of the triggers an Activepieces collection offers. It authenticates through its connection, or through the collection’s only connection when it names none; with several and none named, its deployment fails rather than guessing. A missing connection is a warning in the editor and error on the deployment, never a reason the workflow cannot be saved.

  • A polling trigger is polled once a minute. Each poll opens one session per new item and moves the cursor past them, so no item fires twice. A failed poll is recorded and polling goes on; five failures in a row put the deployment in error.
  • A callback trigger has the platform register an address of its own, /api/callbacks/<token>, with the piece’s service when it is activated, and unregister it when it is deactivated. The address is kept for the life of the deployment. Each request the service sends opens one session per item it carries; a request that carries none, such as a ping, opens nothing.

A piece trigger’s code runs in a worker, never in the platform’s API or dispatcher processes. Its activation, every poll, each request a callback trigger’s service sends, each renewal of its registration, a test in a listen window and its deactivation each run in a worker of their own. That worker holds only the credential of the trigger’s connection, and reads and writes the deployment’s own store, such as its polling cursor or its registration’s id, through the platform. When a service checks a callback address with a handshake before it accepts it, the piece’s answer is computed the same way while the service waits.

A completion trigger lets a workflow look back at another workflow’s sessions, to rate how helpful a chat was, classify what a session was about or follow up on it. It names the other workflow under workflow:

states:
rate:
triggers:
rate-support:
type: completion
workflow: support-chat
guards:
trigger: chat
tools:
allow:
- sessions__read_subject
- tool: sessions__set_attributes
args:
session: "${{triggers.-1.session}}"
instructions: >-
Read the chat with sessions__read_subject, rate how helpful the last reply was from 1 to 5,
and record it with sessions__set_attributes as helpfulness, passing
session "${{triggers.-1.session}}".
  • When it fires. Each turn of a production session of support-chat that ends fires it once:

    • a turn that succeeded;
    • a turn that failed after it started, through archmax_raise, a tool’s error or a refused return.

    It never fires for a turn a member stopped, for a turn that failed before it started (a firing a spend cap refused), or for a parked turn. A parked turn fires once it is resumed and ends. Testing sessions and evaluation cases fire nothing. Neither does a session that a completion trigger opened, so a chain or a loop of completion firings cannot form. Guard on status to look back at only successes or only failures.

  • One session per firing. Every firing opens a session of its own about the finished session, its subject session. A completion trigger takes no session path. The session it opens belongs to the member the subject belongs to, so a rating of a member’s personal chat is personal too.

  • The payload. triggers.-1 describes the subject session: session, workflow, turn, status (succeeded or failed), trigger (what that turn was taken through), origin, turnCount and finishedAt, plus title, state, tags, attributes, returns, startedAt and, for a failed turn, error (its first 2,000 characters) when they are set. It carries no message, so the session opens with a notice naming the trigger unless you declare a message path.

  • Reading and recording. The payload does not include the transcript. The Sessions tools read and record it (see Session attributes):

    • sessions__read_subject reads the subject’s transcript, turn by turn;
    • sessions__set_attributes with session: "${{triggers.-1.session}}" writes the verdict onto the subject, where the Sessions table can show it as a column. The guard in the example binds the argument to that session.
  • Validation and deployment. The trigger must name a workflow other than its own that the environment holds; validation reports anything else as an error. Its deployment is active with no scheduler or address. It is in error while the published version does not hold the named workflow, and the next publish that does activates it.

A webhook, piece or completion trigger may declare guards: payload field paths, each with one glob pattern or a list of them, the same shape a tool’s argument guards take. A firing reaches a session only when every guarded field matches one of its patterns. * matches within one /-separated segment and ** across segments, a list value is matched as its comma-joined elements, a missing or null field matches nothing, and matching is case-sensitive. A pattern cannot read a variable, since no session exists yet.

A firing that fails a guard is declined: it starts nothing, is delivered into nothing, and is logged naming the field, while the deployment stays healthy. Editing a guard does not re-activate the deployment or reset its cursor. In the editor, the trigger’s shield control offers the fields recent firings carried (and a piece’s sample payload, or a completion trigger’s payload fields) or any path you type, and the guard’s editor offers the values those firings carried.

The ▶ beside a start state starts a session through its trigger; on a state with several triggers it first lists them. For manual and mcp it first asks for the declared variables when the entry declares any, typed and prefilled from the latest turn (a File input is chosen again), then starts. For chat it opens the chat surface over the graph. In the session view, a manual start takes the next turn on the selected session rather than opening a new one. For an event trigger it opens a listen window for 120 seconds:

  • when the trigger’s deployment is active and deploys what the draft declares, the window watches it, and the next firing it receives opens the session;
  • otherwise the window listens on the draft and changes no deployment. A webhook gets a test address that accepts deliveries only while the window waits. A schedule fires once, immediately. A polling trigger runs a test poll and fires the first item that passes the guards. A callback trigger whose piece can read recent events from its service fires the first of them; one whose piece cannot is tested once it is published.
  • A completion trigger fires once, immediately, whether its window watches the deployment or the draft. It fires about the newest finished turn of the named workflow, succeeded or failed, among its 20 newest, that passes the guards. Testing sessions count, so you can run the named workflow from the editor and then listen. With nothing to look back at, the window fails and says why.

A session a listen window opens is a testing session and executes the draft. Listen again re-arms a spent window. The same row offers the trigger’s past firings: choosing one replays its payload as a new testing session. A replay is refused when the current definition does not bind the trigger, or when the payload fails its guards.

A deployment that enters error is retried on its own: 15 minutes after the first failure in a row, then 30 minutes, 1, 2 and 4 hours. The sixth failure in a row exhausts its retries: it stays in error and only a publish, a credential change or Retry now tries it again. Those make a failing deployment due at once without resetting its count. The count returns to zero when one of its polls, renewals or callback requests succeeds, or, for a deployment that polls nothing, when it activates. Endpoint triggers fail only on their connection, or an mcp trigger on a type: file entry, which no retry fixes; every reconciliation pass, such as the next publish, evaluates them again.

In the inspector, the row of a trigger the published version deploys shows its deployment’s status: Active, or Failing with the message and when it is retried, or that it stopped retrying, together with Retry now. A trigger only the draft declares shows no status.

A firing that would start a session of a workflow declaring disabled: true is declined: no session opens, and the deployment stays active with its cursor and its address. A firing for one of its parked sessions is still delivered.