Plan: Remote Session CapSet Client
Overview
Push the remote host application / CapSet interop track forward without
turning it into a kernel-core change. The first trusted local CLI/web bridge
already proves login, session summary, CapSet inspection, implemented calls,
denials, logout, stale-call proof, redacted transcript export, browser
automation, DTO service catalog, service-runner profiles, Adventure launch,
worker-backed chat, and worker-backed Adventure status/look/
inventory/bounded go. This plan picks up the remaining direction listed
in WORKPLAN.md’s ad-hoc note: standard capnp-rpc transport/object proxy
layer, complete transport lifetime and exception behavior, more auth adapters
including guest admission, stronger resource/revocation bounds, richer
service clients, and Paperclips launch.
Long-form decomposition lives in
docs/backlog/remote-session-capset-client.md and
docs/backlog/shared-service-demos.md. The session-bound invocation context
boundary is recorded in
docs/backlog/session-bound-invocation-context.md.
Browser JavaScript must continue to receive only view models, results, and
denials. The Rust backend keeps the remote session and capOS caps. Do not
expose terminal delegation, shell-runner policy, raw ProcessSpawner/process
handles, endpoint owner handles, local cap ids, result-cap slots,
browser-held capOS caps, or capOS-driven UI-composition capabilities through
this path.
Conflict Surface
Owned by this plan:
tools/remote-session-client/(Rust backend, browser bridge assets, Tauri preflight, scripted CLI harness)- capOS-side gateway and worker crates that back the remote-session
smokes:
demos/remote-session-capset-gateway/,demos/remote-session-chat-worker/,demos/remote-session-adventure-worker/. The Adventure worker boundary is shared with the Aurelian plan – coordinate before changing the worker’s Adventure call shape. system-remote-session-capset-interop.cue,system-remote-session-adventure-interop.cue, and any newsystem-remote-session-*.cuemanifest the new transport requires- Remote-session DTO additions in
schema/capos.capnp(shared serial surface – seedocs/plans/README.mdConcurrency Notes; only one plan at a time may changeschema/capos.capnp, andmake generated-code-checkmust pass before the next plan picks it up) docs/proposals/remote-session-capset-client-proposal.md,docs/backlog/remote-session-capset-client.mdMakefiletargetsremote-session-ui,remote-session-tauri,run-remote-session-capset-ui,run-remote-session-capset-interop,run-remote-session-adventure-interop
Direction the host UI must preserve while this plan runs (forward from
WORKPLAN.md so the constraint travels with the executable surface):
- Login is a dedicated OS-like screen with a visible username field and no full persistent technical header.
- Browser login sends username/password only, defaulting the username
from
CAPOS_REMOTE_SESSION_USERor the hostUSERso it matches the operator account injected bymake run. Resource profile names such asoperatorare not user-typed system details. - For the current legacy DTO protocol, the trusted Rust backend maps an omitted password profile to the default operator profile before calling the gateway. Gateway-side profile policy/picker support (post-auth picker for manifests with multiple user-meaningful profiles) remains future work; do not move that responsibility into the browser or the legacy DTO surface.
- Authenticated users land in a compact Services-first workspace where Session, CapSet, Diagnostics, and Transcript are separate views. The UI smoke must continue to fail if any visible button is not exercised.
Do not touch from this plan:
- Kernel-side session-lifecycle changes that are not strictly required to
unblock a remote-session DTO change. Production lifecycle changes belong
with the session lifecycle work tracked in
WORKPLAN.md’s ad-hoc note andREVIEW_FINDINGS.md. Coordinate with the user before extendingkernel/src/cap/session_manager.rsorkernel/src/cap/user_session.rs. kernel/src/pci.rs,kernel/src/device_*.rs, IOMMU code (owned by device-driver-foundation plan)demos/paperclips-*,demos/adventure-*(owned by demo plans). Add remote-session DTO entries that consume those servers’ existing surface; do not modify the servers themselves from this plan.
Validation Commands
make fmt-checkmake generated-code-checkcargo build --features qemucargo test-configcargo test-libcargo check --manifest-path tools/remote-session-client/Cargo.toml --target x86_64-unknown-linux-gnucargo test --manifest-path tools/remote-session-client/Cargo.toml --target x86_64-unknown-linux-gnucargo build-demos-caposmake run-remote-session-capset-interopmake run-remote-session-adventure-interop(required when the iteration changesdemos/remote-session-adventure-worker/,system-remote-session-adventure-interop.cue, or any Adventure remote call shape; the capset interop target alone covers Adventure denial, not the positive Adventure path)make run-remote-session-capset-ui
Success Criteria
Each landed iteration must keep both
run-remote-session-capset-interop and
run-remote-session-capset-ui green, ship one or more of the directions
listed below, and refresh WORKPLAN.md’s remote-session ad-hoc bullet to
record what is now landed and what is still planned.
Task 1: Standard capnp-rpc transport and object proxy layer
- Replace the schema-framed bespoke transport with the standard
capnp-rpcproxy layer for at least one service surface (chat or Adventure). Keep the kernel-side service the same; the change is in the host backend and DTO bindings. - Prove the new transport with
run-remote-session-capset-interopand a host-side test intools/remote-session-client/. Record the transition indocs/proposals/remote-session-capset-client-proposal.md. - Document any temporary dual-stack period in
docs/backlog/remote-session-capset-client.mdso a follow-up plan iteration removes the bespoke path.
Task 2: Transport lifetime and exception behavior
- Cover gateway disconnect, half-open transport, and exception paths end-to-end. Each path must produce a redacted denial in the transcript and clean state in the backend.
- Add focused interop assertions for connection-close logout, gateway
logout propagation, and post-logout call rejection. Keep
session-lifecycle kernel changes out of scope; reuse the existing
live/logged_outcells. - Record the resulting contract in
docs/proposals/remote-session-capset-client-proposal.mdso the future capnp-rpc rewrite preserves it.
Task 3: Auth adapter expansion (guest admission included)
- Add at least one new auth adapter beyond password login, e.g. guest admission with explicit profile mismatch denial, or a stub passkey adapter that exercises the broker without requiring durable storage.
- Cover the new adapter with the existing CLI/QEMU denial proofs (inactive accounts, unknown principals, missing or retired resource profiles, profile mismatch) and the redacted-transcript export.
- Update the broker DTO surface, not the kernel session_manager. If
the broker exposes new metadata, gate it behind explicit subject
disclosure as required by
docs/backlog/session-bound-invocation-context.md.
Task 4: Resource and revocation bounds
- Add explicit per-session bounds on outstanding worker calls, transcript size, gateway connections per principal, and backend-side cap holders. Surface bound exhaustion as a denial, never as a panic.
- Add focused interop assertions exercising each bound at boundary and over-boundary.
- Note bound choices in
docs/proposals/remote-session-capset-client-proposal.mdanddocs/backlog/remote-session-capset-client.mdso future operators can tune them safely.
Task 5: Richer service clients
- Add at least one richer service client beyond chat/Adventure. Good
candidates: a SystemInfo/MOTD/help/manpage view, a session summary
diff, or a service-catalog filter. Landed as the session-summary
diff helper in
tools/remote-session-client/src/session_diff.rs. - Keep browser JavaScript on view models only; richer clients live in
the Rust backend. The trusted Rust web bridge holds the raw
(SessionInfoSummary, Vec<CapInfo>)snapshots; browser JavaScript receives only the redactedSessionSummaryDiffVmshape (added / removed cap entries by(name, interfaceIdHex), policy/lease changes, redacted session-id changes, and a summary string). - Add a corresponding focused proof in
run-remote-session-capset-uiand document the new client indocs/proposals/remote-session-capset-client-proposal.md. The browser smoke now clicks the new “Refresh & Show Diff” button twice per session: the first click reportshasBaseline=falsewhile the second click reports a populated diff payload withhasBaseline=true. Two backend host tests cover the baseline + no-change path and the added-cap + expiry-change path.
Task 6: Paperclips launch slice
- Coordinate with the Paperclips Showcase plan’s Task 4 DTO surface. When that surface is reviewed, wire the remote-session worker and browser bridge to launch and drive Paperclips through the same DTO/service-runner profile path that already drives Adventure.
- Prove the launch slice with
run-remote-session-capset-ui, including a redacted transcript and visible-button automation, and keep raw browser-held capOS caps off the path. - Record the milestone in
WORKPLAN.mdanddocs/changelog.md.