pi-idle-supervisor0.1.10
Remote control for a running Pi session: watch and steer it from a remote client. Tested with Pi 1.4.x.
Untested on omp
This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.
Reports 0
No reports yet.
Readme
pi-idle-supervisor
Watch and steer a running Pi session from another device. The extension runs a small HTTP server on your machine. A remote client (for example an Android app) pairs with a QR code, streams the conversation, sends prompts, and answers permission dialogs while you are away from the terminal.
- No relay and no account. You expose the local server through your own tunnel (Tailscale Serve, a named Cloudflare Tunnel, or the built-in
--tunnel sshoption), so nobody else sees the conversation unless you pick the third-party option. Seedocs/adr/0002-local-server-no-relay.mdanddocs/adr/0004-optional-ssh-tunnel-through-localhost-run.md. - Remote clients can attach images and files to a prompt (see below).
- Works with Pi 1.4.x and Node 22 or newer.
Install
# from npm
pi install npm:pi-idle-supervisor
# from git
pi install git:github.com/khaipnp/pi-idle-supervisor
# from a local checkout
pi install ./pi-idle-supervisor
Restart Pi (or run /reload). The extension does nothing until you run /remote or /remote start.
Commands
| Command | Effect |
|---|---|
/remote |
Asks how your phone will connect (LAN, Tailscale or a localhost.run tunnel), then turns remote on that way. If remote is already on, shows the status. |
/remote start [--lan | --tailscale | --tunnel ssh | --url <https url>] |
Starts the server, creates a fresh access token, and shows a QR code and a pi-remote://pair?... string. Each flag picks one way to connect (see below); using more than one is an error. Without a flag, the address comes from the settings. |
/remote stop |
Closes the server and revokes the token. |
/remote status |
Shows whether remote is on, the public URL, the port and the number of connected clients. |
While remote is on, the footer shows 📡 remote · N clients.
Remote stays on across /new, /resume, /fork and reload, with the same token. It turns off when you run /remote stop or quit Pi.
Settings
Add a remote object to ~/.pi/agent/settings.json (or the project's .pi/settings.json):
{
"remote": {
"port": 7878,
"publicUrl": "https://my-mac.tail1234.ts.net",
"tunnel": "ssh"
}
}
port: local port, default7878. If it is busy,/remote startfails with an error. It never picks another port.publicUrl: the https address your tunnel serves. Optional.tunnel:"ssh"opens a localhost.run tunnel on every/remote start. Optional. A non-emptypublicUrlwins over it.
The public URL put in the QR code is chosen in this order:
- the choice in the
/remotepicker, or/remote start --lan,--tailscale,--tunnel sshor--url <url> - the
remote.publicUrlsetting - the
remote.tunnelsetting - this machine's Tailscale MagicDNS name, from
tailscale status --json http://127.0.0.1:<port>, with a warning: only this machine can use it
Remote URLs must be https. Plain http is accepted only for localhost and for LAN mode.
Ways to connect
In LAN mode the server listens on this machine's private network address. Otherwise it listens on 127.0.0.1 only, and a tunnel gives your phone an https address that forwards to it.
LAN (same Wi-Fi, no setup)
/remote start --lan
The server listens on this machine's private IPv4 address (for example 192.168.1.20, never 0.0.0.0) and the QR code holds http://<that address>:<port>. The phone must be on the same network.
Limits:
- Plain http: anyone on the network who captures the traffic can read the conversation and the access token. Use it only on a network you trust, such as your home Wi-Fi, not a café or office network.
- The address can change when your router hands out a new one. Run
/remote start --lanagain and pair again. - Android blocks plain http unless the app allows it. The client app must allow cleartext traffic to private addresses.
- If your computer's firewall asks whether to accept incoming connections, allow them.
Tailscale Serve
Install Tailscale on the computer and the phone and sign both in to the same tailnet. Then:
tailscale serve --bg 7878
Use your port if you changed it. /remote start finds the MagicDNS name itself, for example https://my-mac.tail1234.ts.net. It looks for tailscale on PATH, then for the command line tool inside the macOS app, and it only uses the name while Tailscale is running. If Tailscale is stopped, remote falls back to the localhost address, which a phone cannot reach. It cannot check that tailscale serve is running, so if the client cannot connect, run tailscale serve status.
localhost.run (no install, no account)
/remote start --tunnel ssh
This runs the ssh that ships with macOS, Linux and Windows 10+, forwards a https://<name>.lhr.life address to the server, and stops it when remote turns off or Pi quits. The phone needs nothing installed.
Limits:
- localhost.run ends TLS, so it can read the traffic, including the access token. Use Tailscale for private work.
- The address is new on every start and changes after a few hours. If
sshends, remote turns off and tells you; run/remote startagain and pair again. The extension does not restart the tunnel on its own, because the QR code would no longer match. - It is a free third-party service with no uptime promise.
Cloudflare Tunnel
Cloudflare Quick Tunnels do not support Server-Sent Events, which the event stream needs, so they do not work here. Use a named tunnel with remote.publicUrl.
cloudflared tunnel --url http://127.0.0.1:7878
Pass the https address of your named tunnel explicitly, or set remote.publicUrl:
/remote start --url https://my-tunnel.example.com
Attachments
A remote client can upload files and attach up to 4 of them to one prompt.
- Images (PNG, JPEG, GIF, WebP) reach Pi as images.
- Any other file is saved on your computer and its path is added to the prompt text, so the agent reads it with its own tools.
- Limits: 12 MB per file and 200 MB in total while remote is on.
- Uploads live in a private temporary folder and are deleted when remote turns off or Pi quits.
Slash commands from the phone
A prompt sent from a remote client is handled like a line typed on the terminal:
/name argsruns an extension command right away, even while the agent is working.- Prompt templates and
/skill:nameexpand as usual. - Pi's built-in commands (
/model,/compact, ...) only work on the terminal, and so does/remote. - A command can't carry attachments.
GET /v1/commandslists what can be sent, so the client can suggest commands as you type/.- Notifications shown on the terminal, such as a command's result, reach the phone as
noticeevents. The pairing message, which holds the access token, is never sent.
Clients written for 1.0 or 1.1 keep working, but text they send that starts with a command name now runs the command. Details are in docs/protocol.md.
Follow-ups from the phone
A follow-up sent from a remote client while the agent is working waits in the extension's follow-up queue rather than in Pi's, so the client can still change its mind:
- The client sees the waiting follow-ups and can steer one into the current run or cancel it.
- When the run settles, the oldest follow-up starts the next run, one at a time.
- Stopping the run (from the phone or with Escape on the terminal) drops the waiting follow-ups.
This is protocol 1.3. Older clients keep working; their follow-ups just wait in the same queue. Details are in docs/protocol.md.
Images in the conversation
Since protocol 1.4 a remote client can fetch the images in the conversation, such as a photo sent from the phone or an image a tool read, with GET /v1/messages/{id}/images/{n}, so it can show them rather than a placeholder. Snapshots and events still carry no image bytes.
Model and thinking level
Since protocol 1.5 a remote client can see which model and thinking level the session uses and change them, as /model and Shift+Tab do on the terminal. It offers the models in your enabledModels setting (or --models), or every model you have credentials for when that is not set. The switch applies to the running session only, and works while the agent is working. Changes made on the terminal show up on the phone too.
Since protocol 1.6 a remote client can list this project's saved sessions, open one, or start a new one, as /resume and /new do on the terminal. It cannot leave a session while the agent is working.
Pairing
Scan the QR code with the client, or paste the pairing string. The string looks like pi-remote://pair?url=<public url>&token=<access token>&v=1.
Security
- Access token. Created every time remote turns on: 32 random bytes, base64url. It is the only credential, so treat the QR code and pairing string like a password. It stops working when remote turns off or Pi quits.
- Bind address. The server listens on
127.0.0.1, so only your tunnel can reach it. In LAN mode it listens on one private address (10.x, 172.16–31.x or 192.168.x), never on all interfaces. - Lockout. A wrong or missing token gets
401. Ten failures within 60 seconds lock out all clients for 60 seconds (429). The lockout is global because tunnelled requests all arrive from127.0.0.1. - https only.
--urlandpublicUrlreject plainhttpfor non-local hosts so the token is never sent in cleartext. LAN mode is the one exception and says so when it starts. - Dialogs (ADR-0001 caveat). To let you answer permission prompts from other extensions remotely, the extension wraps
select,confirmandinputon Pi's shared UI context. That relies on unofficial Pi behaviour and may break on a Pi upgrade. If Pi's UI context looks different from what is expected, remote dialogs are turned off with a warning and the rest keeps working. Dialogs Pi opens without going through that context cannot be answered remotely. Seedocs/adr/0001-remote-dialogs-by-wrapping-shared-ctx-ui.md. - Anyone holding the token can read the whole conversation and run anything the agent can run. Run
/remote stopwhen you are done.
For client authors
The wire protocol (pairing, endpoints, events, errors) is in docs/protocol.md, with a JSON Schema in schema/protocol.schema.json.
Development
npm install
npm run typecheck
npm test