Compass, Voyage dispensers, and Rutter
Some algorithms cannot safely live in one LLM conversation. They have durable state, constrained transitions, machine work between decisions, and a need to resume after the process or conversation ends. Rutter is the subsystem that owns that problem. It is not required for basic Officina onboarding.
Four concepts define the relationship:
- A Rutter defines the allowed evolutions, transition behavior, validation, machine work, faults, and recovery for one durable algorithm.
- A Voyage is one persisted traversal of that Rutter. Its stored Reckoning—not conversation history—determines where execution resumes.
- A VoyageDispenser is the process-safe authority for creating and operating an authorized collection of Voyages through opaque IDs.
- Compass is the thin LLM-facing controller. It follows the dispenser contract, assigns Voyages to agents, and never reaches into Rutter storage or passes Python runtime objects through the prompt boundary.
The flow is therefore Compass -> VoyageDispenser -> Voyage -> Rutter.
Compass sees only versioned dispenser operations and public Voyage results.
The dispenser owns run isolation and storage; the Voyage owns persisted
progress; the Rutter owns which transition is valid. A fresh process can resume
an existing Voyage by its ID without reconstructing state from the transcript.
For the main documentation path, see the Overview and Getting Started. See Dispatcher for the authorized process boundary and the Utility Map for current implementation ownership.
Authority boundaries
The boundary is deliberate:
- Rutter owns evolution entry, validation, routing, machine work, transition hooks, nested Rutters, faults, recovery, and durable history.
- A configured dispenser owns initialization modes, the arguments required by each mode, run isolation, Voyage discovery, and release of terminal working directories.
- Compass invokes only the dispenser's versioned process interface. It assigns
each returned Voyage ID to one agent and never passes Python
RutterorVoyageobjects through the prompt boundary. - Each Voyage agent follows only the public status, validation, and advance results for its assigned ID. It does not infer progress from conversation history or inspect Rutter internals.
Self-describing dispenser interface
The invoker supplies one authorized VoyageDispenser process binding. Every
dispenser has the same operations:
| Operation | Purpose |
|---|---|
help |
Explain the complete multi-agent operating workflow and the dispenser's modes. |
modes |
Return the default mode and every mode's explanation and required arguments. |
initiate [mode] |
Create one run's durable Voyages and return their opaque IDs. |
list |
List all currently authorized Voyage IDs. |
list --run-prefix PREFIX |
List only the Voyages initialized for one prefix. |
status VOYAGE_ID |
Read one Voyage's current public state. |
validate VOYAGE_ID |
Validate a response without mutating the Voyage. |
advance VOYAGE_ID |
Advance one Voyage, with a validated response when required. |
release VOYAGE_ID |
Delete one terminal Voyage's working directory. |
Compass begins with help; it does not depend on Rutter-specific Python
docstrings or runtime object introspection. The dispenser's blueprint controls
which callers may invoke the process binding, while help and modes explain
how an authorized caller should use it. Runtime self-description does not grant
access or replace versioned dependency pins.
Modes and initialization
A dispenser declares one or more initialization modes. Each mode has a
caller-facing explanation and a complete set of required arguments. The first
declared mode is the default, so omitting the positional mode selects it.
Compass must inspect modes rather than guess a mode or its inputs.
Initialization inputs describe the work to create, not the dispenser's internal storage. For example, an inventory dispenser may require a document entrypoint and chunk count in its default mode, while a debug mode additionally requires a gold-standard path so it can attach diagnostic hooks.
Every initiate call creates a fresh run and returns only the Voyage IDs for
that run. Reusing a prefix creates another run inside the same caller-selected
group. A mode's required arguments must be supplied exactly; missing or
unexpected arguments are usage errors.
Run prefixes and Voyage IDs
--run-prefix isolates independently initialized runs of the same dispenser.
It is an optional grouping label, not a run identifier. The dispenser creates a
fresh r-<uuid> run for every initiation. Without a prefix, Voyage IDs have the
form r-<uuid>/<numeric-index>; with one, they have the form
<prefix>/r-<uuid>/<numeric-index>.
The complete Voyage ID remains the authority used by status, validate,
advance, and release; those operations do not take a separate prefix.
A bare list is a global inventory across the dispenser's active runs.
list --run-prefix PREFIX is recovery and discovery for all retained runs in
one prefix group. It may contain several runs, so neither form is the assignment
set for a fresh initiation.
Compass operating loop
The controller follows this sequence:
- Invoke
help, thenmodeswhen initialization may be required. - Select the mode, its required arguments, and an optional grouping prefix.
- Invoke
initiateexactly once and retain the Voyage IDs it returns. Uselist, optionally scoped by prefix, only to recover or inspect retained work. - Assign exactly one independent agent to every Voyage ID returned by that initiation. Agents do not share or switch IDs.
- Each agent reads
status. For a Message, it performs the instruction, validates its response, and advances only after successful validation. For ready automatic work, it advances without a response. - Each agent reads fresh status after every successful advance and stops on a terminal result, fault, uncertain result, malformed result, or unknown status.
- After retaining a terminal result, the agent invokes
releaseunless it has an explicit reason to preserve the working directory. Nonterminal or uncertain Voyages must not be released. - The controller finishes only after every assigned agent has stopped.
If the dispenser binding, initialization inputs, returned IDs, or public results are missing or malformed, Compass reports a public-interface gap. It does not repair the gap by inspecting storage or constructing private runtime objects.
Durable storage and resume
The dispenser implementation owns its storage location. Callers do not supply
a run directory to lifecycle operations. A configured dispenser may organize
its state as voyages/<run-prefix>/<voyage-id>/ and its durable products as
artifacts/<run-prefix>/, but those paths remain implementation details rather
than Compass arguments.
The Voyage's persisted Reckoning, not session memory, selects the active
evolution after a process or interaction restart. Because Voyage IDs are
globally resolvable within the dispenser, a fresh process can reopen an assigned
ID and continue through the same status, validate, and advance interface.
Release is the explicit end of that durable working-directory lifetime.