Workflows — from a Draft to a result

Create, validate, publish, and run a Workflow; read typed results, answer decisions, and recover failed Steps.

Use a Workflow when the same sequence of agent work, human decisions, and typed handoffs will run more than once. Dependencies determine when Steps become ready. For a one-off request, start a normal Session. To start a published Workflow at a future time or on a document condition, use a Trigger.

Before you begin

Choose an active Project, a collaborator or admin who can change it, and active collaborator/admin agents for the Session Steps. The execution owner's machine needs an available aachat runtime and the selected coding-agent Runtime configured. A valid definition alone does not make an offline runtime available. See Setup and Environment.

The chat commands below are for an agent inside a running aachat Session with access to the Project. Ask that agent to author the Workflow if you are using WebUI. They are not commands for an unauthenticated terminal. Replace <team>/<project>, agent names, and returned IDs with your actual values. A Project viewer can read content but cannot author or start work; mutations also recheck current Project and execution authority.

What is saved

TermMeaning
DraftEditable files in aachat/projects/<team>/<project>/workflows/<slug>/, synchronized as Project state.
RevisionAn immutable snapshot of the definition and supporting files.
PublishedThe pointer to the Revision used for new published Runs. Publication is separate from a Draft Run.
RunOne execution with fixed Revision and input. Later Draft edits and publication do not change it.
AttemptOne execution attempt of a Step. Retrying creates another Attempt in the same Run.

An Attempt has the exact read-only Revision Bundle at $AA_WORKFLOW_DIR. Read it when doing the assigned Step; never edit it or copy it over the Draft. There is no _published directory. Discover published definitions through list and show.

Create a small, complete Workflow

This example takes a reader name and returns a greeting. First inspect the available agents and published names, then create the Draft identity:

bash
chat project members <team>/<project> --runtime-profiles
chat workflow list --project <team>/<project>
chat workflow init greeting --project <team>/<project>

Use a new slug if greeting is already in use. In the generated Draft, replace workflow.yaml with the following and replace writer.yourname with the exact member name. Choose a Runtime supported by that agent. session.runtime and its kind are required; the example explicitly uses an empty configuration.

yaml
schema_version: 1
name: greeting
description: Write a greeting for one named reader.
inputs:
  type: object
  additionalProperties: false
  properties:
    reader:
      type: string
      minLength: 1
  required: [reader]
outputs:
  greeting: "{{ steps.write.outputs.greeting }}"
steps:
  write:
    needs: []
    session:
      agent: writer.yourname
      runtime:
        kind: codex-acp
        config: {}
      prompt:
        file: prompts/write.md
    outputs:
      type: object
      additionalProperties: false
      properties:
        greeting:
          type: string
          minLength: 1
      required: [greeting]

Create prompts/write.md within the same Draft:

text
Write one welcoming sentence for {{ inputs.reader }}.
Return the sentence in the required greeting output.

{{ aachat.step_completion }}

The final placeholder inserts the completion instructions for this Attempt. It must appear exactly once at the end of a Session prompt. Remove unused starter files if they are no longer needed. The schema is a closed object: reader is required, and undeclared input keys are rejected. The Step must return greeting, and the top-level mapping makes that value available as the Run result.

Validate, try, and publish

From the workspace root, validate in the Draft's Project directory, then optionally run the Draft:

bash
(cd aachat/projects/<team>/<project> && chat workflow validate workflows/greeting)
chat workflow run --draft aachat/projects/<team>/<project>/workflows/greeting --stdin <<'JSON'
{"reader":"Alex"}
JSON

Validation contacts the server to check Project agents and any published child Revision pins; it is not an offline YAML check. A validation error identifies the field or file to correct. A Draft Run starts real agent work, so use suitable input and inspect its returned Run ID with status before moving on. A successful Draft Run is useful evidence, but is not required for publication.

Publish the Draft and inspect its input/output contract before starting the published version:

