Everything this product does begins with one unglamorous capability: convincing an iPhone to hand over a full backup, over a cable or Wi-Fi, to an app Apple has never heard of. There is no public API for that. There is a protocol, a daemon, and a superb open-source project, and this chapter is about standing respectfully on all three, plus the two production incidents that taught us how to ship a Python sidecar responsibly.
The stack under the cable
When an iPhone talks to a computer, Apple's usbmuxd daemon owns the conversation: it multiplexes connections to the device over USB (and, once a device is paired, over Wi-Fi). Speak its protocol and you can request the same services iTunes used: pairing, and crucially the full-backup service. We do not speak it ourselves; we bundle pymobiledevice3, the open-source Python implementation of these protocols, as a frozen sidecar process our Rust backend drives. The user experience on top is deliberately thin: plug in, tap Trust on the phone, click Back Up. Device discovery is push-based, subscribed to usbmuxd's own event stream, so a phone appears the moment the OS sees it rather than on a polling timer.
Shipping Python without shipping pain
Bundling a Python application inside a desktop app is a solved problem with sharp edges. Two of them cost us real releases:
- Single-file freezing is a tax on every spawn. PyInstaller's one-file mode self-extracts its whole bundle on every launch: our sidecar took about 6 seconds to answer anything. Switching to a directory bundle took spawns to about a quarter second. If your sidecar is chatty, the convenient packaging mode is the wrong one.
- Never resolve dependencies at release time. For six releases, our build froze the sidecar fresh from the package index, until a transitive dependency shift quietly broke Windows backups. Worse, the failure was invisible: the tool exited zero on error. The fix is structural, not a pin: sidecars are now built once per platform from locked requirements, self-validated (including the exact command that would have caught the breakage), uploaded as a hashed artifact, and releases download and verify those bytes. A release can no longer be affected by the package ecosystem having a bad day.
macOS notarization added its own hazing: a directory bundle ships more than a hundred Mach-O binaries carrying PyInstaller's ad-hoc signatures, and Apple rejects every one. The release script re-signs the whole tree with the hardened runtime before building, and verifies it, so a signing gap fails in seconds locally instead of ten minutes into a notarization round trip.
Being a good guest in someone else's project
Two obligations come with building a commercial product on a GPL-licensed tool, and both are handled the boring, correct way. Compliance: the sidecar runs as a separate process spoken to over its CLI, our code is not a derivative work, and we publish the corresponding source for exactly what we ship. Citizenship: when we hit a real bug in the backup path, we carried a patch only as long as it took to upstream the fix, and deleted our fork the day a release included it. The project is excellent; the least a commercial guest can do is file good bugs and leave the campsite cleaner.
The payoff for all this plumbing shows up elsewhere in the series: the backup this chapter obtains is the artifact the next chapter reads, and getting the same daemon reachable from inside the Microsoft Store sandbox was its own adventure.