- scripts/smoke/helpers.mjs — spawn-pi (via python3 pty.spawn), wait-for-port,
fetch, WebSocket helpers; createSmokeHome/removeSmokeHome for isolated HOME
- scripts/smoke/smoke.mjs — 6 node:test assertions:
GET /manifest.json → 200 + JSON shape
GET /icon.svg → 200 + <svg body
GET / (with token) → 302→200 + HTML marker
GET / (no token) → 403
WS /ws (with token) → 101 upgrade
pi process alive check
- scripts/smoke/README.md — usage, design notes, extension guide
- package.json: add 'smoke' script
- docs/SYNC.md: add scripts/smoke/** ownership row + History entry
All 6 tests pass in ~1.4 s locally.
Key finding: pi requires a PTY to enter interactive mode and fire
session_start. Spawning without a TTY causes immediate exit. Workaround:
python3 pty.spawn() — allocates a PTY with no additional deps.
|
||
|---|---|---|
| .husky | ||
| assets | ||
| docs | ||
| extensions/remote-control | ||
| scripts/smoke | ||
| .gitignore | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| biome.json | ||
| package-lock.json | ||
| package.json | ||
README.md
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
Personal use and research only. Provided as-is, no liability for damage, misuse, or operational consequences. See Security notes.
Current state: browser client
The extension ships a working HTML/WebSocket client that mirrors a pi session in any browser — including iPhone Safari.
Install
pi install git:git.vpsj.de/jay/pi-remote-control
Usage
Run /remote-control inside pi to open the menu:
- Turn on / Turn off — start or stop the server
- Configure URL — set the base URL for your tunnel or proxy
- Status — show the QR code and current session URL
To start the server automatically:
pi --remote-control
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.
In development: native iOS app
A native iOS app is being built on top of this extension's WebSocket infrastructure. Design goals:
- 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.
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/:
| File | Purpose |
|---|---|
docs/NEXT-STEPS.md |
Current state + what to do next |
docs/PHASE-1-sidecar.md |
Sidecar production-ready |
docs/PHASE-2-ios-mvp.md |
iOS app MVP |
docs/PHASE-3-ios-augmentation.md |
iOS polish features |
docs/SYNC.md |
Multi-agent coordination |
docs/reference/SPEC-ios-app.md |
Full feature spec (v3) |
Security notes
- 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.
