Remote Session CapSet Client Backlog
Detailed decomposition for the remote host app path described in
Remote Session CapSet Clients.
WORKPLAN.md should point here when selecting implementation slices; it should
not inline the details.
Visible Outcome
make run-remote-session-capset-interop boots capOS in QEMU, starts a
loopback-scoped remote session gateway, runs a regular host-side Rust client
on the host, authenticates or exercises an explicitly configured
guest/anonymous denial path, obtains a RemoteSession, lists a broker-issued
RemoteCapSet, gets typed capabilities by name/interface ID, calls at least
two granted capabilities, proves missing/wrong-interface denials, logs out or
disconnects, and observes stale proxy calls fail closed.
The first harness can be a small CLI because it is easy to script. The product shape should also support a native desktop GUI, a Tauri app whose Rust backend holds the remote CapSet, or a webapp whose trusted server/gateway holds the remote CapSet and exposes only UI frames, command descriptors, or bounded tool requests to browser JavaScript. The UI path can be bidirectional: the host UI may grant a narrow UI-surface capability back to capOS-side services or agents so they can propose task-specific panes, command palettes, visualizations, theme hints, and layout changes without receiving arbitrary host UI authority.
The first visible proof keeps QEMU host forwarding and a development
transport. The current implementation uses length-prefixed schema-framed
Cap’n Proto DTOs for remote login, session summary, CapSet list/get, calls,
denials, and logout. Standard capnp-rpc framing and live object proxies
remain the next transport gate.
Implementation Status
Implemented first slice:
make runstarts the remote-session CapSet gateway in the default manifest and forwards guest port2327to a host-local loopback port. The helper prefers127.0.0.1:2327but selects a free fallback when another QEMU run or developer process already occupies the port, unless the port is explicitly configured.make run-remote-session-capset-interopboots a focused manifest, runs a Linux Rust host client, authenticates as the configured operator by default, lists the broker-shaped remote CapSet, callssession,system_info, and proves wrong-interface/unknown/stale denials, and records a redacted transcript. Endpoint-backed service calls such aschatare intentionally withheld until the next worker-backed proxy slice can run them under the authenticated remote session context.RemoteAuthMethodadvertises password and anonymous as enabled methods plus disabled public-key, OIDC, and passkey/WebAuthn entries so the protocol and client are not password-shaped.- The capOS gateway uses manifest-scoped
TcpListenAuthorityon guest port2327, plusSessionManagerandAuthorityBroker. It does not receive rawNetworkManager,TcpListener, orTcpSocketauthority, and the manifest does not grant service endpoint caps directly to the gateway. This first slice still asks the broker for the operator shell bundle, which mints service endpoints that the gateway immediately drops instead of exposing remotely; a narrower broker bundle is tracked below. Login source metadata is derived by the gateway from the accepted socket and a gateway-generated connection event id rather than from client-supplied fields. - The host Rust client crate is UI-neutral and can back a CLI, native GUI, Tauri backend, or trusted web gateway. No browser/GUI test is present yet because no GUI surface has been implemented.
Remaining major gaps:
- Replace the DTO transport with standard
capnp-rpcframing and live typed remote proxy objects. - Expand auth adapters beyond password and anonymous.
- Move endpoint proxying, logout/close propagation, and remote reference
release from gateway-local DTO state to per-session worker teardown and
UserSession.logout. - Add resource limits, TLS/mTLS, renewal, revocation, and UI-composition surfaces.
Design Constraints
- Do not serialize local capOS cap IDs, cap-table slots, endpoint receiver selectors, endpoint generations, result-cap indexes, server cookies, or global session identifiers as portable authority.
- Do not treat password auth as the only remote path. The schema and docs must leave room for public key, OIDC, passkey/WebAuthn, mTLS, guest/anonymous, and service/workload admission.
- Keep the session-bound invocation invariant. Remote post-auth calls run under the remote session’s capOS worker context or an equivalent reviewed context.
- Keep default remote bundles narrower than operator shell bundles.
- Keep browser JavaScript and model providers away from raw capOS caps. Browser and agent paths use gateway-side tool/cap proxies.
- Keep UI composition declarative and bounded. A capOS service may propose layout/theme/view updates only through an explicit UI capability; it cannot inject arbitrary JavaScript/CSS, spoof trusted chrome, or persist UI state without a settings/profile cap.
- Keep listener and transport authority scoped; no raw
NetworkManageror broadProcessSpawnerin the long-term gateway. - Preserve the error split: transport/CQE errors, capability infrastructure exceptions, and domain result unions remain distinct.
Related Proposal Updates
The planning update that introduced this backlog aligned these documents:
remote-session-capset-client-proposal.md: owning design.shell-proposal.md: remote clients are peer clients of broker-issued bundles, not shell transports.boot-to-shell-proposal.md: web/remote login feeds the same session manager and broker, and must support non-password admission.ssh-shell-proposal.md: SSH remains a terminal transport, while public-key auth records can also feed non-shell remote clients through a domain-separated protocol.user-identity-and-policy-proposal.md: broker bundles need a remote-client profile shape in addition to shell bundles.browser-capability-proposal.md,llm-and-agent-proposal.md, andinteractive-command-surface-proposal.md: UI composition, browser/agent front ends, and typed command surfaces remain capability-mediated rather than raw browser or shell authority.roadmap.mdandWORKPLAN.md: the old chat-only interop item is reframed as remote session CapSet interop without changing the selected threading milestone.
Grounding Files
Relevant design and research grounding:
docs/proposals/session-bound-invocation-context-proposal.mddocs/proposals/user-identity-and-policy-proposal.mddocs/proposals/boot-to-shell-proposal.mddocs/proposals/shell-proposal.mddocs/proposals/ssh-shell-proposal.mddocs/proposals/certificates-and-tls-proposal.mddocs/proposals/oidc-and-oauth2-proposal.mddocs/proposals/libcapos-service-proposal.mddocs/proposals/interactive-command-surface-proposal.mddocs/proposals/browser-capability-proposal.mddocs/proposals/llm-and-agent-proposal.mddocs/research/cloudflare-capnproto-workers.mddocs/research/spritely-captp-ocapn.md
Ordered Gates
Gate 0: Rename The Target
- Rename the planning target from chat interop to remote session CapSet interop while preserving the existing chat proof as a historical transport slice.
- Add docs that say the remote client is a regular host app and does not
use
capos-rt, the capOS ring page, or the local CapSet page. - Keep the existing
make run-capnp-chat-interoptarget until a successor proof exists; do not remove useful evidence.
Gate 1: Host Rust Cap’n Proto RPC Client
- Add a host-built Rust client crate or tool using generated schema
bindings. The first slice uses length-prefixed schema-framed Cap’n Proto
DTOs; standard
capnp-rpcremains open. - Keep the client library UI-neutral so it can back a CLI harness, a native GUI, or a Tauri backend without changing the capOS protocol.
- Connect through QEMU host forwarding to the capOS gateway.
- Verify schema version/interface ID mismatches fail with explicit diagnostics.
- Add a host-side transcript that records successful connect, bootstrap, session info, CapSet list, calls, denials, and logout.
Gate 2: Gateway Bootstrap And Auth Method Inventory
- Add
RemoteSessionGateway.authMethodsand a policy-shaped method list. - Support explicit denial for disabled methods so the harness can prove password-only assumptions are not baked into the protocol.
- Record gateway-derived source metadata, method kind, requested profile, and protocol binding in audit-shaped output.
- Keep first-remote-client setup disabled unless a manifest explicitly grants a local setup authority path.
Gate 3: First Auth Adapter
- Choose one bounded first adapter for the proof. Acceptable first choices
are public-key fixture auth, password via existing
SessionManager.loginunder explicit policy, or guest/anonymous admission under a narrow profile. Do not design the schema as password-only. - Map the accepted proof into
SessionManagerand mint a realUserSession. - Prove failed proof, disabled account/profile, wrong requested profile, and unknown principal fail before the broker returns a CapSet.
Gate 4: Broker Remote Bundle
- Add an
AuthorityBrokerpath for remote-client bundles, or a temporary clearly named wrapper around the existing shell bundle that does not imply terminal authority. - Bundle at least
sessionandsystemInfo; add one demo service cap such aschatorpaperclipsfor behavior proof. - Ensure anonymous/guest/default remote bundles do not receive operator shell launcher or broad service endpoints unless policy explicitly grants them.
- Add wrong-name and wrong-interface tests for
RemoteCapSet.get.
Gate 5: Per-Session Worker And Proxy Lifetime
- Host post-auth remote caps in a per-session worker or equivalent reviewed dispatch context.
- Associate all proxied calls with the live remote session context.
- Drop/release local holds when remote references are dropped, the connection closes, logout is called, or the worker exits.
- Prove stale proxy calls after logout/disconnect fail closed.
Gate 6: Capability Calls Beyond Chat
- Call at least two granted capabilities through generated host bindings.
Suggested first pair:
UserSession.infoorSystemInfo.motd, plusChat.sendorPaperclipsGame.status. - Prove a service-specific domain denial remains a schema result rather than a transport failure.
- Prove target service sees session-bound caller metadata rather than a caller-selected identity field.
Gate 7: Transport Security And Non-Password Auth Expansion
- Add TLS server config once certificate/TLS primitives exist.
- Add mTLS client identity admission when certificate policy and account bindings exist.
- Add public-key auth with protocol-domain-separated challenge bytes.
- Add OIDC device-code and browser-assisted PKCE flows when OAuth/OIDC token capabilities exist.
- Add passkey/WebAuthn through the web gateway path when authenticator primitives exist.
- Add service/workload credential admission for non-human automation.
Gate 8: Renewal, Revocation, And Resource Bounds
- Wire
UserSession.logoutand gateway/connection close propagation. - Add renewal only through a narrow session-manager/broker path that does not revive stale ordinary grants by accident.
- Add resource limits for connections, remote refs, in-flight calls, queued promises, result sizes, and per-session CPU/memory/network accounting.
- Add explicit
CapException/RPC exception tests for transport breakage, worker failure, revoked leases, stale sessions, and oversized messages.
Gate 9: Bidirectional UI Composition
- Add a proposal-level
RemoteUiHost/RemoteUiSurfaceschema slice or equivalent typed DTOs for declarative UI patches and typed user events. - Keep the first UI proof behind a separate granted UI-surface cap, not
implicit in
RemoteSessionorRemoteCapSet. - Prove a capOS service can open/update one bounded surface and receive one typed user event from the host UI.
- Prove the same service cannot spoof login/permission chrome, inject raw JavaScript/CSS, persist layout or theme state, or exceed update/size quotas without explicit authority.
- Add a host-app reset/close path that releases the UI surface and leaves underlying service caps intact.
Verification Targets
Initial documentation/planning check:
make docs
git diff --check
First implementation check:
cargo test --manifest-path tools/remote-session-client/Cargo.toml --target x86_64-unknown-linux-gnu
make run-remote-session-capset-interop
make run-capnp-chat-interop
Security review checklist:
- Remote client cannot obtain authority by guessing a cap name.
- Remote client cannot replay a session or grant identifier on another connection.
- Remote client cannot ask for a local cap slot, endpoint selector, or receiver metadata.
- Logout/close/revocation tears down all session-bound proxies.
- Guest/anonymous profiles receive only explicitly policy-granted caps.
- Browser/agent paths never receive raw capOS capability objects client-side.
- GUI/Tauri/web front ends keep capOS caps in the Rust/backend/gateway side of the trust boundary; UI code receives typed view models, command descriptors, or tool requests.
- UI composition is capability-gated, declarative, quota-bound, and reversible by the user.