Skip to content

ADR-0005 — Phase D backend is Go only; no new production Python

Status

accepted

Context

ADR-0004 committed Stage 2 to Option δ: a local shim backend that CoreDeviceService's pair-flow nw_connection is redirected to. That shim has to speak the exact RemoteXPC protocol CDS expects on the client side, and drive pymobiledevice3 on the server side to translate between CDS's view and the real iPhone over the tunnel.

When Phase C of Stage 2 finished and the shim became a concrete implementation task, the first technically plausible path was to reuse pymobiledevice3's own Python h2 / RemoteXPC codecs on the shim side and embed the shim as another long-lived Python process. That would have been the shortest path from "we know the protocol" to "we have a working shim".

The reasons not to do that:

  • iosmux is a Go project. CLAUDE.md opens with **Language:** Go 1.26+. Every production component except the pymobiledevice3 remote tunneld subprocess is Go. Introducing a second long-lived Python component doubles the Python surface we will later have to remove.
  • Removal debt compounds. ADR-0003's pymobiledevice3 patch overlay exists specifically to keep Python as a temporary dependency. A new production Python component works against that plan.
  • Deployment cost. Every new Python dependency means a new piece of the embedded virtualenv, a new surface for version drift, a new thing the installer has to idempotently set up.
  • The protocol is not complex enough to warrant Python. Phase C's self-experiment confirmed the CDS-facing transport is plain prior-knowledge HTTP/2 cleartext with RemoteXPC DATA frames. golang.org/x/net/http2.Framer speaks h2 directly, and porting pymobiledevice3's XpcWrapper / XpcPayload codec to Go is a few hundred lines of mechanical translation with pymobiledevice3 as the reference implementation.

Decision

All new Phase D backend code is Go. The shim lives under cmd/iosmux-backend/ and uses:

  • golang.org/x/net/http2 for h2c (the Framer interface, because RemoteXPC does not fit net/http.Handler semantics)
  • A hand-written XpcWrapper / XpcPayload codec ported from pymobiledevice3's remote/xpc_message.py as reference
  • howett.net/plist for bplist decoding (extended if bplist16 is not already covered)

Python is confined to the existing pymobiledevice3 remote tunneld subprocess, talked to over its HTTP API on loopback exactly as today. No new long-lived Python processes are introduced by Stage 2 or Phase D.

Consequences

Wanted:

  • Production deployment stays as close to "one Go binary plus the existing tunneld subprocess" as possible.
  • Every new protocol concern goes through Go's type system and test tooling, which is what the rest of the codebase already uses.
  • The long-term goal of removing Python entirely becomes tractable: the only Python process is tunneld, and the patch overlay on pymobiledevice3 is explicitly scoped to be deleted.

Accepted as cost:

  • Porting pymobiledevice3's XpcWrapper / XpcPayload / bplist16 logic to Go is work we could have avoided by reusing the Python implementation. We accept this cost because it is one-time and produces a testable Go library, whereas the alternative is permanent.
  • If pymobiledevice3 fixes a protocol bug upstream, we do not get it automatically in the shim — we have to re-port the fix. We mitigate this by keeping the Go codec's structure close to the Python original and citing the source file + line range in every translated function.

Evidence

  • CLAUDE.md**Language:** Go 1.26+
  • CLAUDE.md → "Key Decisions: go-ios REJECTED ... → pymobiledevice3 tunneld as subprocess" (emphasis on "as subprocess", not "as library")
  • research/protocol/s2c-self-experiment/FINDINGS.md — confirms the CDS-facing transport is plain h2c, so net/http2 is sufficient.
  • plans/stage2.md → "Phase D — Principle: new code is Go, Python stays where it already is" section.

References

  • ADR-0001 — why we use pymobiledevice3 at all.
  • ADR-0003 — why the Python dependency is explicitly temporary.
  • ADR-0004 — the shim that this ADR decides the implementation language for.