---
title: "Workflow definition reference"
description: "Bundle paths, Step kinds, typed schemas, prompt references, child Workflows, commands, and execution limits."
---

# Workflow definition reference

Use this reference while editing `workflow.yaml`. The [Workflow guide](/en/docs/workflows) provides a complete Session Step example and the create-to-result procedure. Definitions use YAML with `schema_version: 1`; unsupported fields are rejected. YAML anchors, aliases, merge keys, and tags are not supported. Validate the actual Draft before publishing or running it.

## Definition fields

| Field | Contract |
|---|---|
| `schema_version` | Required integer `1`. |
| `name` | Required non-empty display name; the Draft directory slug identifies the Workflow. |
| `description` | Required description string. |
| `inputs` | Required closed object schema for Run input. Use empty `properties: {}` for no inputs. |
| `steps` | Required map of 1–64 Steps. Keys match `^[a-z][a-z0-9_-]{0,63}$`. |
| `outputs` | Optional map from public output name to one complete Step output reference. This is a binding map, not a JSON Schema. Default: no exported values. |
| `steps.<key>.needs` | Required list of direct dependencies; `[]` for a root. Up to 32 per Step and 256 edges overall. Unknown or repeated dependencies and cycles are rejected. |
| `steps.<key>.when` | Optional condition on a direct dependency output; applies to any Step kind. Use `value` and exactly one of `equals` or `otherwise: true`. |
| `steps.<key>.join` | Optional boolean, default `false`. `true` requires a Session, non-empty `needs`, and no `when`. |
| `steps.<key>.session` | Exactly one Step kind. Requires `agent`, `runtime`, and `prompt.file`. A Session Step also declares an `outputs` schema. |
| `steps.<key>.decision` | Exactly one Step kind. Requires static non-empty `question` and `body.file`; optional `options`. Do not declare Step `outputs`. |
| `steps.<key>.workflow` | Exactly one Step kind. Requires published child `slug`; `inputs` binds child fields. Do not declare Step `outputs`. |

For a Session Step, `runtime.kind` is mandatory. `runtime.config` is a map of option IDs to strings or booleans and may be omitted or set to `{}`. Strings are ACP option value IDs, not arbitrary display labels; numeric values are not accepted. Discover available kinds and options with `chat project members <team>/<project> --runtime-profiles`. Agent membership, owner availability, and Runtime compatibility still matter at execution.

`needs` orders execution; it is not a conditional expression. A Session, Decision, and child Workflow cannot share one Step definition. Files in `scripts/` are supporting assets that an agent may use; their presence does not create a shell Step or run a command automatically.

## Conditions, skipped Steps, and joins

**Version prerequisite:** These fields require a compatible API/server, WebUI, and CLI. Availability in your environment has not been confirmed here. Before using them, confirm the deployed version with your administrator, validate the actual Draft against that server, and check a trial Run's conditions, skip reasons, and outputs. An unknown-field error or missing condition/skip display is a reason to stop and check versions, not to remove the condition and run unconditionally. See the [complete branching example](/en/docs/workflows).

`needs` still declares dependencies; add `when` explicitly to select work by result. `when.value` must be one complete `{{ steps.<direct-need>.outputs.<path> }}` reference to a required boolean or string enum. Decision `answer` is the only free-text string exception. `equals` preserves type and value: boolean `true` differs from string `"true"`; strings are not trimmed or interpreted. For enums, the comparison must be a declared value. Run inputs, optional paths, arbitrary expressions, coercion, loops, and error-recovery branches are not supported.

`otherwise: true` matches only when none of the `equals` comparisons on the **same normalized reference anywhere in the Revision** match. At least one such `equals` is required; at most one `otherwise` is allowed per reference. Multiple Steps with the same matching value all become eligible. A boolean or enum may have uncovered values with no branch work.

For Decision answers, `equals` must match a published option. Branching on an answer requires an `otherwise` **Session**, whose only `needs` entry is that Decision and whose prompt directly references its `answer`. It receives free text and uncovered options. Preserve the human's conditions and authority; ask for a further decision when needed. Matching an answer grants no new authority, and editing the Ask later does not change the pinned answer revision.

A condition mismatch derives `skipped`; an ordinary Step depending on a skipped Step also skips. No Attempt, Session, Ask, signal, or child Run is created for the skipped Step. Failure, cancellation, blocked work, and unresolved dependencies are not successful skips.

A `join: true` Session waits for **every** direct dependency to succeed or skip, and runs even when all of them skip. It does not bypass failure or cancellation. Its prompt must not directly reference `steps.*.outputs.*`. Instead, read the server's `Workflow dependency results` attachment immediately before the completion instructions: a canonical JSON array in Step-key order, with `step`, `state`, and either accepted `outputs` or skip `reason` for each dependency. It counts toward the 100,000-byte prompt limit and is preserved for retry and prompt history.

