Loops in practice
The Loop covers the model. This page covers the machinery you configure and operate: what a Loop binds, how evidence reaches it, and what keeps several Loops honest on one Property.
What a Loop binds
- One target Metric and a guardrail set. A revenue-class target must resolve a leading-indicator pairing before the Loop can be created.
- A Property and environment scope. Staging traffic cannot move a production Loop.
- An audience and funnel-stage scope.
- A cadence — the interval at which the Loop wakes even when nothing fires.
- Signal subscriptions, stored as first-class records.
- Attached Analyzers, with their versions and triggers.
- Its working state: the current turn, transition history, intake queue, proposals, and the decision log.
Configuration and lifecycle evidence are stored separately. Editing a Loop’s setup never rewrites what happened.
Subscriptions and routing
A subscription declares which Signals the Loop cares about. Routing happens at write time: when a Signal is committed, it is matched against current subscriptions in the same environment and delivered to the Loop intake as part of a committed batch. Changing subscriptions later does not quietly re-route the past — replaying older Signals into a Loop requires an explicit, audited backfill.
Cadence and re-arming
Cadence is a per-Loop interval, checked by scheduled scans and delivered through the same intake seam as every other event — a scheduled nudge is not a special path. When a turn completes and the Loop returns to listening, the cadence re-arms for the next interval. Threshold and watch subscriptions fire discretely: a Metric watch emits one Signal per firing rather than a stream, so a noisy source does not spin the Loop. Heartbeats run alongside — a Loop that should have advanced and did not is flagged as stalled, not skipped.
The intake queue
Everything that can move a Loop arrives through one intake: threshold and anomaly firings, cadence events, Metric watch deltas, and explicit diagnose requests. Each transition validates the current state, the triggering event, policy readiness, the acting Principal, and idempotency — a redelivered batch cannot advance a Loop twice. A paused Loop does not auto-advance, no matter what arrives.
Proposals
Proposals are submitted and withdrawn as explicit operations, and two rules hold. A proposal cannot omit prior Decision context: it is bound to a snapshot of the decision log at the moment it was formed. And evidence gaps cannot be bypassed on the way to activation. Activation itself is requested through policy, which allows, denies, or raises an Approval Request. Withdrawing a proposal leaves the turn history intact.
Pause and archive
Pause and archive are status controls beside the state machine, not transitions inside it. Pausing stops auto-advancement; resuming picks up from the true state; archiving retires the Loop. None of these rewrites the transition record or the decision log.
Several Loops, one Property
Running more than one Loop per Property is normal, and Torno does not pretend simultaneous Changes are independent when they are not. Three mechanisms keep concurrency honest:
- Experiment layers. Experiments enforce mutual exclusion through layers, so two Changes cannot overlap an audience without the overlap being acknowledged.
- Metric collisions. When two Loops pull on the same Metric, the collision surfaces on the Loop board and on the Needle for a policy or human tiebreak.
- Program holdout. An optional holdout measures the growth program as a whole, not only its parts.
Where you operate a Loop
The Loop board shows every Loop by true state: target movement, stalls, pending approvals, live Changes, and collisions. Detail pages show turn history, the Signal to Insight to Hypothesis to Change lineage, evidence, and the decision log. Creating a Loop is a guarded five-step flow rather than a loose form.
Agents get the same operations through the CLI, the versioned API, and MCP tools — see the agent interface and Loops as code:
torno loop list
torno loop status <loop_id>
torno context <loop_id>
Whatever the surface, the answers derive from the same backend composition. A Loop looks the same to a human on the board and to an agent holding torno context output — by design, not coincidence.