diff --git a/README.md b/README.md index 6d33b72..35e0f49 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,101 @@ # pi-remote-control +A `pi` extension that exposes running sessions over WebSocket — used today +as a browser-based remote control, and the foundation for a native iOS app +currently in development. + ## Disclaimer -This project is for personal use and research only. It is provided as-is, and the author accepts no liability for any damage, loss, misuse, or operational consequences that result from installing or using it. The server has no built-in authentication beyond a session token and no HTTPS on the dynamic port — see [Security notes](#security-notes) for details. Do not use it for safety-critical, multi-user, or untrusted-network deployments. +Personal use and research only. Provided as-is, no liability for damage, +misuse, or operational consequences. See [Security notes](#security-notes). -## Install +--- + +## Current state: browser client + +The extension ships a working HTML/WebSocket client that mirrors a pi +session in any browser — including iPhone Safari. + +### Install ```bash -pi install https://github.com/goofansu/pi-remote-control +pi install git:git.vpsj.de/jay/pi-remote-control ``` -## Usage +### Usage -Run `/remote-control` to open the menu: +Run `/remote-control` inside pi to open the menu: - **Turn on / Turn off** — start or stop the server -- **Configure URL** — set the base URL exposed by your local tunnel or proxy, saved to `~/.pi/agent/remote-control.json` -- **Status** — show the QR code and connection URL (only when server is running) +- **Configure URL** — set the base URL for your tunnel or proxy +- **Status** — show the QR code and current session URL -> **Note:** On first use, you must configure the URL before the server can start. - -To start the server automatically on launch: +To start the server automatically: ```bash pi --remote-control ``` -## Use case +The server binds to `127.0.0.1` and is reached through a local tunnel +(e.g. Surge Ponte, Tailscale). Open the QR URL in any browser. -The remote-control server binds to `127.0.0.1` on the host running `pi` and is reached through a local tunnel or proxy. This example uses [Surge Ponte](https://kb.nssurge.com/surge-knowledge-base/guidelines/ponte), which provides an end-to-end encrypted device-to-device tunnel without exposing the server to the LAN. +![pi remote control on iPhone](assets/screenshot-mobile.png) -The setup is: +--- -1. Install this extension on the Mac that runs `pi`. -2. Enable Surge Ponte on that Mac and give it a device name such as `pi`. -3. On the same Mac, open `pi` and run the `/remote-control` command. -4. Choose `Configure URL` and set the base URL to your Surge Ponte hostname, for example `http://pi.sgponte`. -5. Choose `Turn on`. -6. Open `Status` to get the QR code and connection URL for the current session. -7. On another device on the same Surge Ponte network, open that URL in a browser. +## In development: native iOS app -In this setup, the browser URL is `http://pi.sgponte:`, where the port is assigned when the server starts. Use `Status` to get the current URL or scan the QR code — it changes each time the server restarts. +A native iOS app is being built on top of this extension's WebSocket +infrastructure. Design goals: -Here's what it looks like on iPhone — this is an actual session asking `pi` about its hardware environment: +- **Byte-exact mirror** of the terminal session — what you see over SSH + is what you see on the phone, rendered via SwiftTerm. +- **Session persistence** — sessions run for days, the app reconnects + instantly after backgrounding (< 1s, via sequence-cursor delta replay). +- **Multi-session** — spawn, name, and switch between pi sessions from + the phone as easily as browser tabs. +- **Pi-aware augmentation** — modifier bar tuned for pi (Ctrl, Esc, Tab, + arrows, Shift+Enter), slash-command palette, status bar showing what pi + is currently doing, push notifications when pi is waiting for input. +- **QR pairing** — scan once, self-signed TLS + token pinned automatically. -pi remote control on iPhone via pi.sgponte +### Architecture (in progress) + +``` +pi (Ink TUI) ◄──► tmux session ◄──► SSH (Mac terminal) + │ + tmux -C (control mode) + │ + pi-remote sidecar (this extension, extended) + │ wss:// (binary ANSI + JSON side-channel) + ▼ + iOS app (SwiftUI + SwiftTerm) +``` + +Streaming uses tmux control mode (`tmux -C`) rather than `pipe-pane` — +verified reliable across alternate-screen transitions in a PoC spike. + +### Implementation docs + +All planning and coordination lives in [`docs/`](./docs/): + +| File | Purpose | +|---|---| +| [`docs/NEXT-STEPS.md`](./docs/NEXT-STEPS.md) | Current state + what to do next | +| [`docs/PHASE-1-sidecar.md`](./docs/PHASE-1-sidecar.md) | Sidecar production-ready | +| [`docs/PHASE-2-ios-mvp.md`](./docs/PHASE-2-ios-mvp.md) | iOS app MVP | +| [`docs/PHASE-3-ios-augmentation.md`](./docs/PHASE-3-ios-augmentation.md) | iOS polish features | +| [`docs/SYNC.md`](./docs/SYNC.md) | Multi-agent coordination | +| [`docs/reference/SPEC-ios-app.md`](./docs/reference/SPEC-ios-app.md) | Full feature spec (v3) | + +--- ## Security notes -- The server only listens on localhost. Remote access depends on whatever local tunnel or proxy you configure. -- There is no multi-user authentication. Treat the connection URL as a secret for the lifetime of the session. -- If you use a reverse proxy instead of Surge Ponte, configure it to terminate TLS at a fixed `https://` endpoint and forward to the server's dynamic backend port. Do not expose the dynamic port directly over a public network, as the server does not support HTTPS and any token or session cookie would be transmitted in cleartext. +- The server only listens on localhost. Remote access depends on your tunnel. +- No multi-user authentication. The connection URL is a per-session secret. +- **iOS app** (in development) uses bearer tokens stored in the iOS Keychain, + self-signed TLS with fingerprint pinning via QR pairing, and optional + Face-ID gate — no CA or public PKI required. +- If using a reverse proxy, terminate TLS there and do not expose the + dynamic backend port directly.