Top-level `outputs` cannot reference a potentially skipped Step, including ordinary downstream Steps that inherit skip. Export a required join output instead. All Steps being succeeded or skipped can finish a Run successfully, but Run outputs require accepted successful completions from every executed Step. A child Run's success alone does not establish that its parent Step has accepted its outputs. Check the parent Run and actual `outputs` before using the result.

## Bundle files and paths

The editable root is `aachat/projects/<team>/<project>/workflows/<slug>/`. A Bundle contains required `workflow.yaml`, optional root `README.md`, and text files under `prompts/` or `scripts/`. Session `prompt.file` and Decision `body.file` point to a file below `prompts/` that exists in the Bundle.

Use relative, case-sensitive paths and ordinary UTF-8 text. Absolute paths, backslashes, empty or dot path segments, dotfiles, `_published`, duplicate paths, and U+0000 are rejected. The Bundle is not a general repository snapshot; keep unrelated files outside it. The executing Attempt sees only its pinned read-only Bundle at `$AA_WORKFLOW_DIR`.

## Supported input and output schemas

The root of Run `inputs` and Session Step `outputs` must be an object. **Every object, including nested objects, must have `additionalProperties: false`.** Declare fields under `properties` and required fields under `required`. An optional property can be absent; do not use `null` as a substitute for an absent field.

| Supported construct | Values or keywords |
|---|---|
| Types | `object`, `string`, `number`, `integer`, `boolean`, `array` |
| Object | `properties`, `required`, `additionalProperties` |
| Array | `items`, `minItems`, `maxItems` |
| String | `minLength`, `maxLength`, `pattern`, `format` |
| Number | `minimum`, `maximum` |
| Shared | `type`, `enum`, `description` |

The only supported `format` is `uri`. Arbitrary JSON Schema is not accepted: no `$ref`, `allOf`, `oneOf`, `anyOf`, nullable types, or union type arrays. Use small inline schemas. A document path can be an ordinary string; `format: uri` is for a URI, not a promise that an artifact exists or that its access permissions are suitable.

## Prompt references and exported values

A Session prompt may contain text and `{{ inputs.reader }}` or `{{ steps.write.outputs.greeting }}`. A Step output reference must name a **direct** dependency declared in `needs`; depending on an intermediate Step does not expose all of its ancestors. Referenced schema paths must exist. The generated completion marker `{{ aachat.step_completion }}` must occur exactly once at the end of every Session prompt, with only whitespace after it.

Decision bodies can use the same input and direct dependency references but must not contain the completion marker. Questions and options are static. The Run creates the Ask and accepts the human answer; no agent submits a Decision completion payload.

Top-level `outputs` names map to Step output paths that are required by the source schema, such as `greeting: "{{ steps.write.outputs.greeting }}"`. A top-level output cannot reference Run input directly. The server derives a closed output schema from the bindings. Successful child output is written once to its parent Step before downstream work starts.

## Complete child and Decision example

First publish `greeting` from the [guide](/en/docs/workflows) in this same Project. Then create the `approve-greeting` Draft with `chat workflow init approve-greeting --project <team>/<project>` and write this `workflow.yaml`:

```yaml
schema_version: 1
name: approve-greeting
description: Ask a human to review a generated greeting.
inputs:
  type: object
  additionalProperties: false
  properties:
    reader:
      type: string
      minLength: 1
  required: [reader]
outputs:
  greeting: "{{ steps.compose.outputs.greeting }}"
  answer: "{{ steps.review.outputs.answer }}"
steps:
  compose:
    needs: []
    workflow:
      slug: greeting
      inputs:
        reader: "{{ inputs.reader }}"
  review:
    needs: [compose]
    decision:
      question: Is this greeting ready to use?
      body:
        file: prompts/review.md
      options: [Use it, Revise it]
```

Create `prompts/review.md`:

```text
Please review this greeting for {{ inputs.reader }}:

{{ steps.compose.outputs.greeting }}

Choose whether it is ready, or explain the revision needed.
```

Validate, optionally run the Draft with `{"reader":"Alex"}`, and publish using the guide's procedure with `approve-greeting` as the slug. The child produces `greeting`, and then the human Run starter (or the starting agent's human owner) receives the Ask. There is no configurable Decision assignee. A successful Run exports both `greeting` and `answer`. Selecting `Revise it` still completes the Decision with that answer; this definition has no subsequent revision Step. Add an explicit downstream Session Step to interpret the answer, or use `when` with the required `otherwise` Session to select branches.

