cmux-iphone

skill
Security Audit
Fail
Health Warn
  • License — License: MIT
  • Description — Repository has a description
  • Active repo — Last push 0 days ago
  • Low visibility — Only 6 GitHub stars
Code Fail
  • rm -rf — Recursive force deletion command in .github/workflows/release.yml
Permissions Pass
  • Permissions — No dangerous permissions requested

No AI report is available for this listing yet.

SUMMARY

Bridge your Claude Code / Codex / cmux sessions to your iPhone & Apple Watch — approve, prompt, and mirror live terminals on the go.

README.md

Cmux iPhone

English · 한국어

CI License: MIT Release

Watch and control your Claude Code, Codex, and cmux sessions from your iPhone (and Apple Watch).
See live terminal output and send prompts; approve permission requests on iPhone and monitor them on Apple Watch — over your LAN or Tailscale.

https://github.com/user-attachments/assets/5f478c28-2086-4696-9d76-e43dda853201


How it works (two halves)

   iPhone / Watch  ──HTTP+SSE──►  cmux-iphone bridge (Node)  ──hooks──►  Claude Code
   (SwiftUI app)   ◄────────────  on your Mac                 ──RPC───►  cmux mirror
                                                              ──log───►  Codex
  • Bridge (Mac): a small Node server (cmux-iphone) that receives Claude Code
    hook events, mirrors live cmux workspaces, watches Codex, and serves the phone
    over HTTP + Server-Sent Events. Discovered on the LAN via Bonjour.
  • App (iPhone + Watch): a SwiftUI app that pairs with the bridge, shows live
    sessions/terminal output, and answers permission prompts.

Everything runs on your own machines — no cloud, no account, no server to host.
The bridge is loopback-only by default (expose it over Tailscale/LAN explicitly); a pairing code + per-device token are the auth boundary.
Run it over Tailscale or a trusted LAN — it is not built to face the open internet
(see SECURITY.md).

cmux is optional. With cmux installed you get the live workspace/terminal
mirror; without it, the bridge still streams hook-based Claude/Codex sessions.


Requirements

