Status: Implementation IMPLEMENTED × Exposure PUBLIC PREVIEW (phase E2 of the decision runtime). Loop: cmd/allternit-api/src/computer_subtask.rs. Contract member: run_subtask in allternit.computer.v2 (see Computer toolset). Decisions: POST /v1/decisions.

Overview

A planner model (any hosted or local model) is good at deciding what to do and expensive at deciding which button is next. run_subtask splits the two. The planner sends one bounded subtask: a goal, the literal inputs it may type, success checks and limits. The executor then runs every step as a typed decision: one choice from a fixed list of options, answered by the fast decision tiers in about 100–300 ms instead of a planner call. Every model family gets run_subtask the same way, as a member of the computer_v2 function tool. The tool guidance tells planners to hand bounded step sequences to run_subtask and to keep their own calls for planning and for whatever a subtask hands back.

The loop

Each step:
  1. Read. read_ui on the target window (the first read pins the window; later reads ask for the since diff of the live element map and patch a local copy, which costs well under a millisecond on a watched window).
  2. Build the options. Visible, enabled, named elements × the allowed ops: click for buttons, checkboxes, links and similar; type <input> into <field> for each literal input and text field; press Return in the focused field; then done and escalate. Elements the shared irreversible classifier flags (send, pay, buy, delete, publish and the rest), and anything in constraints.avoid, are never options unless constraints.allow_irreversible is set; even then, choosing one ends the subtask with needs_confirmation instead of running it.
  3. Decide. One POST /v1/decisions call (kind element, allow_abstain). Unfilled inputs first get one field decision each (“which field takes the email?”), run concurrently.
  4. Act. The choice runs through the same path as every toolset call: control lease, declarative policy and a durable audit row per step (execute_step). Predictable steps run as run_batch with an expect per step (UFO2’s speculative multi-action): all confidently placed inputs go in one batch that stops at the first failed check. Clicks run as act.
  5. Check. The success checks run with verify; {ask} checks are decisions of kind verify over the screen.
  6. Repeat until the checks hold (done), a decision picks escalate, max_steps or budget_ms runs out.
When a decision abstains or lands under its kind’s confidence threshold, the subtask stops and hands control back with status: "escalated", the reason, and a compact current screen (window, map version, up to 60 elements). It never guesses past an unsure step and never loops blindly: an action that changed nothing is not offered again. A subtask that ran before skips the loop: the replay cache replays its recorded steps with no decisions and re-infers only a step whose element moved. The subtask runs on the fast tiers only (the configured chain without the oracle). The oracle is a planner-class model call, so a step that would need it goes back to the planner instead.

API over GUI

A goal that an MCP tool or an API action can do is faster and steadier through that call than through clicks (Microsoft UFO2’s API-over-GUI routing, MIT). allternit-api doesn’t hold the planner’s MCP tools and doesn’t build their arguments, so the planner names the candidates: api_options: [{ tool, description? }] (up to 10). On the first step, before any GUI action runs, they are the first options in the decision, ahead of every GUI option. If the decision picks one, the subtask stops untouched with status: "use_api" and api: { tool, description }, and the planner makes that call itself. After the first GUI action they are no longer offered, so a half-done GUI path never doubles up with an API call. The tool guidance also tells planners to call an MCP tool directly when it plainly does the job.

Approvals and safety

On this computer (non-sandbox), run_subtask needs one approval for the whole subtask: the person sees the goal and the literal inputs. Its steps carry that grant and can only type those inputs. Lease, policy, the safety layer and audit still run on every step, and every step emits a computer.action event for the live view. The grant never covers a step the safety layer flags: an irreversible step, a mutating step in watch mode, or one the monitor wants confirmed ends the subtask with needs_confirmation and the step in held_step; a monitor pause ends it with paused; an app/domain list or credential-binding refusal ends it with denied. The planner runs a held step itself (with act), which asks the person. Secrets never go in inputs; use use_credential. The decision contexts wrap the screen text as untrusted data.

What it returns

status is done, escalated (with reason, screen and next), needs_confirmation (with held_step), paused, denied, use_api (with api) or failed. The whole result reaches the planner spotlighted as untrusted screen data. Each step names its decision id, chosen option, backend, latency and confidence.

Outcomes feed the flywheel

Every decision’s outcome is written back to the decision store, the same record as PATCH /v1/decisions/:id: success when its action ran and its check held (a field’s value matched the input, the screen changed after a click, the success checks held after done), failure when the action or check failed, skipped when it handed back or never ran. These labelled rows are what the shadow heads of the flywheel (E5) train and promote on.

Driver note (macOS 14)

Typing into a field no longer borrows key focus through SkyLight’s private API, which crashed the driver sidecar on macOS 14 when the app wasn’t frontmost. The driver writes the value through accessibility (focus, AXValue, read back; about 30–100 ms) and types on the Cua engine only for fields that refuse a value write.

Parallel and Best-of-N

Independent subtasks on separate computers run together in one run_parallel call, and a high-value subtask can run as N rollouts on N sandbox computers with a judge picking one (best_of). See Parallel subtasks and Best-of-N.