# Remote Session CapSet Client Backlog

Detailed decomposition for the remote host app path described in
[Remote Session CapSet Clients](../proposals/remote-session-capset-client-proposal.md).
`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 run` starts the remote-session CapSet gateway in the default manifest
  and forwards guest port `2327` to a host-local loopback port. The helper
  prefers `127.0.0.1:2327` but 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-interop` boots a focused manifest, runs a
  Linux Rust host client, authenticates as the configured operator by default,
  lists the broker-shaped remote CapSet, calls `session`, `system_info`, and
  proves wrong-interface/unknown/stale denials, and records a redacted
  transcript. Endpoint-backed service calls such as `chat` are intentionally
  withheld until the next worker-backed proxy slice can run them under the
  authenticated remote session context.
- `RemoteAuthMethod` advertises 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 `TcpListenAuthority` on guest port
  `2327`, plus `SessionManager` and `AuthorityBroker`. It does not receive raw
  `NetworkManager`, `TcpListener`, or `TcpSocket` authority, 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:

- Add a first host UI client that reuses the existing Rust client and DTO
  gateway without waiting for WebShellGateway. This may be a Tauri app, or a
  local trusted web bridge plus browser UI, as long as capOS caps stay in the
  Rust/backend side and the frontend receives only view models, command
  descriptors, transcripts, and user-intent events.
- Replace the DTO transport with standard `capnp-rpc` framing 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 the first CapSet UI distinct from WebShell. It can inspect and call
  currently implemented remote session capabilities without launching a shell,
  terminal emulator, shell-runner policy engine, or model agent.
- 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 `NetworkManager` or
  broad `ProcessSpawner` in 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`, and
  `interactive-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.md` and `WORKPLAN.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.md`
- `docs/proposals/user-identity-and-policy-proposal.md`
- `docs/proposals/boot-to-shell-proposal.md`
- `docs/proposals/shell-proposal.md`
- `docs/proposals/ssh-shell-proposal.md`
- `docs/proposals/certificates-and-tls-proposal.md`
- `docs/proposals/oidc-and-oauth2-proposal.md`
- `docs/proposals/libcapos-service-proposal.md`
- `docs/proposals/interactive-command-surface-proposal.md`
- `docs/proposals/browser-capability-proposal.md`
- `docs/proposals/llm-and-agent-proposal.md`
- `docs/research/cloudflare-capnproto-workers.md`
- `docs/research/spritely-captp-ocapn.md`

## Ordered Gates

### Gate 0: Rename The Target

- [x] Rename the planning target from chat interop to remote session CapSet
      interop while preserving the existing chat proof as a historical
      transport slice.
- [x] 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.
- [x] Keep the existing `make run-capnp-chat-interop` target until a successor
      proof exists; do not remove useful evidence.

### Gate 1: Host Rust Cap'n Proto RPC Client

- [x] 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-rpc` remains open.
- [x] 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.
- [x] Connect through QEMU host forwarding to the capOS gateway.
- [x] Verify schema version/interface ID mismatches fail with explicit
      diagnostics.
- [x] Add a host-side transcript that records successful connect, bootstrap,
      session info, CapSet list, calls, denials, and logout.

### Gate 1A: First Host UI Client

- [ ] Build a thin Tauri or trusted-local-web UI over
      `tools/remote-session-client`, without changing the capOS gateway
      protocol. Prefer Tauri when the goal is a distributable desktop app whose
      Rust backend can hold the remote session; prefer a local web bridge when
      browser iteration speed matters more than app packaging.
- [ ] Keep capOS authority in the backend. Browser/webview JavaScript receives
      session summaries, auth-method descriptors, CapSet entries, capability
      call forms, transcript rows, and denial diagnostics, but no replayable
      capOS handles.
- [ ] Implement the first UI views for endpoint configuration, auth-method
      inventory, password/anonymous login, session summary, CapSet list/get,
      `sessionInfo`, `systemMotd`, denied-chat probe, logout, stale-call
      proof, and redacted transcript export.
- [ ] Add browser/UI automation for the chosen client: start a gateway-only
      QEMU fixture, such as `run-remote-session-capset-interop-vm` with
      explicit hostfwd/pid/log handling or a new focused UI fixture target,
      then drive login, CapSet inspection, capability calls, denials, logout,
      and transcript redaction, and capture screenshots or traces for review.
      Do not drive the UI against `make run-remote-session-capset-interop`
      because that wrapper starts the scripted CLI client and shuts QEMU down.
- [ ] Keep WebShell-specific work out of this gate. No terminal emulator,
      shell process delegation, shell-runner policy, agent tool execution, or
      UI-composition cap is required for the first CapSet UI.

### Gate 2: Gateway Bootstrap And Auth Method Inventory

- [x] Add `RemoteSessionGateway.authMethods` and a policy-shaped method list.
- [x] Support explicit denial for disabled methods so the harness can prove
      password-only assumptions are not baked into the protocol.
- [x] 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

- [x] Choose one bounded first adapter for the proof. Acceptable first choices
      are public-key fixture auth, password via existing `SessionManager.login`
      under explicit policy, or guest/anonymous admission under a narrow
      profile. Do not design the schema as password-only.
- [x] Map the accepted proof into `SessionManager` and mint a real
      `UserSession`.
- [ ] Prove failed proof, disabled account/profile, wrong requested profile,
      and unknown principal fail before the broker returns a CapSet.

### Gate 4: Broker Remote Bundle

- [x] Add an `AuthorityBroker` path for remote-client bundles, or a temporary
      clearly named wrapper around the existing shell bundle that does not
      imply terminal authority.
- [ ] Bundle at least `session` and `systemInfo`; add one demo service cap
      such as `chat` or `paperclips` for behavior proof.
- [x] Ensure anonymous/guest/default remote bundles do not receive operator
      shell launcher or broad service endpoints unless policy explicitly
      grants them.
- [x] 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.
- [x] Prove stale proxy calls after logout/disconnect fail closed.

### Gate 6: Capability Calls Beyond Chat

- [x] Call at least two granted capabilities through generated host bindings.
      Suggested first pair: `UserSession.info` or `SystemInfo.motd`, plus
      `Chat.send` or `PaperclipsGame.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.logout` and 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

- [ ] Keep this separate from Gate 1A. Gate 1A is a host-rendered UI over the
      existing client; Gate 9 lets capOS-side services propose bounded UI
      surfaces back to that host UI through explicit capabilities.
- [ ] Add a proposal-level `RemoteUiHost` / `RemoteUiSurface` schema 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 `RemoteSession` or `RemoteCapSet`.
- [ ] 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:

```text
make docs
git diff --check
```

First implementation check:

```text
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.