Decision `options` must be omitted/empty for free text, or contain 2–5 distinct values. Do not add `outputs` to the Decision: its derived schema is an object with required string `answer`. The server fixes the accepted answer revision; editing the Ask afterward cannot change this Run.

A child `workflow.inputs` entry is either a literal JSON value or a single complete input/direct-dependency reference. Do not interpolate text around a reference. Bind every required child input, and provide only fields accepted by its schema. Every referenced source path must be required, even for an optional destination input. Its schema must be a subset of the destination contract, including supported constraints; matching only the primitive type is insufficient. For example, `reader: Alex` is a literal alternative to `reader: "{{ inputs.reader }}"`.

The server pins the child's current published Revision during validation for run/publication. The child must be available in the **same Project**, and that pinned child may contain only Session and Decision Steps. Nested child Workflows are rejected. Publishing a newer child later does not change an existing parent Revision or Run. Revalidate and publish the parent Draft to adopt it. Open a failed child Run to repair its inner Step; cancel a child through the parent Run.

## Command reference

These are Session-agent commands. Substitute real identifiers. Most Project commands accept `--project <team>/<project>` or infer the Project from cwd. `validate` requires the Draft's Project cwd and server access. `publish` and `run --draft` derive the Project from the Draft path. `complete` targets the current Attempt and takes no Run ID.

| Operation | Invocation |
|---|---|
| Create Draft | `chat workflow init <slug> --project <team>/<project>` |
| Validate | From the Draft Project: `chat workflow validate workflows/<slug>` |
| Published list | `chat workflow list --project <team>/<project> [--last 50] [--before <cursor>]` |
| Published contract and Step list ([pre-run checks](/en/docs/workflows)) | `chat workflow show <slug> --project <team>/<project>` |
| History | `chat workflow runs [<slug>] --project <team>/<project> [--last 50] [--before <cursor>]` |
| Draft Run | `chat workflow run --draft <draft-path> --stdin` |
| Published Run | `chat workflow run <slug> --project <team>/<project> --stdin [--wait]` |
| Publish | `chat workflow publish <draft-path>` |
| Run detail | `chat workflow status <run-id> --project <team>/<project>` |
| Cancel | `chat workflow cancel <run-id> --project <team>/<project>` |
| Retry | `chat workflow retry <run-id> --step <key> --project <team>/<project>` |
| Complete Attempt | `chat workflow complete --stdin` |
| Attempt feedback | `chat workflow feedback [<run-id> --step <key> --project <team>/<project>] [--attempt N] --stdin` |

Square brackets above mean optional arguments; do not type them. `run` takes exactly one of `--stdin` and `--input-file <path>`. `list` and `runs` page sizes are 1–100, default 50. Project-wide `runs` shows roots; passing a Workflow slug includes its root and child Runs, with parent identity. `init`, `run`, and `retry` accept `--client-nonce <uuid>` for retrying the exact same request; do not reuse a nonce for changed input. Always obey `available_actions` and structured recovery responses. `--wait` registers durable waiting and does not block the CLI.

## Limits and how to recover

| Surface | Limit | If exceeded |
|---|---|---|
| One Bundle file | 256 KiB | Shorten or split supporting text. |
| Whole Bundle | 1 MiB, 128 files | Remove unrelated assets. |
| Relative path | 256 UTF-8 bytes | Shorten paths. |
| Dependency graph | 64 Steps, 32 needs per Step, 256 edges | Reduce the graph within the one-level composition rule. |
| Rendered Session prompt | 100,000 bytes including generated completion instructions | Shorten prompt/input/upstream text. |
| Decision question / each option | Non-empty; 2,000 / 200 bytes | Shorten the static text; keep 2–5 distinct options or use free text. |
| Rendered Decision body | 100,000 bytes | Correct the immutable input or definition in a new Run. |
| Run input | 128 KiB, JSON depth 32 | Store large content in a Project resource and pass a reference; flatten deeply nested input. |
| Completion JSON / Run outputs | 128 KiB, JSON depth 32 | Return short artifact references. |
| Failed completion diagnostic | Non-empty, at most 4 KiB | Keep the cause and next action, shorten the diagnostic, and retry. |
| Attempt feedback | 8,192 bytes | Keep a concrete note about the problem. |

KiB and MiB are binary units; the byte limits are not character counts. These are Workflow limits, separate from Database SQL or Session follow-up scheduling limits. A successful schema check cannot establish that a Runtime can execute or that a generated deliverable is correct. Use the [Run recovery guide](/en/docs/workflows) for state-based retry, cancellation, and completion acceptance, and the [Trigger guide](/en/docs/triggers) for scheduled dispatch failures.
