Pipelines

A pipeline is a set of agent steps you design once and re-run. Each step is one headless agent run; the arrows between them say what waits for what. Where the Foreman decides the plan each time, a pipeline is the plan that already worked — kept, versioned and run again.

The shape of one

A pipeline lives as a YAML file: .aioat/pipelines/<name>.yaml inside the repo it builds, so it is diffed and reviewed like any other artifact. Without a repo it goes to your personal library and runs in a scratch folder instead — no branch, nothing committed.

Orchestrate → Pipelines → + New pipeline writes a small commented example you can run as-is. ⛓ Open on canvas draws it: drag a node to move it, drag the ● handle onto another node to make it depend on this one, click an edge and press Delete to remove it. Every edit is written back into your file — comments, formatting and key order survive.

What a step carries

SettingWhat it does
PromptThe brief. Parameters appear as {placeholders}.
SpecialistA role briefing from your roster — planner, backend, reviewer, tester…
Model & effortPer step. Plan on a strong model, grind on a cheap one.
ToolsWhat this step may reach: all, repo (no MCP servers), no-shell, read-only, or exactly the MCP servers you name. Least privilege per step, and less context wasted on tools it will never call.
Permissionsaccept-edits (edits fine, shell only if listed in Allowed commands), plan (reads and reports, changes nothing), bypass (everything, unasked — flagged before you run).
Loop untilChecks the step's "done" has to survive: tests, build, lint, cmd:<command>, or svc:<container> <command> to run inside one of its services. A red check goes back to the step with the output, up to the attempt cap.
Gateask parks the step for you before anything downstream starts.
ServicesContainers to have running while it works. Below →
Steps run headless and cannot ask for permission — that is why the shell commands a step needs are listed up front in Allowed commands. A step that needs an unlisted command is denied, not paused.

Running one

▶ Run… asks for the parameters and then shows what will happen before anything starts: how many steps, how many times it will stop for you, which run in parallel, any step with bypass permissions, and any containers it will start. Parameters can be plain text, a ticket (a GitHub issue or Jira key, read at launch and offered to prompts as {t_title}, {t_brief}, {t_url}, {t_key}), a pull request, or a branch.

A run works on one branch. Steps go level by level: a level with one step runs in the run's worktree, a level with several gives each its own worktree off the run branch and merges them back before the next level starts. AIOAT commits each step's work itself — agents need no git permission, and every step leaves one commit behind.

Gates — approving what you can see

A gated step parks in Approvals with what it actually said. You can Approve, Request changes… (the step resumes the same conversation with your feedback and doesn't spend a retry), or Reject (the run stops there).

Each step's output is recorded while it runs, so it outlives the session: a step's process ends the moment it finishes, which is exactly when its gate opens. Read it from the gate, from ▤ on the run card, or by double-clicking the node on the canvas. At a gate, Earlier steps shows what led here — an approval is only informed if you can see the work before it.

When a step gets it wrong

A step usually fails because its definition wants changing. Edit it on the canvas, then press ↻ on that step: it runs again with the pipeline as it is saved now — the new prompt, model, checks and tool scope. Everything downstream goes back to pending with it (their work was built on the old result); everything before it keeps its work and its commits, and the run picks up from that step's level. A re-run is a fresh conversation, not a resumed one.

Runs can be removed one at a time, all the finished ones, or all of them — a run still going is stopped first. The record and its step transcripts go; the branch and its commits are git's and stay.

Services — containers a step works against

A checkout is rarely the whole environment. An end-to-end step needs the stack up; a migration step needs the database; a step may need a tool you would rather not install. Declare them once and a step asks for them by name:

services:
  stack:
    compose: docker-compose.e2e.yml   # a file in this repo
  db:
    image: postgres:16                # or just an image, no compose file
    ports: ["5432:5432"]
    scope: node                       # gone again when its step finishes

nodes:
  - id: e2e
    needs: [build]
    uses: [stack]
    loop_until:
      checks: ["svc:api npm run test:e2e"]   # runs inside the container
    prompt: Run the end-to-end suite and fix what it catches.

The 🐳 Services panel on the canvas authors these without touching YAML; each step then ticks the ones it needs in its own inspector. AIOAT brings a stack up before the step starts — waiting for healthchecks unless you turn that off — and takes it down when the step ends (scope: node) or when the run does. A cancelled run, a failed one, a removed one and a crashed app all clean up after themselves, and only containers AIOAT started are ever touched.

When a check goes red, the containers' own logs go into the step's output and back to the agent with the failure — that is usually where the reason actually is.

Needs Docker. A pipeline that declares services refuses to start if Docker isn't installed or its engine isn't running, and says which of the two it is. Settings → Tools installs Docker Desktop.

Pipelines an AI can read and write

⇩ Export hands out your pipelines and what their runs did as one JSON pack: which steps failed their checks and why, how many rounds each took, what a reviewer sent back at a gate. Give that to a model and ask for a better flow; ⇧ Import takes the answer back, validated before anything is written. The Foreman can do the same from inside AIOAT — it reads the pack, drafts a pipeline, and you run it.

Pipeline files are reloaded from disk when the window comes back, so a pipeline an agent just wrote, or one that arrived with a git pull, is simply there.