copilot-mobile v1.0
Control gh copilot
from any device.
Share a running Copilot CLI session via a URL. Any browser — phone, tablet, second monitor — joins the same PTY and can type, scroll, and interact in real time.
How it works
on your machine
Run copilot-mobile
The CLI spawns gh copilot in a PTY and connects to the relay server as a host. A one-time session URL is printed to stderr.
relay server
Relay bridges the PTY
The relay holds the session. It forwards PTY output to every connected viewer and routes viewer keystrokes back to the host PTY.
on your phone
Open the share URL
A full terminal renders in the browser. Arrow keys, Enter, Ctrl+C — all inputs reach the running Copilot session live.
Install
# Prerequisites: Node.js 20+, gh CLI, gh copilot extension
# install gh copilot extension gh extension install github/gh-copilot # install copilot-mobile npm install -g copilot-mobile
# Usage
# via relay (default: copilot.tatsut.jp) copilot-mobile --relay --password yourpassword # local mode (no relay, direct port share) copilot-mobile # with custom relay server copilot-mobile --relay wss://your.host/relay --password pw
# Persist config in ~/.config/copilot-mobile/config.json
{
"defaultRelayUrl": "wss://copilot.tatsut.jp/relay",
"password": "yourpassword"
}
Security
Per-session passwords
Each session requires a password set by the host. Passwords are hashed (SHA-256) before storage — the relay never holds plaintext.
Timing-safe comparison
Password checks use crypto.timingSafeEqual to prevent timing-based attacks on session IDs and passwords.
No session enumeration
The server returns identical errors for "session not found" and "wrong password", making brute-force enumeration impractical.
Rate limiting
WebSocket connection attempts are rate-limited per IP (10 per 60s). Excess requests receive HTTP 429.
Strict CSP headers
Content-Security-Policy, X-Frame-Options DENY, X-Content-Type-Options, and Referrer-Policy headers are set on all responses.
One-time sessions
Session IDs are cryptographically random (20 hex chars) and generated fresh on every launch. Sessions are destroyed on host disconnect.