ADR-0001 — Use pymobiledevice3, not go-ios¶
Status¶
accepted
Context¶
iosmux is a Go daemon that has to talk to iOS 17+ devices over the new lockdown tunnel protocol. At project kickoff there were two open-source stacks that spoke that protocol end-to-end:
- go-ios — idiomatic Go, single binary, no external runtime dependencies.
- pymobiledevice3 — Python, actively maintained by the reverse-engineering researcher who first published the iOS 17+ tunnel protocol.
A Go project talking to a Python library requires a subprocess + loopback HTTP bridge, which is a real cost. Go-ios would have let us stay in-process.
We ran pre-project research on both stacks against an iOS 17 and an iOS 18 device. The deciding observation was that go-ios was lagging the protocol changes badly — iOS 17.4 and later would not reliably complete the lockdown tunnel handshake, and the maintainers had open issues for weeks without progress. pymobiledevice3, by contrast, shipped iOS 18.x support the same week Apple released the beta.
Decision¶
Use pymobiledevice3 remote tunneld as a subprocess. iosmux
launches and supervises it on a known loopback port and talks to it
over its HTTP API. We accept the two-runtime architecture as the
cost of being protocol-correct on current and near-future iOS.
The subprocess is bundled with iosmux via an embedded virtualenv — end users never interact with Python directly.
Consequences¶
Wanted:
- Protocol correctness that tracks upstream iOS releases without us having to reverse-engineer the tunnel ourselves.
- pymobiledevice3's maintainer is the person actually pushing iOS protocol research forward; we inherit that for free.
Accepted as cost:
- Two-runtime deployment. The installer has to carry a Python interpreter plus a virtualenv. Startup time is measurably longer than a single Go binary would have been.
- An HTTP bridge on loopback for every call that would otherwise be a function call. Latency is fine for control-plane operations; data-plane work stays in Go.
- A long-term plan to eventually rewrite the tunnel client in Go is not off the table, but it is explicitly out of scope for now and requires its own ADR.
Evidence¶
CLAUDE.md→ "Key Decisions: go-ios REJECTED (unstable iOS 18+) → pymobiledevice3 tunneld as subprocess"- Pre-project research notes in
memory/research_findings.md - go-ios issue tracker — iOS 17.4+ regressions open at project kickoff
- pymobiledevice3 release notes — prompt iOS 18 beta support