Skip to content

Boxes#

A workflow is made of boxes. They come in three families, as the editor's palette groups them:

Family Boxes What they are
Light Ask a model, Classify, Function, Notify A call to what is already up — a deployment, an assistant, a function, people's phones. Seconds; no container, no machine to wait for.
Control Condition, Error path, Approval, Wait, Wait for event Ways, waits and people. The workflow waits for them; nothing runs on a machine meanwhile.
Cluster Run, Agent, Sub-workflow Work placed on your machines: containers, GPUs, hours, many files.

Each box's fields, in YAML, are in the Workflow specification. Every box also has needs, when, runs, retry, timeout_seconds and repeat (Workflows). In the editor, a box's Recipe menu fills its fields with a ready answer (Extract fields as JSON, Spending category, If / else…); every field stays yours to change.

Ask a model#

kind: model. A deployment or an assistant of the workspace answers a prompt — the same chat completion the Playground makes, without streaming.

  • Who answers. One of deployment and assistant. A deployment answers as the bare model. An assistant brings its instructions, its tools and the memory of the person the execution runs as; it answers on its own deployment.
  • What it is asked. prompt (required) and system, both templates: ${{ event.text }}, ${{ steps.read.outputs.merchant }}. images: up to 8 templates, each giving a data:image/…;base64, URL (a photo an event carries), for a model that sees images. max_tokens: 1 to 32 768. thinking: let a model that reasons before it answers (Qwen 3, DeepSeek R1) do so — off by default: a box wants the answer in seconds, and a small max_tokens spent thinking leaves none (the attempt then fails, saying so). Classify never thinks.
  • What it answers. format: text (the default): the output text, cut at 16 KiB. format: json: the model is asked for one JSON object (the request's response_format is json_object, and the system message says so); the outputs are json (the object, at most 8 KiB) and each of its top-level fields whose name is [a-z0-9_] — so a prompt asking for amount, merchant, date gives steps.read.outputs.amount. A field's value is its text, or its JSON for a number, a list or an object. An answer that is not a JSON object fails the attempt, and the retry asks again. A model's thinking (<think>…</think>) and a code fence around the JSON are left out.
  • A deployment at zero is woken: the box says Waking deployment and asks again every 5 s, for up to 5 minutes. The default time limit, 360 s, leaves a minute to answer after that.
  • A model that answers an error ends the attempt with the model's own words.

Classify#

kind: classify. A model chooses one of your labels for input, with how sure it is: a branch made by a model, for what a rule cannot say.

  • labels: 2 to 20, each {name, description} — the description tells the model when the label applies. Names are [a-z0-9_-]; uncertain is taken.
  • The model is held to a schema naming exactly your labels (at temperature 0) and answers a label, a confidence (0 to 1) and a reason.
  • Outputs: label, confidence (two decimals), confident (true or false), reason (one sentence, at most 1 KiB). Below min_confidence (0.6 by default), or when the model names a label you did not offer, label is uncertain and guess holds what it said — a way to ask a person.
  • images as for a model; deployment or assistant as for a model; the same 360 s time limit and waking.

After a classify box, a condition's One way per label button writes a case per label, and uncertain as the default way.

Function#

kind: function. Calls a function of the workspace — a published version, at target: an alias, v<n>, or latest (the default). A draft is not called. The call goes to a warm instance, or starts one.

  • input: field → template. A value that reads as JSON (an object, a list, a number, true, false, null) is passed as that; anything else as text (007 stays text).
  • Outputs: result (what it returned, as JSON text, cut at 8 KiB) and, when it returned an object, each of its top-level fields.
  • Time limit: 60 s by default.

Write the code in the box. In the editor, Write the code here (Python or Node) opens an editor with a starter handler: its arguments are the box's input fields, and what it returns are its outputs. Save and publish makes it a function of the workspace named <workflow>-<box>, publishes a version with the alias flow, and points the box at it (target: flow). It is an ordinary function: versioned, listed with the others, with a 30 s limit of its own, 512 MB and one CPU core, kept warm 15 minutes after a call.

Notify#

kind: notify. Tells people something: a title (one line) and a message.

  • to: user:<id> for each person (their Astralyx id: GET $ASTRALYX_API/me answers yours as id). Empty: the person the execution runs as. Only members of the workspace's organisation are told; anyone else is left out.
  • Where it goes: the person's inbox (in the console and the app), always; a push to their phone (app notifications, unless they turned A workflow tells you something off or it is their quiet hours); their Telegram, when they connected it to an assistant (to the chat of this workspace's assistant, else the one they used last; within an hour, once). E-mail only when channels names email, or when the person turned e-mail on for workflow notices.
  • channels: app (the push), telegram, email. Empty: all the person keeps. The inbox always has it.
  • title is cut at 300 characters, message at 2 000. In Telegram the message's Markdown (bold, lists, links) is formatted.
  • It succeeds at once, with outputs sent (true) and to. It is never retried. With nobody to tell (no to, and an execution not run as a person), it fails.

A notice leads to the execution: tapping it opens the execution's page.

Condition#

kind: switch. Chooses one way: the first of its cases whose when holds, else default (else when empty). Its output branch is the way's name; the boxes after it read it in their when. Up to 20 cases; decided at once. See Conditions and ways.

Error path#

A Notify box with runs: failure, put after the box it watches: it runs only when that box fails, and the execution still fails. Any box may be an error path; see Error paths.

Approval#

kind: approval. A person decides before the workflow goes on: an approval of kind flow_step, decided under Anemoi → Approvals like any other.

  • target: what approvers read (a template). approvers: role:admin, role:editor, role:viewer or user:<id>; the workspace's editors when empty.
  • wait_seconds: 60 s to 7 days, a day by default. Denied, or not decided in time, the box fails.
  • Outputs: decision (approved) and decided_by.

Wait and Wait for event#

  • Wait (kind: sleep): seconds, 1 s to 7 days.
  • Wait for event (kind: wait_event): waits for an event named name sent to the execution — from its page (Send event), astra iris workflows events send, or the API — with key=value data, at most 4 KiB, which become the box's outputs. An event sent before the box waits counts. timeout_seconds bounds the wait; without it, it waits as long as the execution may.

Run#

kind: run. Any container on your machines: one worker of a run template (image, command, args, env, requested_resources, drives, configs…), its command, args and env values templates. Without resources it asks for 1 CPU core and 1 GiB. It is never restarted in place: the box's retry retries. It mounts the execution's drive at /flow, and writes its outputs as key=value lines to $ASTRAEUS_OUTPUTS (64 at most, 4 KiB in all).

Agent#

kind: agent. A run of an Anemoi agent (its current version, or version), asked input. Budgets, guardrails, approvals of its tool calls and receipts apply as to any of its runs. Its answer is written to /flow/<box>/answer.md; the execution lists the run's receipt.

Sub-workflow#

kind: flow. Runs another workflow of the workspace as a child execution, with inputs (templates), and waits for it; its outputs are the child's. At most three workflows deep; a workflow cannot run itself.