Component Minimum
macOS 13+
Node.js 18+
Xcode 16+ (to build the app)
iOS / watchOS 17 / 10
Claude Code recent
cmux optional, 0.63.2+ (uses cmux's mobile.* RPC)
Tailscale optional (remote access)

Install — the Mac bridge

Homebrew (recommended)

brew install lim-won/tap/cmux-iphone
cmux-iphone setup

brew upgrade cmux-iphone updates it; re-run cmux-iphone setup once afterward so
the LaunchAgent / cmux workspace re-point at the new version.

From source

git clone https://github.com/lim-won/cmux-iphone && cd cmux-iphone/skill/bridge
npm ci                        # reproducible install (use `npm install` if no lockfile)
npm link                      # optional: puts `cmux-iphone` on your PATH
cmux-iphone setup             # or: node bin/cmux-iphone.js setup

cmux-iphone setup is idempotent (safe to re-run). It:

  1. checks macOS + Node 18+, detects Claude/Codex/cmux/Tailscale,
  2. writes config.json and generates secrets (0600, never rotated on re-run),
  3. backs up ~/.claude/settings.json and merges Cmux iPhone's hooks (scoped —
    it never touches another tool's hooks),
  4. picks a runner — in-cmux when cmux is present (so the live mirror works), or
    a LaunchAgent when it isn't,
  5. health-checks the bridge and prints your LAN/Tailscale address + pairing code.

Why two runners? A launchd process cannot reach the cmux control socket
(verified). So when cmux is present the bridge runs inside a cmux workspace;
otherwise it runs as a LaunchAgent serving hook/phone/Codex sessions only.

Using the cmux mirror

For the live cmux mirror, cmux must be running and its control socket
reachable
when you run setup (configure cmux's socket password if it uses one).
Then:

cmux-iphone setup --cmux     # fails fast if cmux RPC isn't reachable (instead of half-installing)
cmux-iphone doctor           # confirm:  cmux RPC = mobile.workspace.list OK

If cmux is installed but its socket isn't reachable, setup stops and tells you —
it won't silently start a bridge that can't mirror. To skip cmux entirely and run
hook/phone/Codex sessions only: cmux-iphone setup --launchd.

Manage it with the CLI:

Command What it does
cmux-iphone setup install / repair (idempotent)
cmux-iphone doctor read-only diagnostics — paste this into a GitHub issue
cmux-iphone status bridge state, LAN/Tailscale address, cmux, paired devices
cmux-iphone pair show the pairing code · --list · --revoke <id>
cmux-iphone logs tail the LaunchAgent log (for an in-cmux bridge, open the Agent Bridge workspace)
cmux-iphone restart restart the bridge
cmux-iphone uninstall remove hooks + service (--purge also deletes data)

Install — the iPhone / Watch app (build it yourself)

There is no App Store / TestFlight build — Cmux iPhone is distributed as
source and you build it with your own free Apple ID. (TestFlight requires a paid
Apple Developer Program; a public binary may come later if the project enrolls.)

1. Set your bundle id (one command — no XcodeGen needed; the iPhone id, the
Watch id, and the Watch's companion id all derive from it):

./scripts/configure-ios.sh com.yourname.cmuxiphone
open ios/CmuxiPhone/CmuxiPhone.xcodeproj

2. Add your Apple ID to Xcode: Xcode → Settings → Accounts → + → Apple ID
(a free account works).

3. Set the Team on BOTH targets: select the project → for CmuxiPhone and
CmuxiPhoneWatch, Signing & Capabilities → Automatically manage signing
Team = your Personal Team. (The bundle ids are already set by step 1.)

4. Enable Developer Mode on the iPhone (iOS 16+): Settings → Privacy &
Security → Developer Mode → On → restart. (Do the same on the Watch if
deploying to it: Watch app / watchOS Settings → Privacy & Security.)

5. Run: plug in your iPhone (with the Watch paired), pick the CmuxiPhone
scheme + your iPhone as the destination → Run (⌘R). For the Watch app, pick
the CmuxiPhoneWatch scheme and the paired-Watch destination (deploy via the
iPhone if direct watch install fails).

6. Trust the developer cert: on the iPhone, Settings → General → VPN & Device
Management → tap your developer profile → Trust.

Free-team limits: the app expires ~7 days after building (re-run from
Xcode to refresh), no push notifications (local notifications only), max 3
devices. SideStore/AltStore can auto-refresh the iPhone app wirelessly.

Maintainers: the project is generated from project.yml with xcodegen — only
needed if you change the project structure; end users use the script above.

Pair

  1. Open the app → enter the pairing code (see below) + the Mac's address
    (cmux-iphone status shows the LAN and Tailscale addresses).
  2. Same Wi-Fi → the bridge is also auto-discovered (Bonjour), so you can skip
    typing the address. Across networks, use the Tailscale address so the
    same pairing works whether you're in the office or away.

Each device gets its own token; revoke any of them with
cmux-iphone pair --revoke <id> (see cmux-iphone pair --list).

Where do I get the pairing code?

You don't need to be a developer — it's two commands at most:

  • At install, cmux-iphone setup prints your code (and the addresses) at the
    end. It generates one stable code per Mac and saves it — it does not
    keep changing, so you can reuse it.
  • Anytime later, run cmux-iphone pair to show it again.
$ cmux-iphone pair
Pairing code: 000000
Enter this code in the Cmux iPhone app on your iPhone.

Choose your own code (optional): set CMUX_IPHONE_PAIR_CODE=123456 in the
bridge's environment to pin a memorable code. The code is the pairing gate
(rate-limited — 5 tries per 5 min — and each device still gets its own token), so
keep it private. Trusted LAN or Tailscale use is recommended; do not expose the
bridge directly to the public internet.

Rotating code (optional): prefer a code that rotates over a fixed one? Run
cmux-iphone setup --rotating — a fresh 6-digit code each restart (24h TTL,
cleared once a device pairs) instead of the stable per-Mac default.

Watch approvals (beta): the Watch shows approvals but you answer them on
the iPhone for now.


Remote access over Tailscale

The bridge speaks plain HTTP and is built for your LAN or a private
Tailscale tailnet — never the open internet. Tailscale
lets your iPhone reach your Mac from anywhere, as if they were on the same Wi-Fi.

1. Install Tailscale on both devices, same account.

brew install --cask tailscale     # Mac (or download the app), then sign in

On the iPhone, install Tailscale from the App Store and sign in with the same
account. Both devices now share one private tailnet.

2. Find your Mac's Tailscale address.

cmux-iphone status
# Tailscale: http://100.x.y.z:7860

100.x.y.z is your Mac's tailnet IP. With MagicDNS enabled (Tailscale admin
console) you can use the Mac's hostname instead (e.g. your-mac).

3. Pair the phone with that address. Bonjour auto-discovery only works on the
same Wi-Fi and does not cross the tailnet, so for remote access enter the address
by hand: in the app tap Enter IP manually, type the 100.x.y.z (or MagicDNS
hostname) + your pairing code (cmux-iphone pair). The same pairing then works on
Wi-Fi, cellular, or anywhere your tailnet reaches — no re-pairing.

4. Exposing the bridge (it is loopback-only by default). For safety the bridge
binds 127.0.0.1 out of the box, so a fresh install is never reachable over
plaintext HTTP by anyone else on your network — and your phone can't reach it yet.
Pick how to expose it:

cmux-iphone setup --bind 100.x.y.z     # Tailscale IP — encrypted, recommended
cmux-iphone setup --lan                # entire LAN — plaintext, trusted networks only

Both persist bindAddress to config.json and restart the bridge. (The HOST env
var only affects a bridge you launch by hand — the managed launchd/cmux service does
not inherit it, so use setup --bind or edit config.json for the installed bridge.)

Re-run cmux-iphone status to confirm the bound address, and keep the Mac awake for
remote use:
sudo pmset -a sleep 0 && sudo pmset -a disablesleep 1.

Multiple Macs on the road? See REMOTE-SETUP.md for naming
each Mac (office-mac-1, …) and switching between them in the app.


Troubleshooting

Run cmux-iphone doctor first — it prints a PASS/WARN/FAIL report (no
secrets) that's ideal to paste into an issue.

  • iPhone "Connection failed": run cmux-iphone status to get the bridge's
    actual address + port (it may bind another port in 7860–7869, or a non-loopback
    interface), then probe /health there — e.g. curl http://<addr>:<port>/health
    (note: /status requires auth). Bridge + phone must share the LAN (or Tailscale).
  • No cmux workspaces: cmux only mirrors when the bridge runs inside cmux
    (cmux-iphone status shows the runner). Without cmux you still get hook sessions.
  • Watch/phone can't find the bridge (Bonjour): check, in order — the app's iOS
    Local Network permission; both devices on the same network; the router's
    AP / client isolation is off; mDNS isn't blocked; then fall back to entering
    the IP manually (from cmux-iphone status).
  • Permission prompts don't appear: confirm hooks in ~/.claude/settings.json
    and that a device is paired (cmux-iphone pair --list).

How it works

Event flow (Mac → phone)

Claude Code runs a tool → a PostToolUse/PreToolUse hook POSTs to the bridge →
the bridge pushes an SSE event → the app renders it.

Permission flow (Mac → phone → Mac)

Claude hits a permission prompt → the PermissionRequest hook blocks → the
bridge pushes a permission-request SSE event → the phone shows the options →
your choice is POSTed back → the bridge returns the decision to Claude.
(For codex exec-approvals, the bridge types the answer into the pinned cmux
terminal, guarded by a screen hash — it refuses if the screen changed.)

Hooks installed (loopback listener, secret-gated): PostToolUse, PreToolUse,
PermissionRequest (blocking, up to 10 min), SessionStart, SessionEnd,
Stop, error events.


Security

By default the bridge listens on 127.0.0.1:<port> (loopback-only); exposing it to
your phone is an explicit opt-in via bindAddress / the HOST env / setup --lan
(prefer a Tailscale IP — encrypted). Requests carrying a foreign Host header are
rejected (DNS-rebinding defense). Auth is the pairing code + per-device token; the
hook listener is loopback-only and secret-gated.
Secrets live outside the repo at 0600. Trusted LAN or Tailscale use is recommended —
do not expose the bridge directly to the public internet. Full model + reporting in
SECURITY.md.

License

MIT — see LICENSE.

Cmux iPhone is a fork of shobhit99/claude-watch
(MIT); original-author copyright is preserved. The app ships neutral icons — no
Claude/Anthropic or OpenAI/Codex logo assets are bundled; "Claude" and "Codex" are
trademarks of Anthropic and OpenAI respectively, used only as text labels. This is an
independent community tool, not affiliated with or endorsed by Anthropic or OpenAI.
See NOTICE.md for full attribution.

Reviews (0)

No results found