Mosh on iPhone
Backgrounding behavior, reconnect, and the auto-run lifecycle on Mosh sessions.
Why Mosh on iPhone
Mosh is the right transport when your iPhone moves between networks. It rides over UDP, so when you switch from Wi-Fi to cellular or fall behind a CG-NAT for a minute, the session does not collapse. It also carries local-echo prediction, which makes typing feel instant on a high-latency tower.
vmuxPhone supports Mosh end-to-end with the same mosh-server requirement as the visionOS app. Pick Mosh in the host editor, fill in the optional UDP port, prediction mode, and address family, and connect.
What is different on a phone
Three things change when you put Mosh on iOS:
- Background time is short. iOS gives an app a fixed grace period after it goes to the background, then suspends it. UDP cannot survive a process suspension on its own.
- Process lifecycle is different. vmuxPhone can be evicted by the OS at any time when memory is tight, even from the background grace state.
- Reconnects are silent and frequent. Locking and unlocking the phone, switching apps, walking through your house all break and re-establish the UDP path.
vmuxPhone handles each of these explicitly. Most of the behavior is automatic and invisible — the rest is surfaced on the status line at the top of the terminal and in the Live Activity.
The background lifecycle
The terminal session goes through four states as you use the app.
| State | Status line | What is happening |
|---|---|---|
| Active | none | App in foreground, UDP flowing. |
| Background grace | Maintaining connection in background… | App went to the background; iOS background-task coordinator is keeping the runtime alive. UDP packets continue. |
| Suspended resumable | Session paused in background. | Grace period ended. The Mosh state token is preserved and the connection will resume when you foreground the app. |
| Reconnecting | Reconnecting… | App is foreground again; vmuxPhone is replaying the resume probe and rebuilding the UDP session. |
vmuxPhone uses an internal IOSBackgroundTaskCoordinator to negotiate the grace window with iOS. The coordinator gets a deadline back, hands it to the session as the graceDeadline, and ends the background task as soon as you foreground. If iOS sends the task expiration signal before the deadline (which happens under memory pressure), the session prepares for clean suspension immediately.
You do not configure any of this. The coordinator runs every time you switch apps, lock the screen, take a call, or get evicted briefly.
Reconnect behavior
When vmuxPhone comes back to the foreground, it:
- Ends any pending background task.
- Calls
resumeFromForeground()on every open session. - For each Mosh session, replays the saved resume token to recover the UDP path.
- For each SSH session, retries the TCP handshake.
- Updates the status line and the Live Activity.
If the resume succeeds you see your prompt and scrollback intact. If the resume fails (because the server restarted or the session expired), the status line shows Connection failed: reason. Tap the menu and pick Reconnect to start a fresh session — the Mosh client picks a new resume token and re-runs the SSH bootstrap.
The default 15-second connect timeout applies to the SSH bootstrap. UDP itself does not have a hard timeout — Mosh keeps trying until the user disconnects or the session is reset.
Network changes
Mosh sessions roam across networks transparently. There is no toggle for this and no UI prompt. When you walk from Wi-Fi to cellular, the session sees a new client IP, the server responds, and packets keep flowing. The status line remains Connected the whole time.
If the network outage is long enough that the OS suspends the app, the session moves to Session paused in background and resumes on the next foreground.
Local echo on Mosh
Mosh has built-in local-echo prediction. The mode is selected per-host in the editor:
- Adaptive — show predictions only when the round-trip latency is high enough to justify them. Recommended.
- Always — show predictions immediately, even on local Wi-Fi. Use this if you want the typing-feels-instant experience everywhere.
- Never — disable predictions. Useful for debugging or when the predicted text trails confuse you.
The vmuxPhone renderer also has its own local echo prediction layer that runs on top of the SSH/Mosh layer; both can run simultaneously.
Notification and Live Activity behavior
Mosh sessions emit the same events as SSH sessions:
| Event | What you see |
|---|---|
| Bell | A bell flash, an iOS notification (when in background), and the Live Activity alert badge turns on. |
| Disconnect | A notification with the host name and the reason. |
| Reconnect | The Live Activity returns to Connected. |
| Background grace | Live Activity status changes to Background. |
| Suspended | Live Activity status changes to Paused. |
See Live Activities and Notifications for the rest of the surfacing rules.
Auto-run runs
vmuxPhone has a developer-mode auto-run path used by our CI and the Mosh diagnostics tooling. You will not normally encounter it, but it exists so that we can verify the lifecycle without manually shaking the phone.
Launching vmuxPhone with --mosh-diagnostics-auto (and a few related flags) opens a single Mosh window without the host list. The view runs through these stages:
- Boot — emits a
__VMUX_PHONE_APP_BOOT__log line. - Connect — uses the seeded host info and the local Secure Enclave key for SSH bootstrap.
- Ready — when the prompt arrives, emits
__VMUX_MOSH_LIFECYCLE_READY__. - Send a probe token to the shell to verify round-trip output.
- Background — emits
__VMUX_MOSH_LIFECYCLE_EVENT__|event=backgroundwhen the app goes to the background. - Foreground — emits
__VMUX_MOSH_LIFECYCLE_EVENT__|event=foregroundand replays a resume probe. - Verdict — after a 2 s settle, the run exits with
__VMUX_MOSH_AUTORUN_END__|verdict=passedorverdict=failed.
This is purely a test harness. You do not need to do anything with it during normal use, and it is not exposed in the UI. The corresponding Mosh diagnostics page is the user-facing diagnostic surface.
When Mosh is the wrong choice
Pick SSH instead of Mosh when:
- You need port forwarding (Mosh does not support it).
- The remote network blocks all outbound UDP.
- The remote host is missing
mosh-serverand you cannot install it. - You are on a stable, low-latency wired network and prefer simpler reconnect semantics.
For everything else, Mosh on iPhone is the better default.
Troubleshooting
"mosh-server not found on remote host"
mosh-server is missing from the remote PATH. vmuxPhone searches /usr/local/bin, /opt/homebrew/bin, /usr/bin, and /snap/bin automatically. If your install lives somewhere else, set the mosh-server command field on the host to the full path.
"Mosh bootstrap failed"
The SSH bootstrap connected but mosh-server did not respond as expected. The most common cause is a missing UTF-8 locale on the remote host — Mosh requires UTF-8. Run locale -a | grep -i utf on the remote and install one if nothing shows up.
Frequent disconnects during a long run
iOS evicted the app at some point. Make sure you have notifications enabled (so you see the disconnect alert), and consider switching to a paid Always-Allow background task entitlement if you ship a fork of vmux. The default entitlement gives you a normal grace window only.
UDP traffic blocked
If your network blocks outbound UDP, Mosh cannot work. Switch to SSH for that network. Some carrier networks block UDP on common Mosh ports (60000 – 61000) — try setting an explicit port in the UDP port or range field that the carrier permits.
Related
- Mosh connections — protocol-level reference shared with the visionOS docs.
- Mosh diagnostics — diagnostic surface and resolved-paths report.
- Live Activities — session status on the Lock Screen.