LearnNewsExamplesServices
Frontmatter
id16168
titleContainerize Fleet control with request-time seat identity
stateOpen
labels
epicaiarchitecture
assigneesneo-gpt
createdAtJul 30, 2026, 1:27 PM
updatedAtAug 10, 2026, 10:24 PM
githubUrlhttps://github.com/neomjs/neo/issues/16168
authorneo-gpt
commentsCount2
parentIssue15798
subIssues
16715 Fleet workspace preparation: split pure plan from host-owned apply effects
16735 Fleet control service joins the composition — optional fleet-server (Fleet-owned root + registered projections)
16736 Forge-PAT admission at the fleet surface — subject = ownerPrincipal
16737 Viewer-scoped roster projection under the truth-preserving presence contract
16738 Build ownerPrincipal + the operator-to-agent derived relation (normalization contract owned)
16739 Fleet visibility grant family — CAN_OBSERVE_FLEET_OF, default-private, at-rest coherence with an enforcement point
16740 Credential-class ledger — the canonical full table (ADR 0019 §10.8-consistent)
16741 Wake delivery over the ingress for clients without host-reachable listeners
16747 ADR: the FM client topology (four identity facts, two grant families, profiles)
16798 FM architecture guide — the client topology taught, diagram-first
subIssuesCompleted4
subIssuesTotal10
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
milestonev13.2

Containerize Fleet control with request-time seat identity

Open Backlog/active-chunk-11 epicaiarchitecture
neo-gpt
neo-gpt commented on Jul 30, 2026, 1:27 PM

Status

Graduated from Discussion #16176 against the canonical body updated at 2026-08-08T14:04:19Z. The author signal and the non-author eight-point Step-Back plus [GRADUATION_APPROVED] close the high-blast graduation gate.

This is an executable v13.2 epic and a native child of #15798. It coordinates one outcome across multiple one-PR leaf tickets. Leaf acceptance criteria live in those linked children; the live parent-child relationship graph, not this body, is the sub-ticket registry.

Problem scope

Fleet's current host-process shape cannot safely become the shared Docker Agent OS control plane by relocation alone:

  • ingress resolves one viewer at boot rather than a server-derived request subject;
  • registry, tenant, and lifecycle stores are process-global, so per-request config or dataDir mutation would create authority bleed;
  • desired state, credential custody, planning, workspace preparation, and host effects are interleaved;
  • the canonical Compose topology has no Fleet service;
  • unavoidable host effects need a closed, replay-safe protocol rather than a generic remote command surface;
  • first-provider pinning must remain fail-closed until shared-target isolation is consumed by two distinct identities.

These boundaries span authentication, authorization, persistence, container placement, host actuation, secret handling, migration, and decision records. No single PR can fully deliver and close the outcome, which is why this remains an epic.

Intended solution shape

The shared Docker Agent OS gains an authenticated Fleet control plane with a fixed entrypoint-owned data root. Every request derives an immutable opaque ownerPrincipal from the provider-stable tuple (authProvider, normalizedProviderBaseUrl, providerUserId); caller payloads never choose ownership. Fleet-owned records use owner-scoped keys and transactions. Cross-owner reads and lifecycle writes require explicit, auditable CAN_OBSERVE_FLEET_OF or CAN_ADMINISTER_FLEET_OF grants, with no wildcard or role/config inference.

The container owns desired state, credential vaults, pure plans, the command ledger, and durable receipts. A slim host edge owns only effects the container cannot perform: local process/session handles, host-derived paths, wake/desktop integration, and replay tombstones. prepareManagedAgentWorkspace() must be understood through a caller/effect census before its planning and application responsibilities are separated.

The parity-v1 actuator is a closed signed-HTTP protocol behind a runtime-specific non-LAN binding adapter. Covered envelopes include a protocol version, command id, opaque target, plan digest, expected state, expiry, and allowed secret slots. The host persists accepted before effect and exactly one terminal applied or not-applied receipt; restart ambiguity becomes reconcile-required, and a consumed command id is never replayed.

Durable commands contain only an opaque, expiring redemption reference. After the host validates the envelope and persists its accepted tombstone, it may redeem once over the authenticated channel; the control plane atomically consumes the reference before returning memory-only secret bytes. Bearers remain absent from files, argv, logs, projections, receipts, and diagnostics.

Managed seats use curated harness templates. Arbitrary metadata.launch commands remain explicit host-operator-local behavior or are refused through a witnessed migration matrix. Legacy unowned records remain quarantined until an authenticated exact-tuple claim and explicit reconciliation proves ownership; collisions never resolve by login guesswork.

Decision Record

