Skip to content

Running and observing

Fill the run form, dry-run a plan, watch generations stream live, handle approval gates, and track every run across the workspace.

For people running agent work16 pages in this section

Running a Loop is the arrive-and-use moment: supply its declared inputs, optionally dry-run the plan, then watch the run stream live until it reaches one named outcome.

The run form

The run form is generated from the Loop's declared inputs — a typed field per input, each with a type badge, a required marker, and inline validation. An agent input renders a picker; a boolean renders a switch. A sticky preview beside the form shows "what will run" — the contract, the verification rows, the seven terminal chips, and a lifecycle line — and recomputes on every change. After a successful dry-run, the preview switches to the returned materialized_contract, so input-backed goal text is exactly what the runtime will use.

Two actions submit the form:

  • Start run — start the run. Disabled until required inputs are filled.
  • Dry run — validate the inputs and render the first generation's plan without starting a run. It spends no budget and creates no run row. See authoring.

Close lives in the top bar and leaves the form without submitting it. A folded Limits · this run only section exposes six per-run limit overrides — iteration cap, token budget, wall-clock budget, no-progress window, fan-out ceiling, and gate max revisions — plus the budget-exceeded policy. Each numeric field shows the per-Loop default and the hard daemon ceiling, and clamps at the ceiling. The summary changes from "loop defaults" to "overrides set" only when a value actually differs.

The live run page

The run page is the truthful, real-time view of one execution. It streams over SSE and never renders a control the runtime does not support.

A sticky contract header carries the live status pill (pulsing only while running or watching), the generation and attempt count, the run's start metadata, the goal, and the valid Pause, Resume, or Cancel run action. Kill run is the destructive escape in the overflow menu and appears only while the run is live. The Progress story reads the run's materialized_contract; Inspect keeps the raw executed_definition available for authoring and audit questions.

Five meters track spend against limits — attempts, tokens, wall clock, cost, and breadth (fan-out). Bars warn-tint only near a ceiling. The cost meter is derived (tokens × price) and never a cap.

A generation timeline shows each generation as a collapsible card on a flat node spine. A fan-out renders as batch branches; a gate renders as a flat verdict card (pass tinted success, fail tinted danger) with its reason and route (revise or next_generation). When a Loop drives a channel conversation, the converse exchange is embedded inline. A right rail streams the live event feed and the run facts.

Each generation also shows its durable origin and parent_generation. Most generations point to N-1; a ratchet_restore points to the older best generation it was seeded from. Scored verdicts show score, and the accepted baseline carries the Best marker. The run header keeps best_generation and best_score separate from the current generation, so a later regression or an exhausted run does not make the last attempt look like the winner.

Approval gates

A human gate parks the run in needs-approval — a live pause, never a terminal outcome. The page shows the decision context (for a merge gate: the branch, diff, test result, and verifier) and three actions:

  • Approve → the run resumes.
  • Request changes → the run revises and continues into the next generation.
  • Reject → the run halts on a blocked terminal outcome.

Pause, resume, cancel, and kill

  • Pause is a generation-boundary operation, not a mid-node kill. The daemon records a pause intent; the in-flight generation's already-claimed nodes finish; the status flips running → paused only at the boundary. Pause is hidden or disabled outside running.
  • Resume continues a paused (or pause-requested) run.
  • Cancel run cooperatively moves through request, delivery, and drain before ending canceled with cause operator_cancel. The request is durable: boot recovery and scheduler sweeps retry interrupted delivery until the active worker acknowledges it or its session is already absent, then the run drains. If a canceled coordinator task belongs to a nonterminal Loop, recovery reopens that task and reserves one replacement coordinator run.
  • Kill run immediately fences stale work and ends canceled with cause operator_kill. It is destructive and never happens as a hidden escalation from Cancel.

There is no stop alias. Cancel and Kill are idempotent: retrying the same accepted request returns the committed winner instead of starting a second cancellation path.

Node controls and inventories

