DSH / Pi: L1 Observation and Managed Runtime Selection¶
Status: evidence-backed implementation assessment, not a runtime promotion. Scope: the shared goals of Reliability Diagnostics and Desktop Execution Frontends. 中文
Decision¶
Keep DSH as the first L1 event source. Do not infer that DSH is already the preferred production Mode B runtime. Retain Pi as a managed-runtime candidate. The first choice minimizes the cost of qualifying an existing passive observer; the second requires lifecycle, provider, crash-recovery and outcome evidence that a plugin event fixture cannot supply. No quantitative winner is claimed.
Two DSH roles appear in this document and must not be conflated. The bounded managed Turn host (LoopX's adapter choice for one governed Turn) is credential-bound; its default-host resolution shipped in PR #4443, and the steward channel reaches it through the one-segment chat transport recorded below. The L1 event source and session-owning runtime role stays opt-in and is not promoted by that binding; it still needs the C0, C1, overhead, retention and Mode B rows.
Managed Execution Surface (2026-09-15)¶
Selection is constrained by what the repository ships today, not only by what an upstream harness can do. The managed bounded execution unit is the governed Turn:
loopx turn run-onceaccepts--host codex-cli|dsh|generic-cliwith--execution-mode isolated-headless: LoopX decides, a host adapter invokes the agent CLI, an independent validator proves the postcondition, and only a passing result is committed;loopx host-mode-planselectsisolated_headless_turnfor thecontinue_without_uiintent only when the host declarestyped_host_adapter; without that declaration it reports the mode as not ready and names the missing capability;- session ownership (
managed_runtimeversusattached_host) is not decided here. It belongs to Agent Session Execution Modes, which also owns the M1-M4 integration milestones and the cross-frontend projection row.
Three evidence states appear below and must not be read across them. The list is dated 2026-09-15 and is written to land with the managed stack:
- already on
mainon 2026-09-15:loopx turn run-once --host codex-cli|dsh|generic-cli, thedshhost adapter, thehost-mode-plangate above, and the dsh pindeepseek-harness-sdk==0.1.2a3; - not on
mainon 2026-09-15; expected to land with this document: the explicit host selection (loopx/control_plane/turn_driver/host_binding.py, PR #4443), the steward channel's explicit executor selection (loopx/chat_manager.py, PR #4446) and the0.1.5rc1dsh pin (PR #4420). A later reader who finds those PRs merged can read those rows as shipped; a reader who does not must treat them as stack-only. All three merged on 2026-09-15, so those rows are shipped, and the steward rows below were revised twice afterwards: the first revision still defaulted the steward channel tocodexand left the managed host unreachable from it, and the second made that default credential-conditional, so a discovered credential re-pointed the surface a person talks to. This revision restores the steward's shipped default tocodexon every machine and reaches the managed host only by explicit selection, which is the shape the row below states; - local live qualification, not a repository gate: rows marked as local evidence below. Reproducing them needs an operator credential, and CI asserts none of them.
| Role | Source | Selection today | Promotion gate |
|---|---|---|---|
| Default managed execution host | LoopX Turn plus the dsh host adapter, bound to an operator-supplied model endpoint |
shipped product default, credential-resolved: the managed dsh host when the operator credential is configured, the individual codex-cli host when it is not; LOOPX_TURN_HOST re-points whichever resolved and an explicit --host wins (PR #4443, default resolution with this change) |
keep the typed host request/result, independent validation, and the operator-owned credential boundary; do not replace it without an equal or stronger contract |
| Steward channel executor | the interactive Chat transport the steward answers on | one machine setting, then one service-environment value, then the shipped product default: this machine's steward_executor machine configuration (edited from the Dashboard, read back by loopx machine-config describe/inspect, landed 2026-09-16) selects the executor for that machine, LOOPX_MANAGER_ENDPOINT bootstraps or names an unlisted adapter, and the shipped default stays codex on every machine; a selection of the managed host (dsh) moves the model and the reasoning effort with it |
the segment transport's typed limits (no streaming, no cross-turn host session, read-only sandbox) stay disclosed and read back, no managed lane may depend on an individual subscription, and the namespace stores no credential and grants no authority |
| Supported alternative Turn host | LoopX Turn plus the codex-cli adapter |
explicitly selectable, and the credential-resolved default of the managed row above on a machine with no operator credential; it is the individual executor kind, so it is billed to one person's CLI login |
no managed lane may silently depend on an individual's personal CLI subscription: the individual host is reached only as that credential-resolved default and is read back as no_operator_credential, never substituted for a host the operator selected |
| L1 event source and session-owning runtime candidate | DSH | opt-in, not promoted; the bounded Turn host role is the default row above | the C0, C1, overhead, retention and Mode B rows in this document being run and reviewed |
| Optional visible host loop | Pi | not a managed runtime | declare a per-binding session mode with readback, prove single-executor behavior under restart, "conversation is not a receipt", non-authoritative host-local state, and one real-host restart row |
Optional Ark governed Turn profile¶
loopx-ark-turn is a separately
installed provider selected explicitly through --host generic-cli with fresh
iteration context. It shares DSH's signed request/candidate conversion; LoopX
still owns admission, independent validation, work writeback and quota. A
per-Turn stdio MCP process exposes only operator-selected tools with bound work
identity. Provider model usage and resource-cleanup receipts are observations,
not accepted-work quota or a second task lifecycle.
This profile does not change the default host or the native Ark goal_once
profile. Native Goal continuation and outer LoopX Turn continuation must not
drive the same binding. The research composition example
exercises a managed coordinator delegating to local workers; it does not promote
a persistent steward Chat transport, recursive fleet supervision, full live
steering, or a shared authority service. Use its explicit setup/readback/cleanup
instructions and preserve failed versus untested qualification boundaries.
The example's integrated acceptance path uses five preauthorized canonical
tasks and startup-only owner configuration. Both hosts select exact work via
turn --todo-id; fresh TS Todo completion precedes accepted result return.
Synthesis checks current child completion, binding and artifact hashes.
Provider cleanup, Turn progress and canonical completion remain separate.
This does not supply dynamic work derivation or another Python lifecycle owner.
Its default profile uses a local DSH lead with two DSH and two Ark members;
the cloud reviewer consumes a completed local analysis before returning its own
result. A secondary cloud-led profile tests the inverse delegation direction.
Both reuse the same Turn host adapters; neither changes the steward default.
Managed host binding and live qualification (2026-09-15)¶
A managed host binding names four things: the host adapter, the provider, the
model, and where the credential comes from. The DSH binding is the DSH Turn host
with provider deepseek-official, model deepseek-v4-flash (DeepSeek V4.1
Flash) at reasoning effort high, an endpoint from the operator environment
(DEEPSEEK_BASE_URL) and a credential from the operator environment
(DEEPSEEK_API_KEY).
LoopX selects the default host for bounded managed Turns and never infers it
from a launch-time surprise (loopx/control_plane/turn_driver/host_binding.py):
an explicit --host or LOOPX_TURN_HOST always wins, and only when neither is
configured is the shipped default resolved from the operator's own credential
facts -- the managed dsh host when a credential exists, and the individual
codex-cli host when one does not, because an unauthenticated managed host
would refuse to run. The distinction that matters is between a default and a
decision: a credential may resolve a default that would otherwise have to pick
a host at random, but it never re-points a host the operator already selected.
A lane resolved onto the DSH host therefore never depends on an individual
developer's CLI subscription being available, funded, or logged in, and a lane
without an operator credential never silently borrows one either.
This change also rewrites the promotion gate on the supported alternative host in the table above. It read "an individual lane must be selected, not reached by default", which the credential-resolved default contradicts. The rewritten rule keeps the original intent -- no lane may depend on one person's login without the operator being able to see that it did -- and names the readback that makes the dependency visible instead of forbidding the disclosed default.
The steward channel is a different surface, and after the revisions recorded
above its default is one endpoint rather than one rule: codex, the interactive
CLI endpoint, on every machine. Three layers select it, in one order: the
machine's steward_executor machine configuration, then
LOOPX_MANAGER_ENDPOINT, then the shipped default. Selecting the managed host
(dsh) moves the endpoint, the model and the reasoning effort together, so the
channel can never end up with an operator model driven through an individual
CLI login. The rule that decides a credential here is the opposite of the Turn
row's: a credential authenticates the endpoint that was selected and never
re-points the surface a person talks to, because a conversation must not change
hands mid-thread when a key appears in the environment. The readback still names
where the endpoint came from (executor_endpoint_source, now including
machine_configuration) and, for a shipped default, which decision it was
(executor_endpoint_default_reason), so an operator reads a decided default
instead of inferring it from the resolved host name.
A manager connection does not keep a second copy of that decision. The
connection record stores the resolved endpoint as an observation with its
source, and every read path -- the Lark route, the authorized-connection
resolution, and the Turn that answers on the channel -- re-resolves from the
machine. A record written while a different default was in force therefore
cannot keep answering on an endpoint the operator has since replaced, which is
what previously let a machine whose readback said dsh keep running its
steward on codex. When the machine does change the selection, the Session
bound to the channel still runs on the earlier endpoint; that Turn is refused
with the typed manager_channel_executor_rebind_required receipt, and the reply
names the one action that repairs it -- re-applying the connection, which opens
the channel Session on the endpoint the machine now selects.
Both managed surfaces resolve their execution profile from one owner
(loopx/control_plane/turn_driver/execution_profile.py): provider
deepseek-official, model deepseek-v4-flash (DeepSeek V4.1 Flash) and reasoning
effort high, overridable by LOOPX_TURN_PROVIDER / LOOPX_TURN_MODEL /
LOOPX_TURN_REASONING_EFFORT and, at lower precedence, the legacy DSH_PROVIDER
/ DSH_MODEL. The readback is one line, execution_profile, shaped
deepseek-v4-flash@high in the shipped case, with the provider prepended only
when it is not the shipped one; it is one line because every plan payload carries
it and the agent-facing output budget is a contract, and whichever values the
line names are the values that run, so an owner-set model appears as itself.
Credentials authenticate the selected profile and never choose it; the one
thing a credential resolves is the shipped host default of a bounded Turn
nobody selected, and that resolution carries its own readback source.
Evidence for this binding, separated by source:
- repository-covered without any provider call: with an operator credential the
shipped default is
dshand without one it iscodex-cli, an explicitLOOPX_TURN_HOSTre-points either default, and an explicit--hoststill wins over all of them (tests/test_turn_default_host_binding.py,tests/test_turn_managed_executor_binding.py,examples/loopx-turn-managed-executor-binding-smoke.py,examples/loopx-turn-managed-default-flow-smoke.py); - local live qualification with the real SDK and runtime
(
deepseek-harness-sdk==0.1.5rc1, the pin PR #4420 proposes;mainstill pins0.1.2a3and the same pair also passed there): the in-process--host dshpath and thegeneric-clisubprocess path; - local live qualification: one governed Turn reached
validated_progress— the host executed the bounded action, an independent validator proved the postcondition, and only then did writeback and quota spend follow; - local live qualification: a Turn whose postcondition was not proved fail-closed instead — no writeback, and the quota slot spend count stayed at zero.
Open gaps before this binding is a promoted production default:
- the runtime snapshot bundled as
deepseek-harness-runtime-bin==0.1.5rc1cannot boot the stockheadlessprofile as shipped: a profile row pulls@deepseek-ai/dsh-session-title-first-prompt-llm, which imports the omitted@deepseek-ai/dsh-session-title-llm, and resolution runs inside the packaged snapshot, so installing that package into a profile directory does not change it. The current local workaround is a binding overlay that disables the affected row. The managed host path is unaffected: it does not selectheadless, and the defaultsdkprofile boots and exits cleanly; - the LoopX DSH Turn composition must name the tool rows a managed action needs
(
@deepseek-ai/dsh-tool-fs,@deepseek-ai/dsh-tool-bash). Without them a live model can answer but cannot act, and the Turn ends in a validation failure rather than in work. - the host-mode plan used to map the unattended intent to the compatibility
path:
isolated_headless_turncarriedturn_host: generic-cli(loopx/host_mode_planner.py), so theloopx turn plancommand it printed named--host generic-cliinstead of the selecteddshdefault recorded above, which is correct as a labelled rollback path but was not labelled as one. Decided and shipped: the plan takes the "write out the resolved default" option. The preview command pins no host, the pinned compatibility variant is reported asplan_command_rollback, and the typedturn_mapping.host_selectionstates which of the two a command is; targets that genuinely need a visible identity (transitions intovisible_tui) still pin their host.docs/reference/protocols/host-mode-plan-v0.mddefinesturn_mapping.hostas the mode's declared host and scheduler context rather than as an already-resolved concrete host. The plan's--host-identitylist still covers visible hosts only, because a headless-only host such asdshcannot own a visible session.
Mixed local/cloud managed qualification (proposal)¶
The session execution RFC separates provider, session ownership and continuation owner. Extend the same managed work contract to a qualified cloud host; do not encode local = Turn and cloud = native Goal. Keep the current managed-host and steward defaults above.
LoopX's public Ark Managed Agent host contract currently specifies one-shot Goal activation, native continuation and no outer Turn driver. A cloud governed-Turn adapter is a separate, unqualified opt-in candidate, not a reinterpretation of that profile. DSH's bounded Turn adapter and same-session plugin likewise have different continuation contracts; qualification cannot be borrowed between them.
First qualify a complete local/cloud work unit: actual tools/artifact transfer, typed result, independent rejection of a wrong artifact, accepted writeback, usage readback, cancellation and recovery. Then qualify two dependent work cycles and worker-initiated delegation using the shared collaboration contract. A host adapter transports Agent decisions; it must not contain the scenario's business phase sequence. Waiting parents must not occupy every slot needed by children.
Native Goal qualification additionally needs publicly documented activation and identity, duplicate-activation behavior, evaluation/terminal readback, bounded resource use, defer/wake and restart handling. A successful message or an idle session is insufficient. A provider API or slash wrapper stays in its adapter; it is not a generic LoopX command. Provider claims require public versioned sources and reproducible qualification; this proposal cites only LoopX-side contracts and makes no new claim about an Ark deployment or API guarantee.
Report actual provider usage separately from LoopX's validated-work quota: rejected work can still incur inference cost. Unknown usage is not zero. Promote only the tested profile; keep unavailable capabilities explicit and preserve rollback to the prior selected profile without creating a concurrent driver.
Evidence Baseline¶
LoopX was inspected at bf217e1e01bec79f357c9ecbd580cf2dfa73db8b.
The implementation paths below are repository-relative:
packages/dsh-loopx-plugin/src/observer.ts: pinned activation, session event compaction, first-append safety, bounded buffering and flush isolation.loopx/capabilities/reliability_diagnostics/{receipt,projection}.py: independent validation, integrity classification and authority-free diagnostic readback.loopx/dsh_goal_mode/turn_host_adapter.py: a bounded Turn connector, opaque session lineage, SDK calls and failure translation, not a desktop outer loop.loopx/pi_goal_mode/{loopx-goal.ts,pi-goal-loop-runtime.mjs}: a visible-host integration with bindings and continuation behavior; not a passive observer.apps/desktop/loopx-control-plane/src-tauri/src/services.rs: service process management must not be mistaken for the complete managed Agent lifecycle.
The dsh pin moved in two steps, and reading this document needs both states.
main today pins deepseek-harness-sdk==0.1.2a3. The managed stack moves that
pin to the newest released upstream channel rather than an unreleased tag:
deepseek-harness-sdk==0.1.5rc1 / deepseek-harness-runtime-bin==0.1.5rc1 on
PyPI (PR #4420), matching latest for @deepseek-ai/dsh on npm (checked
2026-09-15). Upstream next and alpha tags are newer than that channel and are
not adopted here.
Upstream references were inspected on 2026-09-06, pinned independently of the versions validated by LoopX:
- DSH README at d347e703: Cordis/plugin architecture and explicit developer-preview compatibility risk.
- Pi SDK at 9767ba27: event subscription, session operations and runtime replacement APIs.
- Pi extensions at 9767ba27: event hooks with context-injection, tool-blocking and result-modification power.
The historical Pi repository URL now redirects to earendil-works/pi; the
inspected SDK uses @earendil-works/pi-coding-agent. This is an upgrade-check
input, not permission to replace LoopX's installed package or assume API parity.
Comparison by Product Requirement¶
| Requirement | DSH evidence | Pi evidence | Selection consequence |
|---|---|---|---|
| Passive observation | LoopX ships a separate observer entry, three session publication hooks and pre-append rejection | SDK offers session.subscribe; extensions also offer interception hooks |
DSH has a qualified contract slice; a Pi adapter must choose subscription over intervention and prove isolation |
| Session identity / resume | Existing Turn connector derives session lineage; observer separately requires exact goal/session/run identity | SDK separates AgentSession from AgentSessionRuntime replacement/resume operations | Test identity after restart/fork for each adapter; method availability is not durable recovery proof |
| One bounded attempt | LoopX already has a DSH Turn host with timeout and failure mapping | Existing Pi goal mode includes continuation and pause behavior | Neither native loop may silently become the Desktop scheduler; avoid two outer loops |
| Packaging | Dedicated observer export/bundle and packed smokes exist | Extension discovery is part of SDK resource loading | Verify the actually loaded package/profile, not just source imports; neither boundary is OS isolation |
| Provider profiles | SDK connector/version constraints are explicit | SDK exposes runtime/model construction | Qualify the same route, model, tools and budget; harness choice does not establish provider compatibility |
| Public safety | Producer and Python consumer independently validate; shared counterfactuals exist | Tool/context hooks can expose or change raw content | A Pi observer needs first-append redaction and negative fixtures, not transcript copying |
| Performance | Buffer/count/flush accounting exists; no matched real overhead result established here | Subscription is available; no LoopX observer measurement established here | Reject numeric rankings until identical workloads and revisions are measured |
| Maintenance | DSH upstream explicitly warns of breaking changes; LoopX pins its validated connector surface | Current upstream package/runtime APIs differ from historical integration assumptions | Pin upgrades separately; do not compare an installed DSH against an unqualified latest Pi |
These are integration-cost and contract observations, not claims that Pi lacks events or DSH cannot support other models. Both expose control-capable APIs; passivity is a property of the selected adapter and its loaded dependencies.
The two LoopX surfaces that depend on dsh do not move together. The bounded Turn
host uses the Python SDK/runtime pin recorded above (0.1.5rc1, the released
channel). The dsh-side plugin (packages/dsh-loopx-plugin) now builds its
development, host, and client surfaces on the same released 0.1.5-rc.2 line
instead of the retired 0.1.1-rc.2 one, and its npm peer ranges admit only
>=0.1.5-rc.1. Three upstream moves forced that, so it is a new release line
rather than a patch: the 0.1.5 line no longer publishes
@deepseek-ai/dsh-client-runtime (last released 0.1.1-rc.2), which moves the
slots service seat to @deepseek-ai/dsh-client-ui-renderer — the package this
manifest now names in dsh.client.inject; Session.events became
Session.snapshotEvents() and Inbox.hasPending became the two pending queues;
and the shared /api bridge addresses Remote methods as <namespace>/<method>
with a single args payload field. One dsh.client.inject list cannot order
boot rows for both generations at once, so the plugin cannot claim both. The L1
observer contract above is unchanged: the observer still consumes only
session/created, session/event, and session/disposed, and now treats
token-level assistant/chunk rows as retired input replayed from older durable
logs instead of a live event type.
Data and Authority Flow¶
The operator needs to distinguish missing evidence, unhealthy execution and an invalid observation treatment before deciding what to do:
native session publication
-> isolated observer: compact, validate, count, append
-> independent ledger validation
-> integrity receipt + diagnostic projection
-> operator presentation only
canonical eligibility -> Desktop supervisor -> bounded Turn -> validation/writeback
There is no arrow from diagnostics back to eligibility. valid means the
observation contract passed, not that a task succeeded. A stall signal is not
permission to retry. Observer errors must not become worker failures.
Implemented Readback Increment¶
The existing CLI now supports an explicit combined read:
loopx reliability-diagnostics status --goal-id <goal-id> --with-receipt --format json --as-of "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
The POSIX-shell example evaluates age against the current UTC time. Other
clients must supply a timezone-aware current timestamp. Omit --as-of only
for historical replay: it defaults to the last event time, producing zero
last-event age, not a live liveness check. Display the observation and evaluation
times separately; advancing the evaluation clock does not change integrity.
The receipt and projection derive from the same in-memory ledger reading, avoiding two CLI calls observing different append states. Omitting the flag preserves the original response. This does not make concurrent file append atomic: a partial last line remains an invalid-input signal rather than being silently dropped. The command does not activate an observer, discover a binding, write a ledger, call a model, or change a Goal/Todo/lease.
This is an executable readback seam, not a shipped Mode B panel or supervisor. A future panel must bind exact goal/session/run identity, show observation age and integrity independently of task status, and refuse to label a multi-run or stale goal ledger as the current session's health. It must remain operator-only, with no diagnostic input passed into prompts or scheduler decisions. Existing CLI ledger reads are unbounded; do not put this command on an automatic polling loop before adding an owner-reviewed read budget/snapshot strategy.
Qualification Plan and Stop Conditions¶
- C0 adapter fidelity: compare native execution with the managed adapter, observer disabled. Pin model, route, tool definitions, prompts, environment, budget, package/adapter revisions and initial session state. Account for all retries and interruptions. Reject comparisons with unequal treatments.
- C1 passive arm: enable only the observer on that qualified adapter. Record eligible run identity, persisted/accepted/rejected/drop counts, receipt status, endpoint/worker-context/scheduler influence and all failed runs. Fixture success does not establish this gate; non-valid receipt is not eligible C1 evidence.
- Overhead: measure baseline and observer wall time, process CPU, peak RSS, bytes written, event throughput and flush latency using paired repeated runs. Report sample count, distributions, uncertainty and warm/cold conditions. Declare acceptance thresholds before running; no threshold is invented here.
- Retention/deletion: owner chooses maximum age/bytes, active-writer handling, export/support access, backup scope and delete verification. Dry-run inventory must precede deletion; never truncate an active ledger to meet a size cap.
- Mode B acceptance: separately exercise start/resume/interrupt/close, process crash, stale session identity, duplicate completion, timeout and provider failure in a disposable runtime. Verify one Turn at a time and canonical validation/writeback before spending quota or requesting another.
Keep raw logs and credentials owner-local. Public evidence should contain only generalized methodology, pinned revisions, aggregate results and safe references. No live model execution or retention deletion is authorized by this document.
Milestone ownership stays with Agent Session Execution Modes. This document owns the C0, C1, overhead and retention evidence for the L1 observer arm, and the Mode B acceptance above for a session-owning runtime; the M1-M4 integration milestones and the cross-frontend projection row remain that document's, and nothing here defines mode inference or a second executor.
Delivery Sequence¶
This comparison plus combined CLI readback can be reviewed now. A Mode B panel requires the exact-session read contract and bounded refresh path first; it must not be a second generic monitoring subsystem. Run C0/C1 and overhead experiments as separately budgeted work, then submit only reusable fixes and safe evidence. Implement deletion only after the owner selects the retention profile. Revisit runtime preference if Pi satisfies the same isolation/lifecycle tests at lower measured integration and operational cost, or DSH fails them. Do not introduce L2 advice, retry control or a new scheduler to make an L1 experiment pass.
Steward Channel Chat Transport (2026-09-15)¶
The governed Turn surface and the steward (manager) chat channel need different host shapes, and they now resolve their defaults differently too: a bounded Turn nobody selected still falls back to the host the operator credential resolves, while the steward channel stays on the interactive CLI endpoint until an operator selects the managed host. A Turn is one bounded work segment, which the shipped DSH adapter serves today. The steward channel additionally needs a transport that can hold an interactive session, and the shipped DSH surface explicitly does not promise cross-turn DSH session continuity.
Option A shipped, so this section now records the transport rather than a plan.
The steward channel holds the managed host through
loopx/chat_dsh.py: each Chat turn starts one bounded dsh segment on the
resolved execution profile, hands it the channel's bounded visible history plus
the current message, and returns the final assistant message. The snapshot the
segment sees is composed by LoopX and the segment's sandbox is pinned read-only
through DSH_PERMISSION_MODE, so an answer cannot come from ambient write or
shell authority that the channel never granted.
What the transport deliberately does not claim, because the channel readback could otherwise be read as offering it:
- no streaming — the answer arrives as one final message;
- no cross-turn host session — each segment is fresh, and the visible history is Chat-side context rather than a host session the channel resumed;
- no tool authority — the segment is refused by the dsh sandbox itself when
it reaches for a write, and the channel reports
trust_scope: read_only.
Because the segment cannot read anything for itself, every source it is expected to speak about has to be supplied by LoopX in the same bounded prompt: the declared evidence window and the registered-source read are composed by the Turn owner, cached and budgeted so a wider reach cannot slow every turn. This is a transport consequence, not a new authority: the segment still cannot widen its own scope, and any source it did not receive is a named coverage gap rather than evidence of no progress.
The earlier typed reason managed_host_chat_transport_unsupported is retired
with this change; it described a transport gap that no longer exists, and keeping
it would have made a working host unreachable. The reasons the channel can still
report are the managed host's own launchability facts
(dsh_runtime_unavailable, operator_credential_unconfigured,
invalid_reasoning_effort), and a session request for an unavailable host fails
as a typed host-tool gate instead of silently falling back to an individual CLI
login.
| Option | Shape | Cost and risk |
|---|---|---|
| A. Turn-backed steward transport (shipped) | Each steward chat turn runs one bounded governed segment on the managed host through the same execution profile the governed Turn resolves, with bounded chat history as context | No duplex streaming and no cross-turn host session; each turn is a fresh segment. The tool/sandbox authority is pinned read-only by the channel and the per-turn bound is the channel's own hard timeout |
| B. ACP or stdio adapter | Reuse the ACP stdio adapter path (as the Kiro CLI chat endpoint does) when the managed host exposes such an interface | Lowest transport cost, but depends on an upstream interface that no shipped evidence covers yet |
| C. Codex endpoint bound to the operator provider | Start the Codex app-server itself against the operator provider so the existing transport and tool surface stay | Keeps streaming, but must prove the session no longer authenticates with an individual login; the provider config becomes host-state authority and needs its own gate |
Selection rule: prefer A, because it reuses the Turn authority, typed host failure, journal and quota semantics LoopX already validates; keep B as the cheaper replacement if the upstream interface appears; evaluate C only if duplex streaming is required for the steward experience. Whichever option ships must demonstrate that the governed work a steward drives never reaches an individual subscription, and -- for a steward session the operator put on the managed host -- that the model work lands on the operator credential. The steward's own shipped default is the interactive CLI endpoint, which is billed to one machine's login; that is a disclosed default rather than a hidden one, because the channel reports the endpoint, its source and the shipped decision behind it. This document authorizes no new scheduler, retry authority or second monitoring subsystem to make that demonstration pass.
Option A is the one that shipped, and its demonstration is a repository smoke
rather than a live transcript: examples/loopx-steward-managed-chat-smoke.py
runs the real bundled dsh segment against a local mock model endpoint and asserts
the resolved binding, the model and effort that reach the wire, the persisted
answer, and that the read-only sandbox refuses a write. The persona and audience
of a real steward conversation stay out of this document.
Steward Executor Machine Configuration (2026-09-16)¶
The steward executor used to be selectable only through the Chat service
environment, which made a machine-local decision live in a launch file rather
than in a product setting: no surface could show it, no surface could change it,
and a reader had to know which process variables were in effect. The executor,
the model, and the reasoning effort are now a typed machine-configuration
namespace, steward_executor
(loopx/capabilities/steward_executor/machine_defaults.py), so a machine's
steward choice is a first-class operator setting.
The namespace holds exactly three fields and no credential:
{
"schema_version": "steward_executor_machine_defaults_v0",
"executor_endpoint": "codex",
"executor_model": null,
"executor_reasoning_effort": null
}
executor_endpoint is required and restricted to the endpoints LoopX ships as
channel executors; a blank model or reasoning effort means this machine decides
nothing about that field, so the channel keeps resolving it from the lower
layers. Unknown fields, an unknown schema version, an unlisted endpoint, and an
unsupported reasoning effort all fail closed before any effect. An operator who
needs an adapter the namespace does not list still has
LOOPX_MANAGER_ENDPOINT.
Precedence is stated once, in the channel owner
(loopx/chat_manager.py): machine configuration, then the service environment,
then the shipped default. The machine layer is the one a product surface owns,
so loopx machine-config describe publishes the template and the Dashboard
edits the same document through the existing revision-locked transaction; the
channel readback adds executor_endpoint_source: machine_configuration plus the
document's status and configuration_revision, so a machine decision can be
told from a service-environment value without reading the store.
What this increment does not change: the shipped default stays codex on
every machine, a credential still never selects an endpoint, the managed host
still requires its own credential and runtime, and the selection grants no
authority -- it names a provider-billed runtime, and manager_runtime remains a
separate machine decision. A malformed steward value or an unreadable store
falls back to the lower layers with a typed reason
(configuration_invalid, unavailable) instead of failing the surface a person
talks to, and a malformed sibling namespace cannot rewrite a valid steward
selection.
Validation: tests/capabilities/test_steward_executor_machine_defaults.py,
tests/test_manager_channel_binding.py, tests/test_chat_machine_configuration_api.py,
tests/capabilities/test_capability_configuration_ui.py, and
examples/loopx-steward-channel-binding-smoke.py.
Steward Answer Identity and Runtime Selection (2026-09-16)¶
Once a machine could declare its steward executor, the Dashboard was still
answering two different questions with one value: who answered me and which
runtime served the turn. The transcript titled a steward answer with whatever
the chat-runtime picker happened to hold, and the picker itself preferred a
Codex adapter whenever one was discovered on the machine -- so a channel
resolving to the managed host could still present itself as an individual CLI
login, and the header chip, the composer and the answer could each name a
different executor.
Two rules now hold on the manager channel:
- Answer identity names the speaker. The transcript labels a steward answer
LoopX Manager/LoopX 管家on every path that can produce one -- return receipts, resumed history, recovery streaming, the streaming placeholder, the completion fallback, interruption and failure. The executor and its model stay in the machine-capability chip, which is the surface that reports them. Goal channels keep naming the Goal's own Agent. - Runtime selection resolves the way the channel resolves. The chat-runtime picker follows the channel owner's precedence for the manager context: the declared steward executor first, the shipped default only when the machine declares nothing. A discovered adapter is never presented as the steward.
An explicit operator pick still wins for that context, and the client still
sends no endpoint when the operator made no pick, so the create-session contract
in loopx/chat_server.py -- "each channel resolves its own default through its
own owner" -- is unchanged. An explicit pick is also the only path that moves
this channel off the declared executor, which keeps a discovered CLI from
silently rewriting a machine decision.
Evidence: examples/personal-workspace-browser-smoke.mjs (execution-chip
scenario for the picker and composer resolution, chat-recovery scenario for
the answer identity), plus a live readback on the installed Dashboard where the
header chip resolved dsh while the picker previously reported Codex.
Steward Team Intake (2026-09-16)¶
Audited at 43d362532. Team intake has shipped a bounded preview, owner
confirmation and first-Todo materialization. It has not qualified a running,
budget-enforced or intent-aligned team. The overall roadmap
owns cross-RFC priorities and F1–F7/R1–R7; this selection RFC owns runtime
selection and its qualification evidence, not a separate team architecture.
The shipped boundary is steward_team_plan_preview_v0, kind
steward_team_plan_preview, dispatched through
loopx/control_plane/work_items/governed_transition_proposal.py and Chat
team.plan. It names an exact Goal, 1–8 lanes, registered Agent identities,
first Todo text/priority/class/action, acceptance, quota envelope and stop
condition. Validation produces applies: false. Preview is not execution.
| Boundary | Shipped behavior | Remaining limitation |
|---|---|---|
| Validation/admission (#4519/#4522/#4532/#4533) | Exact Goal, registered Agents, supported advancement kinds and bounded public-safe fields; channel-scoped Goal lookup; unavailable facts drop the proposal while preserving answer text | ready checks registration/action support, not executor health, tool eligibility or budget admission |
| Staffing gaps | Unknown Agent produces agent_not_registered and retains declined_first_todo; explicit capability_not_granted / audience_not_authorized gaps admit no work |
These reason codes do not prove all capability/audience conditions are automatically detected |
| Materialization (#4524/#4528/#4535/#4538) | Revalidates the named Goal; calls canonical Todo owner per ready lane; records proposal digest and bounded lane_todo_ids; existing receipt shape remains readable; no monitor key |
Confirmed priority is dropped; acceptance/quota/stop are not execution constraints on this path; no atomic team commit or automatic partial-recovery proof |
| Confirmation (#4547/#4548/#4552) | Existing frontend displays lanes/gaps and submits team.plan; bundle and browser fixture shipped; the manager conversation now lists the card its own channel stored, so an owner confirms where the sentence was typed while a Goal-scoped fetch stays in that Goal's workspace |
Lark and real worker execution were not qualified by this fixture; the confirmation readback was repaired after this fixture (a confirmed lane keeps its declared priority, a partial application reports its gap count, and a plan that staffs no lane is a typed failure) |
| Freshness | Registry byte changes make the Chat preview stale; optional intent_basis reads alignment source facts before materialization |
No exact Goal-intent/authorization/work precondition at commit; intent_basis is neither the full intent revision nor a CAS fence |
Unchanged-plan retries are covered by focused tests. Do not generalize those tests to concurrent plans, interrupted multi-lane commits or intervening Todo edits. R1 qualifies those cases through the actual action and recovery paths.
Latest integration checkpoint: #4569 (f1166e81e) keeps unsupported action kinds as lane-local gaps, distinguishes declared gaps from host verdicts, preserves admitted gaps on revalidation and projects admitted plans into local owner-channel cards. A blocked lane no longer rejects the whole plan. The Lark manager audience still has no corresponding card. These fixes do not establish plan execution or resolve the baseline F1–F4 commitment/recovery findings.
Subsequent #4572 (0aa6179de) appends a channel-authored confirmation-location pointer to manager answers, naming the Goal workspace. Local and remote manager audiences receive it; Goal channels are not annotated. A remote pointer does not create a Lark card or prove card persistence/team execution; model prose is preserved.
The manager conversation that produced a plan now also lists the card its channel stored, instead of only the Goal workspace the pointer names. This is a presentation change over the same validated proposal: it adds no Lark card, creates nothing before confirmation, and a proposal fetched for a selected Goal stays in that Goal's workspace because it belongs to that context.
Reuse boundary for a Lark card. LoopX already ships the Lark half of a card confirmation: loopx/extensions/lark/goal_channel_operation.py delivers a non-forwardable Card 2.0 with confirm/reject buttons for a typed operation.execute proposal, event_collector_runtime consumes card.action.trigger, and the transport owns operator membership and tenant verification, replay protection, card readback and result-card patching. The reusable part is that shell plus presentation.action_review_plan.compile; the operation-specific parts are the operation envelope identity, the claim/execute effect and the Goal-channel binding the delivery resolves. compileReviewCardFrame now also returns a provider-neutral review_card_frame_v0 for a validated team.plan proposal -- identity is the proposal plus the state fingerprint the apply re-validates, fields are {key, value} pairs whose fixed labels stay keys -- so a plan card can use the same shell and callback consumer. What it still needs is a delivery route for the audience that asked (a manager group is not a Goal channel binding) and a callback effect that applies the proposal through the Chat action service instead of claiming an operation envelope. No plan card is posted yet, and confirming from Lark would also need an explicit answer for whether an external manager audience may perform this durable write.
Relationship to multi-agent and shared authority¶
The alignment RFC owns
shared intent and governed amendments; shared authority
owns persistence/promotion. A team plan proposes work inside accepted intent;
it cannot change permissions, shared acceptance or terminal conditions by
placing prose in its envelope. Stage 3 amendment commit remains unshipped.
The optional receipt intent_basis is the existing source_basis_digest,
not a version of that unimplemented full intent envelope. Historical receipts
must not acquire stronger semantics through a rename.
peer_v1 permits a steward to organize, delegate and synthesize, without
unilateral write, claim, priority or preemption authority. Lanes refer to the
same canonical graph and per-Agent frontier. Creating claimed_by Todos does
not acquire task leases, launch workers or reserve distributed quota.
The peer directory
is shared by manager and peer callers. loopx agent-directory --goal-id <goal>
[--agent-id <caller>] reuses the management projection, caps local rows at 24,
reports omitted rows, has no pagination or presence provider and does not
project lease epochs. A supplied unregistered caller gets a scope gap. Local
CLI membership checks do not authenticate a remote caller; any future remote
entry must derive caller identity from a verified binding.
Per-Agent readback uses loopx shared-goal-alignment --goal-id <goal> --agent-id
<agent>, within its Stage 1/2 source-facts boundary. The plan receipt does not
project that entire state. The three-layer contract
and visible launcher
remain independent owners: user intent, preset procedure and kernel declarations
join by Goal/Agent/Todo identity, not by creating another runner, pane owner,
vision budget or evidence loop. Selecting an executor or storing credentials
grants none of these effects.
Steward Channel Readiness by Milestone (2026-09-16)¶
The steward channel consumes both this document's host selection and the manager milestones in capable-manager-semantic-handoff-v0. This section records which steward-channel behaviours those milestones can rely on today and which stay unverified. It states product contracts, not conversation content: no live channel transcript, audience identity, dated incident or operator-local path is recorded here.
| Milestone | Steward-channel contract in scope | Evidence state on 2026-09-16 |
|---|---|---|
| Manager M1 — useful host agent | The channel resolves and reports its effective executor, model, reasoning effort and source, the executor selection does not follow a credential, and a host that cannot launch fails with a typed reason instead of a silent individual-login fallback | Shipped: selected endpoint with its source and default-rule reason, the executor's execution_profile, executor_kind, and the channel_binding readback (PR #4446 with the Turn-side readback in PR #4443; the unconditional default and the segment transport land with this change). The upstream session identity is still not projected to the channel, so a channel answer cannot yet prove which session served it |
| Manager M2 — semantic continuation | Receiver resolution across registered running lanes; typed per-source coverage and freshness; a goal-level milestone the report can lead with instead of coverage disclaimers | Partially implemented. Typed source failures and one real source read are recorded below; the local peer directory is shipped. Cross-directory receiver resolution, complete semantic requests/return and a synthesizable Goal-level milestone remain open. Source reading does not complete M2 |
| Manager M3 — automatic complete exchange | A persisted answer that exceeds or violates the channel's outbound text contract is split and re-sent under a stable answer identity; an ambiguous or failed send is reconciled instead of replaced by a local notice; the return path survives a transport restart; rich markdown renders as structured text | Partially mitigated. loopx/extensions/lark/outbound.py fails closed on an over-limit or malformed payload, and the channel reports that local failure without re-delivering the persisted answer; one answer carries no idempotency identity, so a retry can duplicate it; structured rendering is not guaranteed |
| Host modes M0-M1 | The channel's executor selection and its bounded one-segment execution | Selection is covered by PR #4446 and the Turn-side selection by PR #4443; bounded one-segment execution is covered by the Mode B acceptance above. The channel itself now reaches the managed host through the segment transport, so the managed host's own one-segment execution is reachable from the channel; what remains open is that the segment is not a session, so cross-turn host continuity is still not offered |
| Host modes M2-M3 | Attached-host parity, typed unavailability, and mode-aware projection with no mode inference and no second executor | Partly shipped: the channel's managed segment transport holds one executor per binding, refuses a second start with the typed managed_host_chat_segment_in_flight, and discards an interrupted segment's answer instead of letting it enter visible history. The channel readback also carries the mode-aware projection: it quotes the Session's own session_mode and status, reads a channel with no Session as unbound, and names a mode outside the closed set as unrecognized instead of deriving a mode from the executor it resolved. Still not implemented: attached-host parity, and an external audience still degrades to restricted |
Remote-source coverage acceptance (2026-09-16)¶
Typed M2 source failures have shipped. The following preserves one historical live-channel read and its acceptance boundary; this roadmap audit did not rerun it:
- a declared remote source that cannot be read reports a typed cause together with the repair that clears it (an authorization that lapsed, a remote client that is missing, a remote protocol that is unavailable, a host that cannot be reached) instead of an untyped unavailability;
- a live manager-channel question that required its declared remote source was
accepted on 2026-09-16 at release
20260916T123949Z(serving revision55ebbc6b7, executordsh, profiledeepseek-v4-flash@high). The answer named the one declared source it read and kept that read's freshness visible, stated its evidence window and the bounds it applied, listed the remote rows it included, and said that hosts it did not read are outside coverage instead of presenting them as having made no progress.
That is the typed per-source coverage and freshness property the M2 row asked for. The other two halves of M2 - receiver resolution across registered running lanes, and a goal-level milestone the report can lead with - stay open. The acceptance is a live channel read: it needs a running channel, a real credential and a declared source, so it is a recorded procedure rather than a CI job, and the failure half needs an unreadable source to exercise.
Two boundaries stay fixed across all five rows. The channel remains an entry point and projection of one manager Session: it owns no profile, no permission state, no second executor and no work authority, so a richer answer contract must not widen what the channel may read or change. And no row is promoted by this document; the M1-M4 integration milestones and the cross-frontend projection row still belong to Agent Session Execution Modes.