Skip to content

Flow specification#

A flow file is the Flow resource in YAML (or JSON). astra anemoi flows apply -f and the console's YAML tab read it; the API takes {metadata, spec}. Every version is immutable once written.

pr-triage.yaml
apiVersion: anemoi.astralyx/v1
kind: Flow
metadata:
  name: pr-triage
spec:
  description: Review a pull request twice, ask, then merge or comment.
  drive: flow-files
  inputs:
    - {name: pr, description: The pull request's URL, required: true}
  steps:
    - id: review
      kind: agent
      agent: pr-reviewer
      input: "Review ${{ inputs.pr }}. Write verdict=approve or verdict=changes to $ASTRAEUS_OUTPUTS."
    - id: security
      kind: agent
      agent: security-reviewer
      input: "Look for security problems in ${{ inputs.pr }}"
    - id: ok
      kind: approval
      needs: [review, security]
      target: "Merge ${{ inputs.pr }}? The review says ${{ steps.review.outputs.verdict }}."
      approvers: ["role:editor"]
      wait_seconds: 86400
    - id: merge
      kind: run
      needs: [ok]
      when: steps.review.outputs.verdict == 'approve'
      retry: {max: 3, backoff_seconds: 30}
      template:
        image: ghcr.io/acme/merge-bot:1.4
        command: merge
        args: ["${{ inputs.pr }}"]
        requested_resources: {cpu_cores: 1, memory_bytes: 536870912}
    - id: comment
      kind: agent
      needs: [ok]
      when: steps.review.outputs.verdict != 'approve'
      agent: pr-commenter
      input: "Summarise /flow/review/answer.md as a comment on ${{ inputs.pr }}"
  outputs:
    verdict: "${{ steps.review.outputs.verdict }}"
    merged: "${{ steps.merge.state }}"

The document#

Field Description
apiVersion anemoi.astralyx/v1 (may be left out).
kind Flow (may be left out).
metadata.name Required: the flow's name in the workspace.
metadata.labels Optional labels.
spec Below.

spec#

Field Type Default Description
description string — For people; at most 4 096 bytes.
inputs list — [{name, description, required, default}]. name: [a-z0-9_], at most 64; default at most 64 KiB. Inputs are text: ${{ inputs.<name> }}.
steps list required 1 to 64 steps; their needs make a graph without cycles.
outputs map — name → template, computed when the execution ends. Names [a-z0-9_], at most 64.
timeout_seconds integer — The whole execution's limit: 60 to 2 592 000 (30 days).
on_failure string stop stop: a step failing for good fails the execution and cancels steps under way. continue: steps that do not depend on it go on; the execution fails at the end.
drive string — A drive of the workspace (a shared one, for steps on several machines): each execution mounts its own folder of it at /flow. Without one, each execution gets a drive of its own, a copy per machine, deleted with it.

Every step#

Field Type Default Description
id string required [a-z][a-z0-9_-]*, at most 40, unique.
kind string required agent, run, approval, wait_event, sleep, flow.
description string — For people; at most 4 096 bytes.
needs ids — Steps that must be done first. Without it, the step starts at once.
when expression — Run only when it holds; otherwise the step is Skipped.
retry object {max: 2} max: attempts after the first, at most 10; backoff_seconds: wait before the next, at most 86 400. Agents, runs and child flows are retried; an approval or an event is asked again only when a person retries the step.
repeat object — until (an expression, which may read the step itself) and max (1 to 20): run the step again, as new attempts, until it holds.
timeout_seconds integer — One attempt's limit: 1 to 2 592 000. For wait_event, the wait's.

Each kind#

Kind Fields Done when
agent agent (required), version (from 1; the current one when absent), input (template, required) The agent's run ends. Budgets, guardrails, approvals of its tool calls and receipts apply. Its answer is written to /flow/<step>/answer.md; the agent may read and write /flow.
run template: one worker (image, command, args, env, requested_resources, datavolume_refs…, as in the run specification); command, args and env values are templates The run ends. Its restart policy is Never: retry retries. It may not mount anything at /flow.
approval target (template: what approvers read), approvers (role:admin, role:editor, role:viewer, user:<id>; editors when empty), wait_seconds (60 to 604 800; 86 400 by default) Someone approves. Denied or not decided in time, it fails.
wait_event name ([a-z0-9_-], at most 63) The event arrives (POST …/flow-executions/{e}/events/{name}); one sent before the step waits counts. Its data are the step's outputs.
sleep seconds (1 to 604 800) The time has passed.
flow flow (required, not itself), version, inputs (name → template) The child execution ends; its outputs are the step's. At most three flows deep.

Outputs of a step#

A step's run writes its outputs to the file named by $ASTRAEUS_OUTPUTS, one key=value per line:

echo "verdict=approve" >> "$ASTRAEUS_OUTPUTS"
echo "score=0.93" >> "$ASTRAEUS_OUTPUTS"

Keys are lowercase letters, digits and _; all of a step's outputs together at most 4 KiB. They are reported when the run ends. A wait_event step's outputs are the event's data; a flow step's, the child's outputs.

Expressions and templates#

A template is text with ${{ expression }} in it, each replaced by the expression's value as text. when and repeat.until are expressions, written bare or inside ${{ }}. At most 16 KiB each.

Element Forms
Names inputs.<name>, steps.<id>.outputs.<key>, steps.<id>.state (Succeeded, Failed, Skipped, …), execution.name
Literals 'text' or "text", numbers, true, false, null
Operators ==, !=, <, <=, >, >=, &&, \|\|, !, parentheses
Functions contains(a, b): whether text a contains b
  • A comparison is numeric when both sides read as numbers, textual otherwise.
  • false, null, "", "false", 0 and "0" are false.
  • An output a step did not write is null.
  • A step may name only steps it depends on (through needs, directly or not); repeat.until may also name the step itself; the flow's outputs may name any step. Names that cannot exist are refused when the flow is written.

Nothing is evaluated as code.

The execution#

GET $WS/flow-executions/{name}:

Field Description
metadata.name <flow>-<6 hex>.
spec flow, version, inputs (defaults filled in), started_by, flow_spec (the version as it was), drive, drive_path, parent (a child's), depth.
status state: Pending, Running, Waiting (only on people or events), Succeeded, Failed, Cancelled; reason; times.
steps <id>: {state, reason, attempts: [{n, name, state, reason, node, started_at, finished_at, outputs}], outputs}. A step is Pending, Running, Waiting, Succeeded, Failed, Skipped or Cancelled. An attempt's name is the run, approval, child execution or event it made.
outputs The execution's outputs, once it succeeded.
events [{name, data, sent_by, at}].
receipts [{step, attempt, agent, run}]: its agent runs' receipts.

Listings (GET $WS/flow-executions?flow=&state=) give {metadata, flow, version, started_by, status, step_counts}.