The run page offers only the verbs valid for a node's current state: Pause, Resume, Cancel, Kill, and Requeue. Pause supports drain (the default) or cancel; Resume supports plain, reset_attempts, or immediate, and can carry a JSON payload for a manual wait. Requeue is available only for quarantined work and creates a bounded successor generation.

Use the workspace inventories to find durable work before acting:

StateWhat it finds
waitingDurable waits and approvals that are parked.
quarantinedAttempts removed from dispatch until an explicit requeue.
attentionSilence, exhausted resume, or quarantined-dependency attention.
retryingAttempts with a durable next_attempt_at.

compozy loop nodes --state <state> is workspace-scoped, cursor-paginated, defaults to 50 rows, and caps at 200. Filter with --loop or --run-id; structured rows carry the exact run, generation, node, and item identity needed by the node verbs. See Failure handling for the command forms.

Runs across the workspace

The Runs view is a first-class, workspace-wide list of every execution across every Loop. A KPI strip surfaces "Active now," "Awaiting you" (the needs-approval queue), "Done today," and "Needs a look." An outcome filter spans the full status spectrum, rendering a segment for each status present in the window, plus Loop and date filters. Active and Past runs list in tables with an outcome pill, the Loop and run id, the goal, the generation count, timing, and a budget mini-bar.

Status detail versus run summaries

Use the detail surface when you need provenance or gate decisions. List surfaces stay deliberately small.

SurfaceShape
compozy loop status / compozy__loop_statusThe detail includes raw executed_definition plus input-resolved materialized_contract; run includes optional best_generation/best_score; generations[] includes parent_generation, origin, verdicts[], and outputs.
compozy loop runs / compozy__loop_runsEach run summary includes optional best_generation/best_score; it never embeds generation history.
Loop catalog listlast_run includes optional best_generation/best_score; it never embeds generation history.

The best fields are omitted until an approved finite score establishes a baseline. A detailed JSON response can therefore look like this:

{
  "run": {
    "generation": 3,
    "best_generation": 1,
    "best_score": 0.82
  },
  "generations": [
    {
      "generation": 3,
      "parent_generation": 1,
      "origin": "ratchet_restore",
      "verdicts": [{ "gate_id": "quality", "outcome": "rejected", "score": 0.61 }]
    }
  ]
}

Origins use the closed runtime vocabulary: initial, stop_when, reattempt, gate_revise, gate_next_generation, dod_retry, ratchet_restore, and requeue. See Ratchets for how a scored best changes succession.

Every surface, not just the UI

ActionCLIHTTPNative tool
Start / dry-runcompozy loop run [--dry-run]POST /loops/:name/run[?dry=true]compozy__loop_run
Run statuscompozy loop statusGET /loop-runs/:idcompozy__loop_status
List runscompozy loop runsGET /loop-runscompozy__loop_runs
Pause / resumecompozy loop pause · compozy loop resumePOST /loop-runs/:id/pause · /resumecompozy__loop_pause · compozy__loop_resume
Approvecompozy loop approve --gate-id … --decision …POST /loop-runs/:id/approvecompozy__loop_approve
Cancel / killcompozy loop cancel · compozy loop killPOST /loop-runs/:id/cancel · /killcompozy__loop_cancel · compozy__loop_kill
List node statecompozy loop nodes --state …GET /loop-nodes?state=…compozy__loop_nodes
Pause nodecompozy loop node pausePOST /loop-runs/:id/nodes/:node/pausecompozy__loop_node_pause
Resume nodecompozy loop node resumePOST /loop-runs/:id/nodes/:node/resumecompozy__loop_node_resume
Cancel nodecompozy loop node cancelPOST /loop-runs/:id/nodes/:node/cancelcompozy__loop_node_cancel
Kill nodecompozy loop node killPOST /loop-runs/:id/nodes/:node/killcompozy__loop_node_kill
Requeue nodecompozy loop node requeuePOST /loop-runs/:id/nodes/:node/requeuecompozy__loop_node_requeue

Live events stream from GET /loop-runs/:id/events (SSE). HTTP routes are workspace-scoped under /api/workspaces/{workspace_id}/…; the Loops API reference lists the exact paths and payloads. See also the compozy loop CLI.

On this page