Peer Supervisor v0¶
Status¶
Experimental and default-off. This protocol adds an observation and proposal
layer over registered peer_v1 agents. It does not add a new scheduler, create
agent sessions, or grant one identity durable authority over another.
The design is informed by Shepherd's runtime-supervisor experiments, where a stronger observer can compare concurrent effect streams and choose to inject, handoff, or discard a branch. LoopX keeps those actions as typed proposals until a host runtime exposes the required execution capabilities and returns evidence.
Why A Supervisor¶
Several equal peers are useful for independent progress, but they give the user multiple places to inspect. An optional supervisor provides one synthesis channel that can compare:
- goal status and user gates;
- each peer's quota and interaction contract;
- todo claims, leases, and continuation state;
- recent agent-scoped evidence;
- compact runtime effect or state references.
The user can use the supervisor task as the preferred control-room conversation while several peers run. The user may still talk directly to any peer. Decisions that change goal authority remain LoopX user todos or gates, so they do not live only in a supervisor transcript.
Configuration¶
The supervisor must already be a registered peer. Enabling it is explicit:
loopx configure-goal \
--goal-id <goal-id> \
--supervisor-agent <registered-agent-id> \
--supervised-agent <peer-a> \
--supervised-agent <peer-b> \
--execute
Omit --supervised-agent to observe every registered peer except the supervisor.
Disable the feature with:
Configuration is stored as coordination.supervisor with schema
peer_supervisor_v0. Absence means disabled. The canonical configuration has
execution_mode=proposal_only.
Generate the dedicated task body after configuration:
The prompt runs the supervisor's own quota guard, then consumes one read-only observation packet:
supervisor_observation_v0 selects from existing public-safe projections. For
each supervised peer it includes current claim, state, next action, last
activity, workspace/handoff references, recent thin evidence rows, and compact
effect references. It does not run another peer's quota guard, include raw
history or transcripts, or introduce write authority. Missing peer status or
evidence is projected as a warning and makes decision_input_complete=false.
Degraded status contracts behave the same way: the packet preserves the usable
read-only projection, reports compact health counts, and does not claim that
the decision input is complete.
Durable Proposals And Host Receipts¶
The supervisor records its exact normalized decision before reporting it:
loopx supervisor-event propose \
--goal-id <goal-id> \
--agent-id <supervisor-agent-id> \
--decision-json <decision.json> \
--execute
This appends a goal-local supervisor_proposed event. It remains
proposal_only; the proposal is never proof that a host changed a session.
The CLI can validate or append a rejected or failed attempt receipt:
loopx supervisor-event receipt \
--goal-id <goal-id> \
--agent-id <supervisor-agent-id> \
--receipt-json <receipt.json> \
--execute
An executed receipt is stricter: it can only be appended through the host
adapter API, which supplies verified capabilities outside the editable receipt
JSON. It also requires an opaque authority reference, compact evidence
references, and an explicit rollback boundary. Rollback mode is closed to
compensating_action or not_reversible; neither mode authorizes automatic
rollback. Missing capability, authority, evidence, or rollback boundary fails
closed. A normal CLI caller therefore cannot promote a proposal to executed
merely by naming a capability. rejected and failed receipts remain durable
attempt evidence without projecting success. Reusing the same record id is
idempotent when the payload matches and a conflict when it differs.
Read the compact projection with:
The ledger is local-private goal runtime state. JSON input paths are never recorded, and inline credential-shaped values are rejected.
Decision Contract¶
supervisor_decision_v0 uses an enum-like closed set:
| Kind | Meaning | Required host capability |
|---|---|---|
observe |
Keep watching; no intervention is justified. | none |
inject |
Propose a bounded message to an existing session. | session_message_injection |
handoff |
Propose continuing a target from a named source state. | session_state_fork, workspace_state_transfer |
discard |
Propose terminating a failed branch while retaining compact evidence. | session_termination |
Every proposal names reason codes and compact evidence references. inject
names a target and message. handoff names source, target, and state reference.
discard names target and state reference.
The v0 CLI does not execute these actions. Missing host capabilities leave the proposal unexecuted; a model response is never accepted as proof that a session was injected, forked, or terminated. Destructive actions require explicit host authority even after an executor exists.
Future Fork Extension Gate¶
A Shepherd-style fork is useful, but it is not another spelling of
handoff:
| Operation | Source continues | Target | Scheduling effect |
|---|---|---|---|
handoff |
Usually finished or yielding | Another registered peer continues from state_ref |
Transfers continuation; should not increase active branch count by default |
future fork |
Yes | The scheduler leases a temporary execution branch to an idle capability-matched registered peer | Increases active work and must reserve bounded capacity |
LoopX should add fork to the closed supervisor decision set only when a real
host call site can satisfy the complete execution contract. Until then it stays
a documented extension gate rather than speculative production schema or a
prompt-only action.
Identity And State Model¶
Raft's persistent-agent model is the right constraint for LoopX: one registered
peer keeps one durable identity and accumulated context. A fork copies
execution state, not identity. It creates an execution_branch_id, then the
scheduler assigns a branch_lease_id to an existing idle, capability-matched
executor_agent_id. The source and executor may be the same peer, but the
normal multi-agent path uses another available peer so the source can continue.
The scheduler must not register a cloned peer, copy durable memory into a new
identity, or create a hidden leader/follower relationship.
The branch therefore separates four identities explicitly:
source_agent_id: the peer whose versioned execution state is forked;source_state_ref: the immutable execution and workspace checkpoint;execution_branch_id: the temporary branch identity;executor_agent_idplusbranch_lease_id: the registered peer temporarily scheduled to run it.
The branch lease is narrower than normal todo ownership. It authorizes bounded execution of one branch, not claiming the source peer's todo, inheriting its quota, or merging its durable memory. If the result is selected, ordinary LoopX continuation or handoff policy decides which peer owns the next durable todo.
The source must be a versioned immutable source_state_ref, not a reconstructed
chat transcript. The branch receives an isolated session/process view and a
copy-on-write workspace view. Its effect and evidence streams remain separately
addressable and join back to the source through stable refs.
Admission And Settlement¶
Forking consumes more compute and creates competing outputs, so a supervisor proposal is not enough to start one. A future host admission receipt must prove:
versioned_execution_stateandsession_state_fork;workspace_copy_on_writeor equivalent isolated workspace state;scheduler_capacity_reservationandidle_peer_selection, including capability matching, fanout, cost, fairness, expiry, and cancel boundaries;branch_execution_lease, preventing one idle peer from accepting competing branches and making lease loss fail closed;- an opaque authority ref and idempotent branch id;
- compact effect/evidence refs without raw transcript injection; and
held_result_settlement, so branch output cannot land in the canonical workspace or LoopX state merely because the branch finished.
The minimum lifecycle is:
proposal_only -> admitted -> leased -> running -> held_result
-> failed
-> expired
held_result -> selected | discarded
selected still passes through ordinary LoopX todo ownership, validation,
review, merge, and user-gate policy. It is not an automatic merge. discarded
retains compact evidence and releases the executor peer plus reserved capacity;
it does not authorize destructive git cleanup. A branch that expires or loses
its lease must fail closed instead of silently continuing.
Supervisor And Workspace Interaction¶
The supervisor remains the preferred synthesis channel, not a centralized company brain. Branch progress should appear as queryable inbox-like projection rows so the supervisor can pull relevant changes without pushing every branch event into its context. Completed branch output remains held until explicit settlement, matching an agent-native workspace where persistent peers keep their own context and exchange bounded messages or artifacts.
This extension should first ship as a default-off dry-run canary over a concrete
multi-agent scheduler/host adapter. Required validation includes capacity
exhaustion, duplicate fork idempotency, source-state immutability, workspace
isolation, capability-based idle-peer selection, competing branch leases,
branch expiry/cancellation, held-result settlement, and recovery when the host
reports a partial failure. Only that evidence justifies widening
SupervisorDecisionKind and the public event schema.
Opt-In Inject Adapter Canary¶
loopx.control_plane.agents.supervisor_inject exposes one narrow Python host
seam for inject. LoopX ships no default adapter and no CLI switch that enables
it. A host must explicitly supply an adapter with
session_message_injection, a rollback mode and opaque rollback policy ref,
plus an authority ref for the individual execution. Dry-run validates the
entire request without calling the host.
On execution, the adapter receives a stable SupervisorInjectRequest and must
return a typed SupervisorInjectResult. LoopX then appends the capability-
matched receipt. A prior executed receipt suppresses a second host call, so a
repeated control-plane request is idempotent. The rollback field records the
boundary; it does not retract a message or grant authority to send a
compensating message. handoff and discard remain proposal-only until their
own host contracts and safety evidence exist.
Authority Boundaries¶
- The supervisor is an equal peer with an extra observation responsibility.
- It cannot claim another peer's todo, spend another peer's quota, or rewrite a user gate merely to resolve a proposal.
- Review and handoff remain ordinary task policies; the supervisor does not become a hidden review owner.
- Pre-peer hierarchy fields remain confined to the existing exactly-once migration reader. They are not a live configuration model and are not used by this protocol.
This separation lets LoopX test whether richer synthesis improves delivery
without coupling the State Kernel to a particular session runtime or bringing
durable hierarchy back into peer_v1.