bash
chat workflow publish aachat/projects/<team>/<project>/workflows/greeting
chat workflow show greeting --project <team>/<project>

Alongside the published Revision's inputs and outputs, inspect each entry in steps: key, kind, and needs. Check agent_name and runtime_kind for Session Steps and workflow_slug for child Workflows. The list follows dependency order; it does not guarantee serial execution of independent Steps. Show does not start a Run or expose prompt bodies, secrets, or every internal Step of a child Workflow. Start the published version after this check.

bash
chat workflow run greeting --project <team>/<project> --stdin --wait <<'JSON'
{"reader":"Alex"}
JSON

Publication snapshots the files and changes the Published pointer; it does not modify the Draft files or draft_version. run --wait starts the Run and registers a durable notification for the source Session. The command returns immediately. After acceptance, the source agent ends its turn and reads the result on continuation instead of polling.

bash
chat workflow status <run-id> --project <team>/<project>
chat workflow runs greeting --project <team>/<project>

A succeeded example Run returns outputs such as {"greeting":"Welcome, Alex!"}. The wording is generated, not guaranteed to be that exact sentence. Before success, outputs is absent. Without top-level output declarations, a succeeded Run returns {}. Check both the Run state and the actual result or linked artifact.

Complete a Session Step

The agent executing the Step follows the generated completion block. In the example Attempt, after producing the actual greeting, it submits:

bash
chat workflow complete --stdin <<'JSON'
{"outcome":"succeeded","outputs":{"greeting":"Welcome, Alex!"}}
JSON

If it cannot finish, it submits the cause and next action:

bash
chat workflow complete --stdin <<'JSON'
{"outcome":"failed","error":"Required source is unavailable; restore access before retrying."}
JSON

Only a JSON response containing "accepted": true confirms acceptance of the completion intent. A timeout, terminal echo, or final chat response does not. After a transport error, retry the exact same JSON payload using the same non-interactive form. Once accepted, start no further work and finish the current response normally. Acceptance is not yet proof that the whole Run succeeded. Do not use chat session finish as a substitute.

If a Session Step needs an unplanned human decision, create a Project Ask and register chat wait --all --ask <ask-id> --project <team>/<project>, then end the turn without completing the Step. On continuation, read chat ask show <team>/<project> <ask-id>, resolve the answer or cancellation, and finish the Step. A Workflow Attempt can wait on same-Project Asks, not on Session or Run targets.

Human decisions and reusable children

A planned Decision Step creates a Project Ask for the human who started the Run, or the human owner of the agent that started it. There is no assignee field in the Decision definition. Answer it in the Project's Ask interface. The Run uses a pinned answer revision as {"answer": "..."}; a later edit to the Ask does not rewrite that output. waiting_for_decision is an intermediate state, not a failure. This is a business decision, distinct from a coding Runtime asking permission to use a tool. An answer supplies data to downstream Steps. Branching requires explicit when conditions as below; an answer does not grant deployment authority.

A Workflow Step can call a published Workflow in the same Project. Its child Revision is pinned, and only one level of composition is supported. See the complete definition reference for Decision and child examples, typed bindings, and limits.

Choose a branch and collect its result

Use this example only after confirming the compatible API/server, WebUI, and CLI described in the version prerequisite and definition rules. Availability in your environment is not established by this guide or by a successful syntax check. If validation rejects when/join, or the Run view lacks condition/skip details, stop and check the deployed version with your administrator.

This Workflow asks which note to prepare, runs one branch, and exports the join's summary. It does not publish or deploy anything. As with greeting, inspect Project members and Runtime profiles, then run chat workflow init choose-note --project <team>/<project> (choose another slug if occupied). Replace the Draft's workflow.yaml with the following. Replace all three writer.yourname entries and Runtime settings with the actual supported member/profile.

yaml
schema_version: 1
name: choose-note
description: Choose a note, then summarize the branch result.
inputs:
  type: object
  additionalProperties: false
  properties: {}
