# Phantty Remote Access Plan

## Goal

Add an opt-in remote access feature for Phantty that lets a signed-in user open a
Cloudflare-hosted web console, enter a short-lived session key generated by the
local Phantty instance, watch the active terminal, and later request interactive
control after local approval.

The first implementation must be safe-by-default:

- No public listener is opened on the user's Windows machine.
- Phantty only dials out to a configured and pinned remote server.
- The web console requires a single configured username/password before any
  session key can be submitted.
- A session key alone is never sufficient. It must match an online Phantty
  device, an authenticated web user, a live WebSocket pairing, and the permission
  mode granted by the local user.
- Control is not enabled by default. The first working version is read-only.

## Ghostty Comparison

Ghostty does not provide a web relay or remote takeover feature, so Phantty
should not copy a remote protocol from Ghostty. The relevant Ghostty behavior is
its IO boundary:

- Ghostty routes terminal writes through `src/termio/message.zig` using
  `write_small`, `write_stable`, and `write_alloc` message variants.
- Ghostty drains those messages in `src/termio/Thread.zig` and performs PTY
  writes from the IO writer thread, rather than writing to the PTY from arbitrary
  UI code paths.
- Ghostty's `Surface.queueIo` also blocks PTY writes when the surface is
  read-only.

Phantty should follow this pattern before accepting remote input. Local typing,
paste, future remote typing, and terminal-generated responses should all pass
through a single write queue so that permission checks, logging, and revocation
can be centralized.

## Architecture

### Cloudflare Side

Use a single Cloudflare Worker deployment:

- Static assets host the `xterm.js` browser console.
- Worker routes handle login, session state, and WebSocket upgrades.
- Durable Objects hold live pairing state between one Phantty WebSocket and one
  or more authenticated browser WebSockets.
- Secrets hold the single-user login material and session signing key.

Initial routes:

- `GET /` serves the browser app.
- `POST /api/login` validates the configured single user.
- `POST /api/logout` clears the login cookie.
- `GET /api/me` reports whether the browser is logged in.
- `GET /ws/browser?session=...` accepts an authenticated browser WebSocket.
- `GET /ws/phantty?device=...` accepts a Phantty WebSocket after device
  authentication.

The Worker scaffold may start with placeholder device authentication while the
Phantty network client is not implemented, but the route shape must not imply
that a session key alone is enough for control.

### Phantty Side

Add remote configuration keys:

- `remote-enabled = false`
- `remote-server-url =`
- `remote-server-fingerprint =`
- `remote-device-name =`

These keys only configure trust and discovery. They must not store the web
admin password or long-lived device private key in plaintext.

Add the IO write foundation:

- Add write messages to `src/termio/message.zig`.
- Have `src/termio/Thread.zig` perform PTY writes on the IO writer thread.
- Replace existing direct UI writes with a `Surface.queuePtyWrite` helper.

Later remote phases will call the same helper after checking local permission.

## Protocol Model

1. Phantty loads `remote-*` config.
2. If enabled, Phantty connects outbound to the pinned Cloudflare Worker over
   `wss://`.
3. Server and Phantty perform challenge/response device authentication.
4. User opens the Cloudflare page and logs in with the single configured account.
5. User clicks "Enable remote sharing" in Phantty. Phantty generates a
   short-lived, single-use session key in memory.
6. User enters the key in the web console.
7. Durable Object pairs the authenticated browser with the online Phantty device.
8. Read-only terminal output begins.
9. Browser may request control. Phantty must show a local confirmation UI before
   remote input is accepted.
10. Phantty can revoke the session at any time.

## Security Requirements

- Use `wss://` only for remote transport.
- Pin the server identity from Phantty config before trusting the relay.
- Keep session keys short-lived, single-use, memory-only, and scoped to one
  device/session.
- Never log session keys, passwords, or device private keys.
- Default to read-only.
- Require local confirmation before accepting remote control.
- Display remote status in Phantty while connected.
- Provide an immediate disconnect action.
- Store web login secrets as Cloudflare Worker secrets, not committed files.
- Prevent browser XSS from becoming terminal control: no third-party scripts and
  no rendering terminal data as HTML.

## Execution Phases

### Phase 1: Safe Foundations

- Write this plan.
- Add Phantty remote config keys and default comments.
- Add mailbox-backed PTY write messages and route existing local writes through
  them.
- Scaffold the Cloudflare Worker/xterm.js app with login and WebSocket route
  placeholders.
- Build Phantty and verify Windows-compatible tracked paths.

### Phase 2: Read-Only Relay

- Add a Phantty remote client module that connects outbound when enabled.
- Stream terminal output snapshots or PTY byte events to the relay.
- Render read-only output in xterm.js.
- Show connection state in a Phantty UI panel.

### Phase 3: Controlled Input

- Add browser "Request control".
- Add Phantty local confirmation UI.
- Add permission-gated remote input through `Surface.queuePtyWrite`.
- Add revoke/disconnect controls.

### Phase 4: Hardening

- Add device key storage using Windows DPAPI or Credential Manager.
- Add server fingerprint pinning enforcement.
- Add replay protection and session expiry.
- Add audit events without sensitive data.
- Add UI automation for the remote panel.

## Non-Goals For Phase 1

- No real remote control.
- No file transfer.
- No clipboard sync.
- No SSH password exposure.
- No multi-user accounts or registration.
- No direct inbound listener on the Windows machine.