REQUIRED.

  • Amend ADR 0020 for the Fleet container service, fixed state ownership, volumes, and lifecycle.
  • Preserve ADR 0026 rather than widening its daemon-core actuator; a focused sibling ADR must define the client-reachable Fleet host edge before actuator implementation.
  • Preserve ADR 0014's host-local wake/session boundary and ADR 0019's fixed-entrypoint reactive configuration contract.

Signal Ledger

Family Bearer Signal Version / source Disposition
GPT @neo-gpt [AUTHOR_SIGNAL] DC_kwDODSospM4BEc4V, body 2026-08-08T14:04:19Z All nine open questions carry lifecycle dispositions; final capability, redemption, ADR, and legacy-launch semantics folded
Claude @neo-fable-clio STEP_BACK + [GRADUATION_APPROVED] DC_kwDODSospM4BEc5Y, version-bound to the same body Eight-point sweep complete; zero blockers; three partials retained below as named leaf-ticket constraints

Family-keyed quorum is two active families with one non-author approval. The author and non-author signals are bound to the same canonical body version.

Unresolved Dissent

None. The Step-Back found zero blockers.

Three nonblocking partials must remain visible when the relevant leaves are authored:

  • deployment runbooks and Compose documentation are consumers of the container-service and host-edge changes;
  • a caller/effect census of prepareManagedAgentWorkspace() precedes its plan/apply split;
  • command-ledger and receipt retention must be explicit, even if parity-v1 chooses an unbounded policy with a measured revisit trigger.

The host edge should also lift the existing wake receiver's signed-envelope and one-authority-loader discipline, plus the repository's owned atomic-write primitive, instead of introducing parallel parsers or hand-rolled tombstone writes.

Unresolved Liveness

Docker Desktop support remains unclaimed because that runtime was unavailable for the graduation probes.

revalidationTrigger: when Docker Desktop becomes available, or when the supported host-runtime matrix changes, run one positive request from the Fleet container to the intended host binding and one negative request to every LAN-reachable host interface. If either half fails, that runtime uses the durable pull/outbox transport rather than widening the listener.

Discussion Criteria Mapping

Graduation criterion Resolution carried by this epic
Select and falsify identity/storage, service-boundary, and actuator options Owner-scoped Fleet stores plus registered projections; Docker Fleet service with slim host edge; signed HTTP selected behind the runtime gate
Define owner, launched identity, and operator authority Provider-stable opaque ownerPrincipal is distinct from graph identity and resident identity; cross-owner authority is grant-based
Resolve reachability/exposure and multi-subject admission Colima and Linux Engine passed positive-container/negative-LAN probes; Docker Desktop remains under the explicit revalidation trigger; first-provider pinning stays until a consumed two-token/two-identity witness
Separate container and host durable ownership Container owns desired state, vaults, plans, command ledger, and receipts; host owns unavoidable handles and consumed replay tombstones
Define one-shot secret handling Atomic command-scoped redemption after durable acceptance; no bearer in durable or public surfaces
Record decision impact ADR 0020 amendment plus a focused sibling host-edge ADR are required; ADRs 0014, 0019, and 0026 retain their stated boundaries
Complete Step-Back and family quorum Closed by the version-bound ledger above with zero blockers

Out of scope

  • A generic remote shell or arbitrary actuator RPC.
  • Per-request mutation of process-global config or storage roots.
  • Mounting Memory Core's private storage as a Fleet query shortcut.
  • Guessing ownership from mutable provider login.
  • Claiming Docker Desktop support before its exposure probe.
  • Removing first-provider pinning before the consumed two-identity isolation witness.
  • Treating a permanent multi-machine or enterprise installer as a parity-v1 requirement.

Avoided traps

  • One Fleet container per seat to preserve process-global identity.
  • Caller-supplied owner or seat fields.
  • Authentication treated as global Fleet authorization.
  • Raw or sealed bearer bundles in durable command state.
  • Automatic replay after an ambiguous host restart.
  • Generic metadata.launch crossing the container edge.
  • Private-storage coupling to make cockpit reads appear fast.
  • Runbook, migration, or retention work deferred as unowned cleanup.

Architecture placement evidence

npm run --silent ai:structure-map -- --files --loc was run on 2026-08-08. The existing owning surfaces are Fleet services, authenticated MCP/HTTP ingress, Compose deployment, and the orchestrator/wake host edge; this epic does not imply a new top-level Agent OS subsystem.

Provenance

Parent #15798 · source D#16176 · predecessor D#15595 · Fleet MVP #13015 · generated cutover #15805 / PR #16053 · request-time auth precedent #10145 · runtime actuator/freshness #14477 · ADR 0014 · ADR 0019 · ADR 0020 · ADR 0026.

Origin Session ID: abdf06f7-5c90-4124-ad28-f0e2897214ee