outputs:
  summary: "{{ steps.summary.outputs.text }}"
steps:
  choose:
    needs: []
    decision:
      question: Which note should be prepared?
      body: { file: prompts/choose.md }
      options: [Draft, Hold]
  draft:
    needs: [choose]
    when:
      value: "{{ steps.choose.outputs.answer }}"
      equals: Draft
    session:
      agent: writer.yourname
      runtime: { kind: codex-acp, config: {} }
      prompt: { file: prompts/draft.md }
    outputs:
      type: object
      additionalProperties: false
      properties:
        text: { type: string, minLength: 1 }
      required: [text]
  interpret:
    needs: [choose]
    when:
      value: "{{ steps.choose.outputs.answer }}"
      otherwise: true
    session:
      agent: writer.yourname
      runtime: { kind: codex-acp, config: {} }
      prompt: { file: prompts/interpret.md }
    outputs:
      type: object
      additionalProperties: false
      properties:
        text: { type: string, minLength: 1 }
      required: [text]
  summary:
    needs: [draft, interpret]
    join: true
    session:
      agent: writer.yourname
      runtime: { kind: codex-acp, config: {} }
      prompt: { file: prompts/summary.md }
    outputs:
      type: object
      additionalProperties: false
      properties:
        text: { type: string, minLength: 1 }
      required: [text]

Create prompts/choose.md in the same Draft:

text
Choose Draft for a short planning note, or Hold to record that work is on hold.
You may also describe your conditions in your own words.

Create prompts/draft.md in the same Draft:

text
Return a short planning note in text. Do not publish or deploy anything.

{{ aachat.step_completion }}

Create prompts/interpret.md in the same Draft:

text
The human answered: {{ steps.choose.outputs.answer }}
Return a note in text preserving the answer and any conditions. Do not infer
approval or carry out the requested work. If another decision is necessary,
use a Project Ask and wait before completing this Step.

{{ aachat.step_completion }}

Create prompts/summary.md in the same Draft:

text
Read the attached Workflow dependency results. Return a concise summary in
text using the succeeded outputs and explaining which branch was skipped.
Preserve any human conditions; do not treat a skipped branch as completed work.
If all dependencies were skipped, report that no branch work was performed.

{{ aachat.step_completion }}

From the Draft's Project directory, validate, then optionally try the Draft with the empty input object:

bash
chat workflow validate workflows/choose-note
chat workflow run --draft workflows/choose-note --stdin <<'JSON'
{}
JSON

Open the returned Run in the Project's Workflows and answer its Ask. Selecting exactly Draft runs draft and skips interpret; selecting Hold or supplying free text runs interpret and skips draft. Draft, after review is free text, not approval for the Draft branch. A later Ask edit does not change the accepted answer for this Run. If interpret needs another decision, follow the Ask/wait procedure above before completing it.

After the selected branch succeeds, summary reads its accepted output and the other branch's skip reason. Each running Session submits its own schema-valid completion using the generated instructions. The summary Attempt may, for example, submit {"outcome":"succeeded","outputs":{"text":"Work is on hold; the draft branch was skipped."}} only if that describes the actual result. accepted: true acknowledges that Step's completion, not the whole Run's success.

Use chat workflow status <run-id> --project <team>/<project> to verify the Run is succeeded and outputs.summary exists and contains the expected result. Missing outputs are not an empty successful deliverable. Inspect the active Step, completion acceptance, or output_error before passing anything onward. When a child is involved, inspect the parent too: child success alone does not prove the parent accepted its output. After the trial, publish and run the published version using the earlier procedure with choose-note and {}.

This Decision example always selects one of the two branches after an answer. With boolean/enum conditions, an uncovered value can skip every branch: a join still runs and must report that no branch work occurred. An ordinary downstream Step would skip instead. Do not count skipped work as performed or retry it to force a branch; correct the Draft or input and use a new Run if the intended choice was different.

Read the Run and recover

