RemoteDeploy: An iPhone Install in Ten Seconds
Published by Dan Richardson at https://freepdx.com/deep-dives/remotedeploy
- Status
- Production
The Problem
Getting a fresh build onto a physical iPhone is slow. When you’re rapidly iterating and want to get builds onto hardware to test cameras and image processing pipelines, speed and flexibility in deployment is key. TestFlight runs 15 to 30 minutes per upload, USB means physically holding the device, and Xcode wireless debugging needs both machines on the same network. I wanted a use a local desktop to build my app, but deploy on my phone in seconds, from anywhere. What would it take to do that?
What I Built
An open-source (MIT) macOS menu-bar app - no dock icon, no main window - that wraps xcodebuild to archive and export with ad-hoc signing, then serves the IPA over HTTPS using SwiftNIO.
I designed the architecture and wrote a 697-line implementation specification on March 30, 2026: decisions up front, explicit boundaries, and a list of commandments that read like scar tissue from past projects. I then used agent-assisted delivery to implement, review, test, package, and release the first version in one day across about thirty commits. It went open-source the next day with a README, an app icon, and a signed DMG.
Four days after launch, v2.0 added an iOS companion app, a 20-endpoint REST API, and a progressive web app, with QR-code pairing and Bonjour discovery. From there it grew ticket by ticket: live build-log streaming over WebSocket, Expo and React Native support behind a BuildEngineRouter abstraction, macOS self-deploy (RemoteDeploy deploys itself - quits the running binary, swaps the bundle, relaunches via a trampoline script), auto-renewing Tailscale TLS certificates, push notifications through Prowl, Pushover, or ntfy, and IPA import for pre-built binaries.
Tech Stack
- Swift
- TypeScript (Copilot Auto-Keep)
- SwiftUI
- SwiftNIO
- Tailscale (secure tunnel + TLS)
- Bonjour / mDNS
- LaunchAgent auto-start
- NIOSSL
- XcodeGen
- Swift Package Manager
- os.Logger
- VS Code Extension API
How It Works
Every major component is a Swift protocol with a concrete implementation - BuildEngineProtocol, DeployServerProtocol, TailscaleProviderProtocol, CertificateProviding, and about eight more - so the codebase is testable and extensible without touching existing code. It ships as four targets: the menu-bar host, a headless SwiftNIO server in its own process, the iOS companion, and a shared Swift package for models and API types.
The REST API covers the full surface: project CRUD, build trigger and cancel, build and install history, settings, filesystem browsing for project discovery, device pairing and revocation, plus the WebSocket for real-time logs. Auth is bearer tokens stored in the iOS Keychain and hashed with SHA-256 server-side, so the raw token never touches disk on the Mac. A deploy.sh installer builds the release .app, installs to /Applications, and configures a LaunchAgent for auto-start and crash recovery, with no runtime dependency on Xcode or the source tree.
Also in the dev-tooling bucket: Copilot Auto-Keep, a VS Code extension that auto-accepts Copilot agent edits by watching for workspace edit bursts and firing Keep All after a debounce. Same instinct - if the machine can handle it, don’t make me click.
What Made It Hard
Signing and serving an installable IPA correctly, over the air. Streaming build logs live over WebSocket to the phone and the PWA. And keeping the design clean as the surface grew - the protocol-oriented Swift 6 architecture is what let v2.0 bolt on a companion app, a full API, and self-deploy without rewrites.
The Throughline
RemoteDeploy is what happens when I hit a friction point and build through it rather than around it. I asked the right questions, wrote a spec sharp enough to build from, shipped it in a day, and then hardened it in public - the same pattern behind Rejog Stash, whose native iOS build is exactly the kind of app this exists to get onto a phone in a few seconds.
Status
Shipped and open-source, still maintained. The repo sits at roughly 330 commits and 217 Swift files across four targets. It went MIT the day after launch, and the living day-one spec is still updated as decisions get made. Code at github.com/ThroughlineTech/mac-remote-deploy.