# 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 new
  `system-remote-session-*.cue` manifest the new transport requires
- Remote-session DTO additions in `schema/capos.capnp` (shared serial
  surface -- see `docs/plans/README.md` Concurrency Notes; only one plan at
  a time may change `schema/capos.capnp`, and `make generated-code-check`
  must pass before the next plan picks it up)
- `docs/proposals/remote-session-capset-client-proposal.md`,
  `docs/backlog/remote-session-capset-client.md`
- `Makefile` targets `remote-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_USER` or the host `USER` so it matches the
  operator account injected by `make run`. Resource profile names such
  as `operator` are 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
  and `REVIEW_FINDINGS.md`. Coordinate with the user before extending
  `kernel/src/cap/session_manager.rs` or `kernel/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-check`
- `make generated-code-check`
- `cargo build --features qemu`
- `cargo test-config`
- `cargo test-lib`
- `cargo check --manifest-path tools/remote-session-client/Cargo.toml --target x86_64-unknown-linux-gnu`
- `cargo test --manifest-path tools/remote-session-client/Cargo.toml --target x86_64-unknown-linux-gnu`
- `cargo build-demos-capos`
- `make run-remote-session-capset-interop`
- `make run-remote-session-adventure-interop` (required when the
  iteration changes `demos/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-rpc` proxy 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-interop` and
      a host-side test in `tools/remote-session-client/`. Record the
      transition in `docs/proposals/remote-session-capset-client-proposal.md`.
- [ ] Document any temporary dual-stack period in
      `docs/backlog/remote-session-capset-client.md` so 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_out` cells.
- [ ] Record the resulting contract in
      `docs/proposals/remote-session-capset-client-proposal.md` so 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.md` and
      `docs/backlog/remote-session-capset-client.md` so future operators
      can tune them safely.

### Task 5: Richer service clients

- [x] 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`.
- [x] 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 redacted `SessionSummaryDiffVm` shape (added /
      removed cap entries by `(name, interfaceIdHex)`, policy/lease
      changes, redacted session-id changes, and a summary string).
- [x] Add a corresponding focused proof in
      `run-remote-session-capset-ui` and document the new client in
      `docs/proposals/remote-session-capset-client-proposal.md`. The
      browser smoke now clicks the new "Refresh & Show Diff" button
      twice per session: the first click reports
      `hasBaseline=false` while the second click reports a populated
      diff payload with `hasBaseline=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.md` and `docs/changelog.md`.