In WebUI, open the Project's Workflows, select the Workflow, and open a Run. The dependency graph and Step details let you inspect inputs, outputs, Attempts, source Session, linked Ask, and child Run. Open the relevant Attempt or child before deciding how to recover. CLI status includes available_actions; these reflect current state and authority, and are rechecked when you act.

Observed state or problemNext action
Work is running or waiting for a decisionInspect the active Step or answer the Ask; do not launch a duplicate to obtain a result.
skipped with condition_not_matchedCompare the recorded reference and actual value with the condition. No Attempt, Session, Ask, signal, or child Run was created for this Step; it has no retry action.
skipped with dependency_skippedInspect the named upstream Step's skip reason. Ordinary downstream work also skips; use an explicit join when it must collect the remaining results.
A join has not started or has failedCheck every dependency. Failed, cancelled, blocked, or unresolved work is not a successful skip. Repair the cause and retry only when offered; a failed join can be retried with skipped dependencies when listed in available_actions.retry_steps.
attention_requiredInspect the failed Step and cause. It is settled, not succeeded.
Retry is offeredRun chat workflow retry <run-id> --step <step-key> --project <team>/<project> only for a key in available_actions.retry_steps.
A Workflow Step failed in its childOpen the child Run and retry the failed inner Step when offered.
Cancellation is neededUse chat workflow cancel <run-id> --project <team>/<project> only when available_actions.cancel is true. Cancel a child through its parent.
Definition or immutable input is wrongCorrect and validate the Draft, publish if needed, and start a new Run. Retrying does not adopt Draft edits.
Decision Ask was cancelled or its assignee is unavailableRepair the cause and retry when offered; a retry creates a new Ask. An oversized rendered Decision has no retry action.
Runtime cannot startRestore the execution owner's runtime/configuration, then follow the available retry action. Ordinary Session resume is not supported for Workflow Attempts.

For several root Runs whose results must be combined, start them without individual --wait flags and register one explicit wait:

bash
chat wait --all --workflow <first-run-id> --workflow <second-run-id> --project <team>/<project>

Child Runs belong to their parent and cannot be wait targets. When continued, inspect each result using the supplied Read: command. Settled results can include attention or cancellation; waiting is not an assertion of success.

To pass a successful result to another Workflow, inspect both schemas, then select only the keys accepted by the next closed input object. For a next Workflow named save-greeting that declares greeting:

bash
chat workflow status <run-id> --project <team>/<project> | jq '.outputs | {greeting}' | chat workflow run save-greeting --project <team>/<project> --stdin

Run this only after confirming success and the presence of outputs; do not pipe a failed status into a new Run. Store large deliverables in Shared Documents or Media and return a bounded reference. Completion and Run outputs are limited to 128 KiB and JSON depth 32. workflow_completion_limit_exceeded requires smaller outputs and a corrected new Run; a historical succeeded Run can report output_error instead of oversized outputs.

Improve the next Revision

When a prompt, input, output schema, or agent assignment caused a concrete problem, leave Attempt feedback. In the current Attempt use chat workflow feedback --stdin; outside it use the Run ID and Step, with optional --attempt N:

bash
chat workflow feedback <run-id> --step write --project <team>/<project> --stdin <<'TEXT'
The prompt did not specify the reader's language. Add a language input before the next revision.
TEXT

Feedback is plain text, up to 8,192 bytes. Do not invent scores. Read it in Run status or the Run screen and use the improvement action to prepare Draft changes. Feedback alone changes no prompt. Edit the normal Draft, validate it, optionally try it, and publish the next Revision. Keep Run logs in Run history.

In WebUI, choose Ask an agent to improve to prepare and focus a new Session's launch draft. If another draft is already entered, review the replacement confirmation. Check the Project, Workflow slug, and normal Draft path in the prepared prompt, select the Agent and Runtime, then send to start the improvement Session. Preparing the draft is not Session-start acceptance. Open the started Session to follow its edits; an existing Run still uses its pinned Revision.