Workflows are in preview. Where they aren’t open to your account, every Workflows endpoint answers a bare
404 with no body. Don’t retry it; ask Orgo to open Workflows for the account.What a workflow is made of
A workflow has exactly one start, then up to the steps it needs. Each step after the start names the steps it follows (after), so steps can run side by side and join again.
Anything that changes from run to run is a fill-in in braces, like
{report} or {first name}. A fill-in is something an earlier step hands on, something the start carries, or a setting you fill in once.
Here is a complete workflow. Each weekday at 9:00 AM, Hermes writes a report and it is posted in a Slack channel you name once:
The workflow’s computer
Every workflow runs on one of your computers. Its app steps use the apps connected there (the same ones Connectors shows), its agent steps ask the agent installed there, and its screen and script steps run there. Pick the computer once withPATCH /workflows/{id} and { "computer": "<computer UUID>" }. A workflow whose steps need a computer can’t run without one.
How a workflow starts
Any workflow can also be run by hand: Start a run,
orgo workflows run, or orgo_run_workflow.
A new workflow is off. Turning it on (PATCH with { "on": true }) sets up its start, and it works only while the workflow can run: if it can’t, the answer is 422 with code: "not_ready" and a to_fix list in plain words. A later change that leaves it unable to run turns it off, and the answer says turned_off: true.
Check it before it runs
Validate proves a workflow will work, and sends nothing. It looks at the computer (without waking it), each agent installed there, each app signed in (with a read that proves it), the channels and sheets it names, the secrets its scripts read and your credit. Each step answersok, or say (what is in the way) and fix (the one thing that fixes it).
Runs
A run goes on in the background. Start a run answers202 at once, and you read it again with Get a run or follow it with Follow a workflow.
A run whose steps use the computer’s agents or screen wakes the computer as it starts, if it is asleep. A timed start wakes it about 3 minutes before. A run that still finds it asleep stops, and its fix wakes the computer and runs it again.
Stop a run ends a run wherever it is: mid-step, between tries, or waiting. What it runs on the computer is ended. Steps that already ran stay done.
A run waiting at Check with me goes on only when you say go, on the canvas or signed in. A key or an agent may stop it with Answer a waiting run and
{ "choice": "stop" }, but a go from a key answers 403 with code: "person_required". An agent that finds a run waiting should tell you, not answer for you.
Reliability
- Each start runs once. A time is keyed by the time itself, so it starts one run however many times it fires. An app event sent again (twice at once, as a new event, or late) is the run it already started.
- On time. A time missed while Orgo was down runs once, late, while less than half its period has passed (6 hours at most). The run says how late it started. Past that it doesn’t run, and it is listed as a stopped run with no steps. A computer asleep is woken about 3 minutes before a timed run that needs it.
- Retries. A failure an app says will pass is tried again over minutes. A workflow that sends many keeps each app’s pace on its computer, so the rest wait their turn instead of failing.
- Retries of your own calls. Send an
Idempotency-Keyheader when you create a workflow or start a run. A retry with the same key answers what the first request did, and never makes a second workflow or a second run. - Saved. Workflows, their settings and their last 20 runs are kept across restarts. A run uses the steps as they were when it started; a later edit never changes a run already going.
Safety
- Text from outside gets a turn with no tools. When an agent step reads something other people wrote (an email, a message, what an app found, what an event or a caller sent), Hermes and Claude Code answer it in a turn with no tools, no MCP servers and no secrets in their environment. OpenClaw has no such turn, so a workflow that hands it outside text is refused before anything runs, and Validate says so on that step.
- Facts are checked. Before a send goes out, every number, date and name an agent wrote must be in the data it was handed, or worked out from it. If one isn’t, the agent gets one more turn; then the run waits at Check with me if the workflow has one, or stops and sends nothing.
- Scripts get only the secrets they name. A script runs in a clean environment: no
/root/.envand noORGO_API_KEY. A workspace secret is there only when the script names it, like$STRIPE_KEY. - You say go. Only you approve a Check with me step. A send whose words an agent wrote after reading other people’s words needs a Check with me before it when it goes to someone the event named, and Validate says to add one.
- Who a send reaches never comes from an agent’s answer. The recipient, channel or sheet is set in the step.
What a key needs
Workflows have their own permission group,workflows: read to list and read workflows and their runs, write to make, change, delete and run them. A key without it answers 403 with code: "key_permission". Two more rules:
- Making a workflow from
describealso takes AI write, since a model drafts it. - Picking a workflow’s computer, and validating, turning on or running a workflow whose steps act on its computer, also take Control write and AI write: the same access that controlling the computer takes.
A complete example
Make the morning report above, check it, turn it on and run it once. Replace$COMPUTER_ID with the UUID of a computer where Hermes is set up and Slack is connected.
- API
- CLI
- MCP
$RUN_ID with the run_id from step 5. To have Orgo draft the steps instead, send {"name": "Morning report", "describe": "Every weekday at 9 AM, …"} in step 1, then read to_fix for the settings it asks for. To change the steps, read the workflow, edit its lines and send them back with Replace a workflow’s steps and If-Match set to the version you read.API reference
Every error is JSON:
{ "error", "code", "say"?, "next"?, "to_fix"? }. say is the problem in a few words, and next names the call that fixes it.