Automation reference and limits
The exact values behind the automation engine. Flow and step grammar, the expression syntax, per-skill output contracts, the real-time event names, and the platform's hard limits in one place.
This is the value reference for automation. Use it to confirm a field name, an operator, an output field, an event name, or a ceiling by its exact value. It covers the grammar that defines a Flow and its steps, the expression syntax those steps use, the structured result each skill returns, the real-time events the platform emits while work runs, and the hard limits that bound all of it. The concepts behind these values live in the Flows, Build a Flow, and Skills guides.
A Flow is agent work that executes: ordered steps, checkpoints, and results. A Workflow is the set of statuses a record moves through. They are different features. This page is about Flows. Workflow statuses are in the statuses reference.
Flow definition grammar
A Flow is a template made of a few named parts. These are the exact fields.
| Field | Type | What it holds |
|---|---|---|
flowId | string | The Flow's stable identifier. |
scope | string | Where the template comes from: global, repo, or filesystem. |
usableScope | global / initiative / plan | Where a run may be launched from. Optional. |
title | string | The display name. |
description | string | What the Flow does. |
steps | step array | The ordered units of work. |
parameters | parameter array | The inputs supplied at run time. |
defaults | defaults object | How the run behaves unless overridden. |
trigger | trigger object | An optional rule that fires the Flow on its own. |
Step fields
Each step runs one skill and carries the controls below. The Flows guide explains what each one does; this is the exact shape.
| Field | Type | Notes |
|---|---|---|
stepId | string | Unique within the Flow. |
name | string | Display name. |
skillSlug | string | The skill this step runs. |
parameters | string map | Values passed to the skill. A value can be a literal or a reference to an earlier step's output. |
checkpoint | object | enabled, plus an optional message and autoApproveInBackground. A checkpoint pauses the run for an approval. |
condition | string | An expression that must be true for the step to run. |
skipCondition | string | An expression that, when true, skips the step. |
onFailure | abort / skip / fallback | What to do if the step fails. |
fallbackStepId | string | The step to run when onFailure is fallback. |
maxTurns | number | A cap on agent turns in this step. |
contextMode | full / parameters-only | How much prior context the step receives. Default full. |
executionMode | sidecar / headless | Where the step runs. Default sidecar. |
sideEffects | external | Marks a non-idempotent step so it is never auto-retried after a stall. |
order | number | The step's position. Array order is the runtime order. |
Parameter fields
| Field | Type | Notes |
|---|---|---|
name | string | The parameter's identifier. |
description | string | The user-facing prompt in the run dialog. |
type | string / number / boolean | The value type. |
required | boolean | Whether a value must be supplied. |
defaultValue | string | Used when none is supplied. Optional. |
hidden | boolean | Hides the parameter from the run dialog, for internal values. Optional. |
Defaults fields
| Field | Type | Notes |
|---|---|---|
checkpointMode | template / all / none | Which steps pause for approval. template pauses only at marked steps. |
mode | interactive / background | Whether the run is watched or proceeds on its own. |
maxTotalTurns | number | A cap on agent turns across all steps. Optional. |
timeoutMs | number | A wall-clock ceiling for the run. Optional. |
agentRuntime | object | Pins the run to a provider and model when no profile sets one. Optional. |
autoDispatchOnReview | boolean | When true, the Flow dispatches itself for each blocking review finding. Default false. |
maxIterations | number | The recheck loop's maximum rounds before unresolved findings go back to a person. Default 3. |
Triggers
A Flow runs on demand, and a trigger can fire it on its own. There are three shapes.
| Trigger | Fires when | Filters |
|---|---|---|
scheduled | A cron expression matches, in an optional time zone. The schedule can be paused and resumed. | None. |
pr-comment | A comment arrives on a pull request. | By finding severity (blocking, suggestion, nit, question) and source (ai, github-comment, in-app). Each filter is optional; with none set, the source defaults to AI findings and human GitHub comments, and all severities are included. |
pr-review | A pull-request review is submitted. | By review state (approve, request-changes, comment). Optional; defaults to changes-requested. |
How a run starts
A run begins one of four ways. The first is a person; the other three are a trigger firing on its own. All four count the same against the daily-runs limit.
| Start | What begins the run |
|---|---|
| Manual | A person launches the Flow from a record or the Flows list and fills in its parameters. |
| Scheduled | A scheduled trigger's cron expression matches. |
| Pull-request comment | A pr-comment trigger matches an arriving comment by severity and source. |
| Pull-request review | A pr-review trigger matches a submitted review by its state. |
A triggered run has no person to fill the run dialog, so it uses the Flow's defaults and each parameter's default value. A parameter a trigger relies on therefore needs a defaultValue, or a hidden value set on it, or the run starts without it.
Where a template resolves from
The same flowId can exist at three layers, and the most specific one wins. This is how a built-in becomes editable without losing the original.
- A filesystem default that ships with the platform.
- A workspace copy your team has saved.
- A repository copy scoped to a single repo.
A built-in is read-only until you Customize it, which forks it into a workspace copy. Reset to Default removes the copy and restores the built-in, keeping any schedule attached. The full lifecycle is on Flows.
Expression grammar
Conditions and parameter references share one small expression language. It compares and combines values; it does not calculate them. That keeps a Flow easy to read and its behavior easy to predict.
expression = or_expr
or_expr = and_expr ( "||" and_expr )*
and_expr = comparison ( "&&" comparison )*
comparison = unary ( ("==" | "!=") unary )?
unary = "(" expression ")" | value
value = ref | string | number | "null" | "true" | "false"
ref = "$" segment ("." segment)*
segment = identifier ( "[" number "]" )?| Form | Reads | Example |
|---|---|---|
$input.name | A value the run was started with. | $input.initiativeName |
$steps.id.output.field | A field from an earlier step's result. | $steps.verify.output.readyForPr |
field[n] | An element of an array field. | $steps.research.output.files[0] |
A resolved reference is turned into text before it reaches the skill, so a comparison against one quotes the value: $steps.verify.output.readyForPr == "true", not a bare boolean. A reference to a field an earlier step did not produce resolves to the string "undefined", so it pays to bind against fields the upstream skill actually emits. The operators are equality (==, !=) and the logical && and ||, with parentheses for grouping. An expression is capped at 4096 characters; a longer one is rejected. When a decision needs more than a match, have a step report a plain result in its output and branch on that.
Step output contracts
Every step returns a structured result validated against a fixed shape for its skill, with a couple of automatic retries if the first result does not fit. Each result carries the base contract below, and named skills extend it with their own fields, which the next step can read.
| Base field | Type | What it holds |
|---|---|---|
summary | string | A one to three sentence summary of what the step did. |
status | success / partial / blocked / error | The step's outcome. A step that reports blocked pauses the run for attention. |
artifacts | string map | A map of artifact name to its file path in the sandbox. |
The built-in skills the SDLC and fix Flows compose extend that base with these fields.
| Skill | Extended output fields |
|---|---|
ax-research | entryPointName, entryPointType, discoveryDocPath, dependencyCount |
initiative | initiativeId, initiativeFile, featureCount, phases |
plan | planId, initiativeId, planFile, stepCount |
implement | planFile, commitHashes, stepsCompleted, buildStatus (pass / fail / skipped) |
verify | planFile, buildPass, integrityPass, readyForPr, issues |
create-pr | prUrl, prNumber, branch |
generate-test-cases | testCaseIds, planId, count |
review | prNumber, overallVerdict (approve / request-changes / comment), findings, filesTouched, reviewerIteration |
scoped-implement | prNumber, addressedFindingIds, skippedFindingIds, commitSha, filesTouched, rationale |
recheck | prNumber, iteration, findingResults, regressionsDetected, allResolved, shouldContinue |
A skill your team authors produces the base contract, so a custom step still reports a summary, a status, and its artifacts, and a later step can read those. The verify, review, and recheck skills declare that they require an applied environment, so the Flow gates them on open environment-health blockers before and after they run, parking the run for attention rather than pressing on with a broken environment. A create-github-pr skill returns the same fields as create-pr for teams that name it explicitly.
Reading one contract end to end
Here is a single output field crossing from one step into the next step's condition. The review step runs and reports its result:
{
"summary": "Reviewed PR 482. One blocking finding on input validation.",
"status": "success",
"overallVerdict": "request-changes",
"findings": [ { "findingId": "finding-1a2b", "severity": "blocking" } ]
}A later scoped-implement step reads that verdict by name in its condition, so it runs only when the review asked for changes:
$steps.review.output.overallVerdict == "request-changes"The verdict was a literal value in one step's result; one step on, it is the gate that decides whether the next step runs at all. Nothing was passed in a prompt and nothing was inferred. The field is a named part of the review contract, the reference reads it by that name, and the comparison quotes it because a resolved reference reaches the expression as text. That is the shape of a Flow: a step states a fact, and a later step acts on it.
Skill reference
A skill is the unit a step runs. A Flow composes skills; a skill is what does the work inside one step. These are the parts that matter when you bind one to a step.
| Field | What it holds |
|---|---|
slug | The skill's stable identifier, the value a step's skillSlug names. |
title | The display name in the skill picker. |
description | What the skill does, shown when you choose it for a step. |
promptTemplate | The instructions the skill runs. A step's parameter values fill it in. |
scope | Where the skill comes from: a built-in that ships with the platform, or one saved in your workspace. |
visibility | Whether a workspace skill is private to its author or shared with the tenant. |
modelOverride | An optional model the skill always runs on, so a step can pin its own model. |
A skill takes its inputs through the step that runs it: the step's parameters are interpolated into the promptTemplate, as literals or as references to earlier output. Authoring a skill is on the Skills guide.
Run states
A run and its steps move through fixed sets of states. The full tables, including what each state means, are in the statuses reference; the values are listed here for quick lookup.
- A flow run is
pending,running,paused,completed,failed,rejected,cancelled,blocked, orinterrupted_by_deploy. - A step is
pending,running,completed,failed,blocked,skipped, orcancelled.
Who may read, run, edit, or cancel a Flow is set by the flows.read, flows.run, flows.manage, and flows.cancel.any scopes in the permission scope catalog.
Real-time events
The platform keeps every open tab current over a single server-sent events stream at /__/events. The events on it are lightweight signals: each one names what changed so the page can refetch the authoritative record. The store is the source of truth, not the event payload, so a missed signal is corrected on the next read rather than lost.
Record lifecycle signals
These fire as records are created, changed, or removed. They are grouped by the kind of record.
| Group | Event names |
|---|---|
| Initiatives | initiative-created, initiative-updated, initiative-deleted, initiative-restored |
| Plans | plan-created, plan-updated, plan-deleted, plan-restored |
| Bugs | bug-created, bug-updated, bug-deleted, bug-restored |
| Test cases | test-case-created, test-case-updated, test-case-deleted, test-case-restored |
| Sprints | sprint-created, sprint-updated, sprint-deleted, sprint-restored |
| Sprint membership | sprint-items-added, sprint-items-removed, sprint-items-reordered |
| Projects | project-created, project-updated, project-deleted, project-restored, project-team-linked, project-team-unlinked |
| Portfolios | portfolio-created, portfolio-updated, portfolio-deleted, portfolio-restored, portfolio-project-added, portfolio-project-removed, portfolio-team-linked, portfolio-team-unlinked |
| Goals | goal-created, goal-updated, goal-deleted, keyresult-updated |
| Teams | team-created, team-updated, team-deleted, team-member-added, team-member-updated, team-member-removed, team-owner-transferred |
| Skills | skill-created, skill-updated, skill-deleted |
| Agent instructions | agent-instructions-updated |
| MCP configs | mcp-server-config-created, mcp-server-config-updated, mcp-server-config-deleted |
| Sandbox profiles | sandbox-profile-created, sandbox-profile-updated, sandbox-profile-deleted, sandbox-profile-test-run-completed |
| Workflows | workflow-updated |
Portfolio and project events are gated by membership, so a person receives one only for a record they can see. The rest fan out across the workspace.
Run and activity signals
Flow runs, background tasks, and fan-out work emit their own progress signals on the same stream. Like the lifecycle signals above, each one names what advanced so the page can refetch the run's authoritative record.
| Source | Reports when |
|---|---|
| Flow run | The run starts, advances a step, reaches a checkpoint, and finishes. |
| Background task | The task changes state as it provisions, runs, and settles for review. |
| Fan-out batch | Each subtask starts, completes, or fails. |
| Chat turn | A turn starts and completes. |
A fan-out subtask inherits the parent's context, its inputs and the prior results, so each one starts oriented without being told everything again. The fine-grained content of a turn travels on its own stream, covered next; these are the coarse signals that tell a surface a run moved.
The chat-turn stream
A single agent turn streams its own output on a separate, cursor-resumable response so a dropped connection can reconnect and replay from where it left off. The chunks on it are typed.
| Chunk | What it carries |
|---|---|
delta | A piece of the agent's reply as it is written. |
thinking_delta | A piece of the agent's reasoning, when the model exposes it. |
tool_start | A tool call beginning, with its inputs. |
tool_end | A tool call finishing, with its result. |
agent_result | The turn's terminal outcome. |
error | A runtime error during the turn. |
heartbeat | A keepalive, about every 15 seconds, that holds the connection open. |
The turn ends on a [DONE] marker rather than a closed connection, so the client can tell a finished turn from a dropped one and resume accordingly.
The operator that drives a self-hosted sandbox talks over a separate command-and-response channel, not this event stream. It carries provisioning instructions to your cluster and their results, never the workspace events above.
Limits and ceilings
These are the numbers the platform enforces. They come in three kinds, and the value column says which: a fixed cap is the same on every plan and keeps one run from affecting another; a plan allowance rises with your plan and is marked "By plan"; and a per-run default is a starting value you can change on a single run, marked "default". Most are sized so they never come up in normal use.
| Limit | Value | What it bounds |
|---|---|---|
| Expression length | 4096 characters | A single Flow condition or parameter reference. |
| Daily flow runs | By plan (Free 5, Team 20, Business and up uncapped) | Flow starts per workspace per UTC day, across manual, scheduled, and triggered starts. |
| Workspace Flow templates | By plan (Free 1, Team 3, Business 10, Enterprise uncapped) | Flows your team saves or customizes. Built-in defaults do not count. |
| Recheck rounds | 3 (default, configurable per run) | How many times a fix Flow rechecks before handing unresolved findings to a person. |
| Fan-out tasks | 20 | Subtasks one fan-out batch can spawn. |
| Fan-out wait | 120 s default, 300 s maximum | How long a step waits for its spawned subtasks. |
| Planning fetches per turn | 6 | Times an agent can pull related planning records in one turn. |
| List page size | 50 default, 200 maximum | Records returned by one list query. |
| Typeahead results | 100 per group | Matches returned per group in a search. |
| Bulk sprint update | 100 items | Items changed in one batch sprint operation. |
| Credential leases | 64 per origin, 16 per minute | Short-lived credential grants a run can hold and request. |
| Saved dashboards | 20 per person | Dashboards one person can keep. |
| Estimates | 1000 | The ceiling on a single hours, points, or actual-hours value. |
| Upload size | 50 MB | A single file or request body. |
| Large-value storage | About 58 KB | The point at which a long text field moves to blob storage automatically. |
A run's AI authoring is also bounded by per-turn and per-day budgets and is rate-limited and audited as it writes; those are covered on the agent runtime and counted against your quotas.
Programmatic access
Automation on this platform is built where the work lives, as Flows and skills you compose, schedule, and trigger, rather than as scripts that drive the work model from outside. A scheduled or pull-request trigger starts a run with no person and no external caller, and a Flow's steps read each other's results through the contracts on this page, so a multi-step pipeline runs inside the product rather than from a job server you keep alive. The HTTP endpoints behind the web and operator surfaces are internal to them and are not a published API today. If your team wants one, raise it with your account contact so it can be weighed against what Flows and triggers already reach.
Keeping this reference current
These values are read from the platform's own definitions, so they move with the product. The live surfaces own them: a Flow's editor shows its steps and defaults, a run's detail page shows the result fields a step produced, and the Workflows and quota pages show the values in force for your workspace. When a number here drives a decision, confirm it against the surface that owns it.
Why automation is shaped this way
Every value on this page is a contract that holds while a run is in flight. A step's output fields are a promise about what the next step can read, which is what lets a Flow be assembled from parts instead of written as one long prompt. The expression language stays small so a condition reads at a glance. The events are signals rather than payloads because the record is the source of truth, so a Flow that ran while you were away leaves its result in your work model, not in a message you can miss. The limits are stated in full for the same reason: when you build on a platform, the numbers it holds you to should be ones you can read before you reach them, not after.
For a power user, this is the page behind a Flow you are assembling: the step fields when you wire one up, the output contracts when you pass a result forward, and the operators when you write a condition.
For a developer, the event names and the limits are the reference to keep. The lifecycle signals are how a surface stays live, the chat-turn stream is how a turn is followed, and the ceilings are the numbers to design within.
For an administrator, the triggers and the recheck default are the ones to know. A scheduled or pull-request trigger is how work starts without a person, and the recheck ceiling is how a fix loop knows when to hand back to a human.
For a prospect, the takeaway is that the automation is composable and bounded: a small grammar, clear contracts between steps, live signals you do not have to poll for, and limits stated in the open.