Update for Skyflo 1.5. Since Skyflo 1.5, a mission can also run in Skyflo Cloud, on a machine Skyflo operates for it, and a paired phone can follow it there. For such a mission the executor is that machine rather than your Mac; The Mission Outlives the Laptop explains what that machine holds, why it holds no provider or GitHub credential, and how it hands the mission back. The essay below is kept as written.
The Question That Waits for You
A mission that runs for forty minutes will usually stop at least once to ask something. Which cutover should the migration use. Should the retry keep the old lock as a fallback. May it run the deploy script against production.
Until now the answer had to come from the Mac. If you had walked away, the mission waited, correctly, because an engineering harness that guesses when it should ask is worse than one that waits. But a harness that waits for an hour because its person is in a meeting has turned a good rule into a slow product.
Skyflo 1.3 lets a phone take that moment. Pair an iPhone or iPad in Settings, Devices, and the phone shows your missions as they run, notifies you when one needs you, and lets you answer, send guidance, stop a mission, start one, or approve or decline an action. The phone app itself is in testing and reaches the App Store after Apple's review; the Mac side ships today.
That sentence describes a remote control, and remote controls are easy to build badly. The rest of this post is about the one decision that kept it from being one.
The Phone Never Runs Anything
Skyflo's executor is your Mac. The daemon there holds the missions, the worktrees, the terminal, the agents and their credentials, and it is the only thing that ever acts. We kept it that way. The phone runs no agent, holds no repository, calls no model provider, and has no path to a shell.
So the phone does not send actions. It sends decisions, and every one of them goes to the Mac to be checked before anything happens.
That constraint is what made the rest tractable. A phone is lost, borrowed, left unlocked on a table. If the phone could act, every one of those would be an incident. Because it can only ask the Mac, the worst a stolen phone can do is ask, and the Mac has to agree.
What a Decision Carries
Every request the phone sends is signed with a key the phone created when it was paired. The private half never leaves the device; where the hardware has a Secure Enclave, it lives there. The Mac learned the public half at pairing, when you typed the phone's code into Settings, Devices and confirmed it was the phone in your hand.
What gets signed matters more than the fact of signing. Each kind of request has a fixed binding: the kind of decision, the mission, and the exact thing being decided, in a fixed order with a separator no field can contain. An answer binds the question and a hash of your text. Guidance binds the mission and a hash of the instruction. An approval binds the gate, and for an action Skyflo prepared, the gate's own binding hash: a hash of the exact operation, its normalized inputs, the resource and environment it targets, and the most it is allowed to cost.
That last one is the whole point. You do not approve "the deploy". You approve that command, with those arguments, against those paths. If the agent changes a single argument after you looked, the binding no longer matches, the Mac refuses the approval, and the phone tells you the request changed instead of approving something you never saw. Consequential actions also ask for Face ID or Touch ID before the phone will sign at all, and the device passcode is not accepted in their place.
Getting There Exactly Once
The account service sits between the phone and the Mac, because a phone on cellular and a Mac behind a home router cannot reach each other directly. It stores a request until the Mac collects it, and it is not trusted to decide anything. It cannot forge a signature it never held, and the Mac verifies each request against the phone's own key.
Networks lose responses, and a decision is exactly the kind of thing you must not send twice. So the phone writes each request to its own storage before sending it, under an identity chosen once. If the response is lost, the phone asks about that identity instead of sending a fresh request, and the account service accepts each identity only once. A request nobody collected in time expires, and the phone says so, rather than leaving you unsure whether your approval ran.
What Leaves Your Mac, and What Does Not
A phone has to show you something, so some of your missions do leave the Mac once a phone is paired. We kept that as narrow as the phone's job.
For every mission, the Mac shares its title, its status, its repository and branch, and which agents are working. For a mission you open on the phone, or one waiting for you, it also shares the conversation: your instructions, the agents' replies, the steps they took with short summaries of their results, and whatever question or approval is waiting. Each reply is capped, only the recent turns travel, and process output, terminal sessions, browser pages and images never do.
With no phone paired, the Mac shares none of it. Those copies are deleted thirty days after they last changed and a week after a mission is archived, unpairing a phone deletes what was waiting for it, and deleting your account deletes all of it.
Where It Stands
The Mac side of this is in Skyflo 1.3 today, and the account service that carries it is live. The phone app is in testing and goes to App Review next; until it is on the App Store, Settings, Devices shows the pairing flow but there is no public app to pair. Before the phone app goes to review, we run that whole loop on our own phones against production: pairing, notifications, answers, guidance and Face ID approvals. Everything else in the release is in the 1.3.0 release notes.
The idea underneath it is the same one the rest of Skyflo is built on. The harness owns the work, holds the authority, and records what happened. A new surface can make that faster to reach. It does not get to change who is allowed to act.