All docs

Docs / API & CLI

Runs

A run is the second shape: you hand Amolfi a goal instead of a tool call. Amo triages it, delegates to the specialists that own the work, and follows it against your real workspace — the same work you would watch happen in chat.

Start one

Starting a run returns 202, never 200. A run is asynchronous by nature, and a run id must never read as finished work.

POST /v1/runs
{
  "goal": "draft the october email from what actually shipped",
  "working_style": "autonomous",
  "effort": "normal"
}

202 { "status": "queued", "run_id": "…", "working_style": "autonomous", "effort": "normal" }

Choose how involved to be

  • collaborativeAsk. Amo does the work and pauses only when your judgment would materially improve the result.
  • autonomousAuto. The default. Amo assumes you may be away, makes reasonable judgment calls, and continues as durable background work.

Working style changes collaboration, not authority. It never changes a tool’s permission, risk class, cost ceiling, or approval requirement. Omit it and the server uses autonomous; unknown write values are refused rather than silently mapped.

Choose the reasoning effort

  • lowFast. Speed first.
  • normalNormal. The default for everyday work.
  • highHigh. The kernel routes the run through the heavy reasoning model.
  • ultraworkUltrawork. The kernel uses its separately configurable Ultrawork route.

Effort is durable run state, not terminal decoration. Start, list, status, and receipts carry it, and each execution iteration uses its model route. Effort never changes permission or approval authority.

Find durable work

GET /v1/runs   → up to 25 recent goal-directed runs, current work first

Run history lives on the server, not in one terminal process. The CLI stores only one non-secret selected-run pointer per API origin and workspace so another terminal can use amolfi runs status or amolfi runs watch without inventing local history.

Follow it

GET  /v1/runs/{run_id}           → status, style, effort, specialists, activity, input or approval
POST /v1/runs/{run_id}/guidance  → steer it, or answer a needs_input checkpoint
POST /v1/runs/{run_id}/cancel    → stop it

Poll the run rather than holding a connection open. Each snapshot carries the run’s status, the specialists working on it, and the recent activity lines.

The status vocabulary

A run reports one of seven statuses. This is a deliberately narrow public vocabulary — the internal lifecycle is richer, and it stays internal so it can change without breaking you.

  • queued — accepted, not started.
  • working — in progress.
  • needs_input — parked on one work question. Send guidance to answer it and wake the same run.
  • pending_approval — stopped, waiting on a person. Not an error.
  • completed · failed · cancelled — terminal.

Activity lines are also a projection, not raw internals: they read as amo:…, specialist:…, tool:…, approval:…, or run:…. A tool line can carry the hostname it called. Render that as plain text and never as a link — it is influenced by whatever the tool was pointed at.

When a run needs an owner

needs_input and pending_approval are intentionally different. Guidance may answer a work question. It may never settle an approval.

A run that reaches something outward — sending, spending, signing, publishing — does not execute it and does not fail. It files an approval card and waits. The run surfaces as pending_approval with the decision’s id, and a workspace owner approves or declines in the app.

Machines propose. Owners approve. A run is a goal, not an authorisation.

There is deliberately no approve endpoint. Guidance is guidance — it maps to steering a run that is already yours to steer — and adding an approve verb would be the bypass this whole design exists to prevent, wearing a different noun. The scope vocabulary makes it unrepresentable: propose is the ceiling.

What bounds a run

A run’s reach is bounded by the token’s scopes, not by the goal’s ambition. A goal that needs a capability the token lacks stops with a 403 rather than returning a partial result and calling it done. Running a goal needs runs.runs.write; polling one needs runs.runs.read.

Read how it actually works. Setup, security, and the model underneath — in plain language, no marketing in the way.