← Blog Mobile 17 September 2026 9 min read

Your agents, from your phone.

Everyone wants to check on a running agent from the couch. The hard part is not the screen. It is keeping two devices in step over a connection that comes and goes. Here is how Luminair's mobile relay does it, and what we had to rebuild to get there.

Fig 01  Two paths between phone and MacSchematic
YOUR PHONE You “Run the tests.” Live from the Mac OFFLINE OUTBOX Saved on the phone first, sent when the connection returns INSTANT PATH · SINCE 6 SEP Account room One persistent socket per account, shared by the Mac and every phone DURABLE PATH · THE RECORD AND THE FALLBACK Prompt inbox phone writes, Mac reads · Mac polls every 5 s, deletes what it runs Live event log Mac writes, phone reads · ordered, append-only e/1 e/2 e/3 e/4 YOUR MAC Luminair Runs the turn on your real files Mirrors every relayed run in the desktop app Beats a presence heartbeat every 5 to 10 s
A schematic of desktop/main.js and the phone app's sync code. When the socket is down, the dashed durable path carries everything on its own, only slower.

The short version

  1. Think of the relay as a walkie-talkie with a notebook. The walkie-talkie (a live socket) is instant when both ends have signal. The notebook (cloud documents) remembers everything, so nothing is lost when they do not.
  2. Your phone sends a prompt; your Mac runs it on your real files and streams the output back. The run is mirrored in the desktop app, so nothing happens off the record.
  3. The first versions sent whole snapshots and the phone's text could rewind mid-word. On 1 August the live mirror became an ordered, append-only event log.
  4. Luminair tells three kinds of offline apart (your phone, your Mac, your Mac's internet), and an outbox on the phone holds prompts until they can be delivered.
02Built with Luminair

Tested from the couch.

Luminair is built inside Luminair, and a good part of that work is steered from a phone. That is how most relay bugs were found: a reply that stopped halfway, a prompt that ran twice, a Mac marked offline while it was clearly working. The sync code is full of dated notes about each one, and the fixes carry a Claude co-author line in git. The dates in this post come from those notes and commits.

Luminair · the desktop side of a relayed run
Luminair desktop app in the light theme: a folder sidebar and three chat sessions side by side
The Mac is where the work happens. A turn sent from the phone shows up here as it runs, in the same session. (Demo workspace.)
03Agents on a phone

Not a smaller terminal.

In March, Builder.io surveyed the ways to run Claude Code from a phone: SSH over a private network, companion apps, cloud containers, and Anthropic's own Remote Control, which shipped on 25 February 2026. The article is blunt about the oldest route: “SSH drops the moment your phone sleeps or hops from WiFi to cellular.”

Remote Control solved much of that. You scan a code and continue a local session from the Claude app. At launch it was a Max-only research preview; Anthropic's docs now list Pro, Max, Team and Enterprise, and promise that “if your laptop sleeps or your network drops, Claude Code reconnects automatically when your machine comes back online.”

Builder's own conclusion is the useful part: what people want from a phone is to check on long-running work and kick off new work. “These aren't terminal problems. These are orchestration problems.” We agree with the diagnosis. Our answer is different from theirs: keep the agent on your own Mac, next to your files, and make the link to the phone dependable.

The screen is the easy part. The hard part is two devices agreeing on what happened while one of them was in a tunnel.
04The relay

A prompt's round trip.

You link the Luminair app on your phone to your Mac once, with a one-time code from the desktop settings. After that, a message you send from the phone makes this trip:

01

The phone writes it down

The prompt goes into a cloud inbox for your account. If the account room is connected, the same prompt is pushed down the socket at once, so the Mac does not have to wait for its next look.

02

The Mac picks it up

The Mac checks the inbox every five seconds as a fallback. Whichever path arrives first wins; the prompt runs once, on the Mac, with the session's engine and its real file tools.

03

The output streams back

Live output goes out over the socket and into the durable event log. The desktop mirrors the run in the same session, so when you sit down you can scroll through what happened.

04

“Done” must land

The final write is retried, up to four times, because it is the one that tells the phone the turn is over. A single lost “done” once left the phone waiting about 90 seconds, deciding the Mac had gone quiet, and queuing a finished turn again (2 August).

The account room is the newest layer. Since 6 September each signed-in account has one persistent socket, shared by the Mac and every phone. The Mac publishes on it everything the phone used to poll for, and receives prompts the instant they are sent. The code is explicit that the cloud documents “stay the durable record and the fallback when the socket is down”. The socket makes things fast; the documents make them safe.

05The rewrite

From snapshots to a log.

The first live mirror was simple. As a turn streamed, the Mac rewrote one cloud document holding the whole reply so far, and the phone showed whatever it last read. That works until two writes cross in flight. The phone could receive an older snapshot after a newer one, and the text on screen would jump backwards, sometimes mid-word.

Fig 02  Why the phone's text rewoundSchematic
Before ONE SNAPSHOT DOC “Running the te” “Running the tests…” slow write lands last PHONE SHOWS Running the tests… Running the te After SINCE 1 AUG e/41 e/42 e/43 e/44 missing? fetch it first PHONE APPLIES IN ORDER Running the tests… Each event is only the change since the last one. The id is its number, so writing it twice is harmless.
Not to scale. The rule is real: events live at numbered documents under the session, written by one writer (the Mac), applied by number rather than by arrival order. The commit of 1 August calls it the “root-fix for the mobile mirror rewinding mid-word”.

The rewrite, on 1 August, kept the snapshot for older phones but added an append-only event log beside it. Every live write now also records just the change since the last one, as an immutable document numbered in order. The phone reads the log incrementally and fills any gap before it moves on.

A fix the same day closed the other half. If a write to the log failed, the Mac used to announce that number anyway, so the phone moved past a document that did not exist and was left with a permanent hole. Now the log write is retried, and the push only goes out once the write is confirmed.

A research note written a few days later, before the next layer was added, looked back at three earlier relay generations and wrote down the rules they had paid for. Three of them explain most of what you have read so far:

  • One writer per session stream: the Mac, so there is never a fight over numbering.
  • Order by position, never by network arrival: that was the rewind bug.
  • Push never leads the durable write: that was the hole bug.
06Three kinds of offline

Whose connection died?

“Offline” sounds like one state. On a relay it is at least three, and blaming the wrong device is its own bug. Luminair checks each one separately.

Fig 03  Three failures, three different messagesFrom the code
What is downHow Luminair noticesWhat you see
Your phoneThe phone cannot reach the cloud at all, or the system reports no network.The phone says it is the one offline, instead of blaming the Mac. New prompts wait in the outbox.
Your MacThe Mac's presence stamp stops changing. The phone judges this by its own clock: no change for 25 seconds means offline. One missed check is forgiven.The Mac shows as offline on the phone.
Your Mac's internetThe Mac's five-second inbox check is also its heartbeat to the internet. A streak of network failures there marks the Mac as offline since the first one.“This Mac has had no internet since 14:02. Codex could not reach its server. Reconnect and send again.”
Summarised from the phone app's presence code and desktop/main.js. The quoted message is the real template from desktop/engines/runner-cli.js, with an example time and engine filled in.

The second row hides a subtle fix. The phone used to compare the Mac's clock with its own. A few seconds of clock drift made the status flicker, and more than 15 seconds of drift showed a live Mac as permanently offline. Now the phone only asks whether the stamp has changed recently by its own clock, which clock drift cannot fool.

The third row came from a bad afternoon on 17 September. For 18 minutes the Mac had no internet. Claude said there was no response from the API, Codex timed out, Antigravity streamed nothing, and Google's client said it was not logged in. Five messages, one cause, and none of them said “offline”. Now, when the app's own connection checks are failing, the error says so. A usage limit or a broken sign-in is still reported as itself, because those are not the network.

07The outbox

Write now, send later.

The last piece lives on the phone. Since 23 July, anything you queue on the phone is written to the phone's own storage first, marked as not yet confirmed, and only then sent to the cloud queue your Mac drains. The storage survives the app being closed and airplane mode.

When the connection returns, the phone flushes every session with unsent items, and it also retries every 15 seconds while the app is open. It never simply overwrites the cloud queue. It pulls the current queue, merges its own items in, and pushes the result, so a batch written in a tunnel cannot wipe out items the Mac already ran while you were away.

Two small ledgers make that safe. One remembers, for seven days, the ids of items the phone already ran, so a Mac that wakes up hours later and mirrors a stale copy back cannot make an old request run twice. The other remembers deletions for a day, so something you removed offline does not come back when you reconnect.

08Find it in the app

Link a phone in a minute.

  1. 1On the Mac, open Settings › Mobile relay. Under Pair a phone, create a code. It works once and expires after 10 minutes.
  2. 2Type the code into the Luminair app on your phone. The phone appears under Connected devices, where you can unlink it later.
  3. 3Under This computer, keep Accept work from other devices on. Turn on Protected Mode for turns from other devices if you want relayed turns kept inside the session's folder, so a lost phone cannot reach the rest of the Mac.

The Mobile relay page is part of the Pro+ plan.

09Honest limits

What the relay can't do.

Worth knowing

  • Your Mac has to be on, awake and running Luminair. The phone is a remote for your Mac, not a cloud machine. A Wake from phone option can reopen Luminair after a crash, but it cannot power on a Mac that is off.
  • The outbox can only deliver once both the phone and the cloud are reachable, and the Mac only runs it once it is back.
  • A socket is fast but fragile; when it drops, the five-second inbox check takes over, so replies feel slower until it reconnects.
  • We have not published delivery-time measurements for the relay.

Sources

Steer your Mac from anywhere

Link your phone once, and keep your agents moving from the couch, the train or the queue for coffee.

Download Luminair →