Skip to content

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

References

  • ADR-0002 — where tunneld runs.
  • ADR-0003 — how we maintain local changes to pymobiledevice3.
  • ADR-0005 — the rule that contains Python to this single subprocess and forbids new long-lived Python elsewhere.