mirrormux
v0.1.0
Published
Mirror a live tmux pane to your phone's browser. Watch and drive Claude Code from anywhere on your network — no app, no API key, zero runtime dependencies.
Maintainers
Readme
mirrormux
Mirror a live tmux pane to your phone's browser.
You are working in tmux at your desk. You walk away. You open your phone and the same screen is there — mid-task, still updating. You approve the prompt that was waiting, type the next instruction, and put your phone away.
No app to install. No API key. No account. Zero runtime dependencies.
⚠️ This tool types into your shell. Anyone who gets past authentication can run arbitrary commands on the host. It ships bound to
127.0.0.1for that reason. Read SECURITY.md before exposing it to a network.
Why this exists instead of the alternatives
Most mobile coding-agent clients host the agent: a bridge server spawns a session that belongs to the app. mirrormux does the opposite — it is a remote control for a tmux pane that already exists.
That single choice is the whole product:
- The PC and the phone see the identical screen. Not a resumed session, not a synced transcript — the same pane, because both are reading the same tmux window.
- Your existing agent login just works. mirrormux runs nothing and
authenticates to nothing. Whatever you started in tmux — Claude Code on a
subscription, an SSH session, a long build — is what you see. No
ANTHROPIC_API_KEY, no per-token billing. - Nothing to install on the phone. It is a web page (installable as a PWA if you want the fullscreen look).
If you want a polished native app with git staging, a file explorer, and Codex support, use CC Pocket — it is excellent and does far more. mirrormux is for the one thing it cannot do: showing you the pane you are already attached to.
Requirements
- macOS or Linux with tmux installed
- Node.js 20+
- A phone on the same network, or a VPN / SSH tunnel back to the host
Install
npx mirrormux --init # writes a config with a generated 24-char password
npx mirrormux # start--init prints the username and password once. It writes to
~/.config/mirrormux/config.json with mode 0600.
git clone https://github.com/nogataka/mirrormux.git
cd mirrormux
node server.js --init
node server.jsA config.json in the repository root takes precedence over the one in
~/.config, so cloned checkouts keep their settings local.
Connect from your phone
By default the server listens on 127.0.0.1 only — nothing outside the host
can reach it. Pick one of these:
SSH port forward (safest, nothing listens on the network):
ssh -L 7690:127.0.0.1:7690 you@your-host
# then open http://127.0.0.1:7690 on the forwarding deviceMesh VPN (Tailscale / WireGuard): set "host" to your VPN interface
address, then browse to http://<vpn-ip>:7690.
Trusted LAN: set "host": "0.0.0.0" and browse to http://<host-ip>:7690.
The server will warn you at startup about what this exposes.
Then, on the host, run your work inside tmux:
tmux new -s main
claude # or anything elsePanes started outside tmux are invisible to mirrormux — that is the one workflow change this tool asks of you.
What you get on the phone
- The live pane, ANSI colors intact, following new output automatically
- Approval prompts as buttons. Numbered agent choices are detected and normalized into Allow / Allow all / Deny, with the primary action on the right where your thumb is
- Per-window status dots — yellow (working) / red (waiting on you) / green (idle) — so you can see which of several sessions needs you
- A real text field, not a terminal emulator. IME works, so CJK input works. Enter inserts a newline; sending is an explicit button, so you can edit a long instruction before it goes anywhere. Voice dictation, autocorrect, and clipboard all come free from the OS
- Width that actually fits. One tap resizes the tmux window to your phone's measured column count, so the TUI re-wraps instead of scrolling sideways. It restores itself a minute after you disconnect
- Image attachment from the library, camera, or paste
- A tmux admin page for creating, renaming, reordering, and killing windows, with two-step confirmation on destructive operations
Optional: notifications when you are away
Your terminal beeps when an agent finishes. Your phone, in your pocket, does
not. mirrormux can post to Slack or LINE via Claude Code's Stop and
Notification hooks.
The point is the idle gate: it only notifies when the host keyboard has been idle past a threshold (default 5 minutes). Sitting at your desk produces no notifications at all.
See README.ja.md for setup, or
config.example.json for the shape of the notify block. This part is entirely
optional — mirrormux works fine without it.
Configuration
Full reference: config.example.json. The ones that matter:
| Key | Default | Meaning |
|---|---|---|
| host | 127.0.0.1 | Bind address. Changing this exposes an RCE surface |
| port | 7690 | |
| auth.user / auth.pass | (required) | Generate with --init |
| tls.cert / tls.key | (none) | Serve HTTPS; also marks the cookie Secure |
| defaultTarget | null | tmux target to open first, e.g. main:0 |
| shortcuts | a couple | One-tap text buttons above the input |
| launchPresets | [] | Directories the admin page may start sessions in. Phones cannot send arbitrary paths — only these |
| allowedHosts | [] | Extra hostnames accepted in the Host header |
CLI
mirrormux start
mirrormux --init create a config with a generated password
mirrormux --revoke log out every device
mirrormux --config PATH use a specific config file
mirrormux --helpLost your phone? mirrormux --revoke invalidates every session token
immediately.
Running it as a service
bash scripts/install-launchd.sh # macOS, via launchdLogs land in ~/Library/Logs/mirrormux/. On Linux, write a systemd user unit
pointing at node /path/to/server.js.
How it works
tmux pane (the source of truth)
↑ ↑
your terminal mirrormux server
(attached) capture-pane / send-keys
↓ SSE
phone browserReading is tmux capture-pane -p -e on a poll, diffed and pushed over SSE.
Writing is tmux send-keys -l, which delivers the whole string literally in one
burst — no per-keystroke race with the TUI redrawing, and no escape-sequence
interpretation.
mirrormux never attaches, so it never fights your terminal over the window size.
Limitations
- tmux is required, and your work has to run inside it
- Agent approval detection reads on-screen text, so an agent's UI redesign can break it. The design is fail-soft: detection failing costs you the buttons, not the ability to type
- Slash-command autocomplete does not appear — type the full command, or put it
in
shortcuts - macOS/Linux only; the notification idle gate uses macOS
ioregtoday
License
MIT — see LICENSE.
Not affiliated with Anthropic, OpenAI, or the tmux project.
