Reference for Orchestrator Workflows (app id orchestrator). For a
task walkthrough with screenshots, see the
Workflows guide.
A Workflow is stored internally as a loop. The command API, event names,
and storage paths keep that older term for compatibility.
A Workflow stores a goal, a generated step plan, trigger settings, limits, and run history. Steps can run in order or at the same time. A Workflow completes only when a planned step reports completion.
Orchestrator stores this state and manages scheduling, run locks, attempt and token limits, workspace isolation, and restart recovery. The Sero host controls the tools and permissions used by each step.
The orchestrator tool and /orchestrator command route every action through a
single per-workspace coordinator. Only the coordinator starts steps or mutates
workflow runtime state.
Actions: create, list, show, activate, disable, enable, run_next,
run_again, retry, retry_step, revise, choose_recovery,
set_step_model, set_step_tools, set_step_agent, set_loop_context,
set_delivery, set_schedule, reflect, reflect_workspace,
choose_suggestion, answer_input, the library_* and catalog_* actions,
and delete.
/orchestrator commandsLibrary commands:
Catalog commands:
active-session — runs in the foreground session.background-agent — runs as a background subagent; the default for work
steps. Supports per-step model, agent role, and extra tools.human — pauses the workflow for your input.Use the Map / Details control to change the plan view. Map is the default for a draft Workflow. Details is the default for an active Workflow.
| Control | Values | Behaviour |
|---|---|---|
| Direction | Auto, Horizontal, Vertical | Auto draws top-to-bottom when the panel is narrower than 760 px, and left-to-right otherwise. The current direction is named in the map's top-left corner. |
| Zoom out / Zoom in | — | Each press changes the scale by 15 percentage points. The percentage between them is the current scale. |
| Fit map | — | Returns to the fitted scale. Disabled when already fitted. |
The map opens at the scale that fits the whole plan into the panel. That fitted scale is never above 100% and never below 25%. Zooming out stops at 70% of the fitted scale; zooming in stops at 190%.
Select a node to show its execution type, instructions, route condition, and fan-out maximum below the map. Select the node again to close the details.
Each node shows the badges for its routing fields.
| Badge | Field | Meaning |
|---|---|---|
| Branch icon | produces | The step records one or more routing variables. |
| Circle | when | The step runs on one route only. |
| Shield | gate | The step waits for your approval. |
×N | fanOut | One run per item found, N at most. |
↩ (violet) | feedback | The plan can return from here to an earlier step. |
A skipped step has a dimmed node. This includes steps on routes that the run did not use. A feedback route is a violet dashed edge. It becomes brighter after the run uses the route.
| Field | Type | Purpose |
|---|---|---|
produces | string[] | Names the routing variables the step records in its outcome. Advisory: the runtime trusts what the step actually recorded, and uses this to validate guards and mark the branch point. |
when | { var, in?, default? } | The step runs only when var holds one of the in values. A guard marked default is taken when no sibling guard on the same variable matched. A step with no when is on the main line and always runs. |
gate | 'approval' | The step presents the exact content to be delivered as an approval question and parks the workflow for your decision. Required on a pre-final step for an external destination. |
feedback | { id, toStepId, when, maxTraversalsPerRun } | A bounded return to one earlier step the current step depends on, taken when when matches. maxTraversalsPerRun caps how many times one run may take it. |
fanOut | see Run one step for each item | One activation per item in a list an earlier step recorded. |
The planner picks each step's model, agent, and tools. Tune overrides them for a single step:
Auto (default), tier LOW / MED / HIGH, or a specific
model.Default agent, or one of the workspace's named agents
(~/.sero-ui/agent/agents/). A role brings its own instructions and default
model; the orchestrator's step rules still apply on top. A role deleted before
the step runs falls back to the default agent, and the workflow shows a warning —
it never gets stuck on a missing role.The Context button sets a custom system prompt and hides chosen skills for the workflow's background steps. Leave the system prompt blank to use Sero's default, type to replace it, or clear it to drop the default entirely. The orchestrator's per-step result rules always apply on top. Tools are set per step in the plan, not here.
Managed-worktree workflows run in a separate checkout and do not prompt about changes in the workspace root. Workspace-root workflows check for uncommitted changes before background filesystem work starts.
The confirmation identifies the workflow, workspace, and trigger type. It links to the workflow detail and offers these actions:
Snooze state is durable. Scheduled fires that occur while snoozed collapse into one retry, queued events wait, and the dirty-workspace check runs again when the snooze expires.
Attempt history records these outcomes explicitly. A skipped pass has status Skipped and its reason; a delayed pass has status Snoozed and keeps its retry time even after the workflow resumes. Waiting remains reserved for runs parked on input or with no runnable step.
Every workflow has a delivery destination — where its results ship. You choose it (at create, or later with the Delivery button); the planner authors the steps that implement it but never picks it. Without a choice the workflow behaves as before: worktree workflows deliver a pull request, workspace-root workflows leave files in the working tree.
| Destination | Ships | Needs |
|---|---|---|
| Pull request | a commit + PR via gh | — |
| Workspace files | changes left in the working tree | — |
| Saved report | one file written in the workspace | — |
| Email draft | a Gmail draft (never sent) | the Google plugin |
| Send email | a sent email — approval-gated | the Google plugin |
| Chat post | a message to the channel in the params | a connected MCP chat server |
| Webhook POST | an HTTP POST to the URL in the params | — |
Destination parameters (channel, recipients, URL, report name) are set beside the picker and handed to the agent verbatim. A param the destination cannot work without — the webhook URL — is marked required: the workflow won't activate until you set it, so a run never stalls halfway to ask for it. Workflows installed from the catalog never include these values (they're yours, not the author's) — set them in Delivery before activating.
Working on an existing pull request. A workflow that reacts to PR events (CI failed, review comments) can be set to work on the PR branch from the firing event — a switch next to the worktree setting when you create it. Instead of starting a fresh branch, each run checks out the branch of the PR the event points at, so its commits and pushes update that PR directly. The branch belongs to the PR: deleting the workflow never deletes it. Only a firing event that points at a pull request can name the branch (CI results, PR opened, approvals, review comments); any other start — a schedule, a manual run, or a repo-wide event like "main updated" — stops with a plain explanation rather than guessing.
Receipts. A workflow that declares a destination completes only when its final step reports a delivery receipt — what landed and where (PR URL, message link, draft id, file path). A completion claim without one is rejected and the step revises; PR and saved-report receipts are additionally cross-checked (the PR must really be open, the file must really exist). Delivered receipts show on the run in history — as a link when the ref is a URL — and in the finish notification, and future runs are told what already shipped so a recurring workflow doesn't re-deliver it.
External destinations always ask first. Send email, chat post, and webhook POST are visible to other people, so the plan separates drafting from sending. The Workflow shows you the full draft on the input card with Approve/Reject), and a send only counts as delivered when its proof names your recorded approval for that exact content — enforced mechanically, not just prompted. A rejection sends nothing. Each approval covers exactly one send; the next iteration asks again with its new content. If a step ever sends something without approval, the workflow refuses to accept it as done and flags the run for revision instead.
If a destination's tool isn't available (say the chat MCP server isn't connected), the workflow still activates and runs with a warning; the warning clears on its own once the tool appears.
On create, and on every revision, the plan is checked for unique step ids, supported step types, at least one step, and dependencies that do not form a cycle. An invalid plan is repaired once; if it still fails it is saved as a blocked draft with the errors and cannot be activated.
A dynamic fan-out step runs once per item in a list that an earlier step discovers. For example, one scout per codebase area. The plan itself never changes: one run may find 3 areas and start 3 scouts, the next run 10 and start 10.
When a step fails, the model chooses one action: retry the step, revise the step, revise the plan (how steps are added, removed, or reordered), skip the step, wait, or block the workflow. Revisions are validated before they are applied.
Manual recovery on a blocked or failed workflow:
A workflow completes only when a planned validation or finalization step emits an explicit completion signal. Orchestrator never guesses that a workflow is done. If every known step has succeeded but no step signals completion, the workflow waits.
A workflow runs manual, on a cron schedule, by an event, or a hybrid of
both. Triggers only mark a workflow due — the lifecycle, the per-workflow lock, and
the limits still apply before anything runs. A cron workflow that became due while
Sero was closed runs once on next open (missed fires collapse into one catch-up
run).
The schedule, events, and stop condition are authored in the prompt and changed with Refine. Write them in plain language — "every morning", "when CI fails on my PRs", "whenever docs/ changes" — and Sero derives the trigger. They show read-only in the workflow's summary line, with the event details on hover.
The cron schedule is the one exception: the Scheduler app's Workflows tab lists
every scheduled workflow in the workspace and can edit or pause the schedule
directly (the set_schedule action). Only the schedule is editable there — the
workflow itself is still managed in Orchestrator. Pausing a hybrid workflow's schedule
stops only its scheduled runs; it keeps firing on its events.
The Workflows tab also lists pending snoozed retries. An event-only workflow snoozed from a manual run appears without cron editing controls and disappears after the retry starts.
| Source | Fires when |
|---|---|
loop:completed / loop:blocked / loop:asked-question | another workflow in the workspace finishes, blocks, or asks a question |
fs:changed | files in the workspace change (one batched event per burst) |
github:pr-opened, github:ci-failed, github:ci-passed, github:issue-labelled, github:review-requested, github:review-comment, github:pr-approved, github:main-updated, github:issue-opened | the matching activity happens on the workspace's GitHub repo |
webhook:<name> | an external system POSTs JSON to http://127.0.0.1:<port>/hooks/<name> |
An event trigger can carry an exact-match filter ("only the bug label") and a
plain-language condition ("only when the failing PR is mine") judged at fire
time. The event that started a run shows as a chip on that run in the history,
and its details (source, summary, payload) are given to every step.
Events that arrive while a run is already going are not lost: they queue (up to ten, oldest first) and each one gets its own run when the current one finishes. The workflow's summary line shows how many are waiting and which is next; if the queue ever overflows, the oldest event is dropped with a visible warning on the workflow.
Some situations have no event because nothing "happens" — a pull request going stale is just time passing. Write those as a schedule instead: "every morning, list my open pull requests that have had no activity for a week and …". A hybrid workflow can combine both — a schedule for the sweep plus events for instant reaction.
Sources only do work while an active workflow uses them: the file watcher, webhook listener, and GitHub poller all stop when the last subscribing workflow is paused. A workflow finishing can trigger another workflow, but chains stop after five hops and a workflow never triggers itself.
GitHub events are polled through the gh CLI using your existing login — no
tokens are stored. Sero uses one shared poller per workspace. It checks every 2
minutes by default and never checks faster than once per minute. It uses
conditional requests and slows down under rate-limit pressure. The Workflow's summary line shows when
GitHub was last checked and the local webhook port.
| Limit | Caps |
|---|---|
| Attempts per step | retries of a single step |
| Total attempts | retries across the whole run |
| Concurrency | steps running at once |
| Wall-clock | total run time |
| Tokens / cost | when the model reports them |
Reaching any limit blocks the workflow with a clear reason. Limits are management controls only — they do not restrict what a step's agent may do. They are set from your description at create time and changed with Refine, not through a form.
A profile-shared collection of saved workflows, reusable in any workspace.
Curated, ready-made workflows you install instead of writing from scratch. The Catalog tab sits beside My Library in the library view.
requiredTools), the
install still works and the draft carries a warning.Per-workspace Workflow state:
(A legacy single state.json is migrated into this split layout on first load,
keeping a backup.)
Shared Workflow Library — one copy across every workspace in the profile:
Catalog cache — repo registry plus one local clone per catalog repo:
Treat this as local workspace and profile metadata. It can include prompts, plans, step instructions, outcomes, timestamps, and token/cost figures. Redact before sharing logs or screenshots.
Orchestrator does not add a second permission, approval, command allow/deny, or tool-policy layer. Step work runs through standard Sero execution with the normal runtime tools. Management limits cap how a workflow runs, not what an agent is allowed to do.