iOS Device Toolkit
Drive a physical iOS device over USB with pymobiledevice3. This skill covers the high-value workflows; deep reference per area is in references/.
- Capture, logs, crashes →
references/capture.md
- Apps, app sandbox files, AFC media, debugserver →
references/apps-files.md
- Device info, perf, springboard, webinspector, tunneling →
references/diagnostics-perf.md
Install
# uv (preferred) or pipx
uv tool install pymobiledevice3
pipx install pymobiledevice3
pymobiledevice3 version # confirm; tested at 7.0.7
Prerequisites
- Physical iOS device attached via USB (or Wi-Fi-paired through usbmuxd).
- Developer Mode enabled on device (Settings → Privacy & Security → Developer Mode). Verify with
pymobiledevice3 mounter query-developer-mode-status.
- Trusted computer — accept "Trust This Computer" prompt on the device after first connect.
- iOS 17+ only: a long-running
tunneld daemon is required for any developer-mode service (screenshots, DVT instruments, debugserver, pcap-with-process, etc.). Start it once per boot:sudo pymobiledevice3 remote tunneld
The CLI auto-retries developer commands through tunneld; you no longer need --tunnel "" on every call in 7.x, though it still works.
Device selection
For a single attached device, no flag is needed. For multiple, scope every call with one of:
--udid <UDID> — usbmux-discovered device
--tunnel <UDID> — tunneld-discovered device (developer services on iOS 17+)
PYMOBILEDEVICE3_UDID=<UDID> / PYMOBILEDEVICE3_TUNNEL=<UDID> env vars — set once, all subsequent invocations inherit
Discover UDIDs:
pymobiledevice3 usbmux list # USB + Wi-Fi devices known to usbmuxd
xcrun devicectl list devices # Apple's own listing (macOS)
pymobiledevice3 lockdown info | head # full lockdown dump for the default device
Caveat: --tunnel "" (empty string) prompts interactively. In non-interactive shells, pass the UDID directly.
Quick reference
# --- Device info ---
pymobiledevice3 usbmux list
pymobiledevice3 lockdown info
pymobiledevice3 diagnostics battery
pymobiledevice3 mounter list
# --- Capture ---
# Screenshot (iOS 17+, DVT path — works where the deprecated developer screenshot fails)
pymobiledevice3 developer dvt screenshot ~/Desktop/shot.png
# Live syslog
pymobiledevice3 syslog live
# Crash reports
pymobiledevice3 crash ls
pymobiledevice3 crash pull ~/ios-crashes
# Packet capture (filter by process is optional)
pymobiledevice3 pcap --out trace.pcap --process Safari
# --- Apps ---
pymobiledevice3 apps list --user # only user-installed
pymobiledevice3 apps install ./MyApp.ipa
pymobiledevice3 apps uninstall com.example.MyApp
pymobiledevice3 developer dvt launch com.example.MyApp
pymobiledevice3 developer dvt process-id-for-bundle-id com.example.MyApp
pymobiledevice3 developer dvt kill <PID>
# --- Files (app sandbox + media) ---
pymobiledevice3 apps pull com.example.MyApp Documents/log.txt ./log.txt
pymobiledevice3 apps push com.example.MyApp ./seed.json Documents/seed.json
pymobiledevice3 afc pull DCIM/100APPLE/IMG_0001.HEIC ./
pymobiledevice3 afc ls -r DCIM
# --- Perf ---
pymobiledevice3 developer dvt sysmon system # one-shot system stats
pymobiledevice3 developer dvt sysmon process # per-process loop
pymobiledevice3 developer dvt proclist # PID + start times
pymobiledevice3 developer dvt energy <PID> [<PID>...]
# --- Networking / port forwarding ---
pymobiledevice3 usbmux forward 8080 8080 # local:8080 -> device:8080
pymobiledevice3 webinspector opened-tabs # requires Safari Web Inspector enabled on device
pymobiledevice3 webinspector cdp # CDP server for WebView debugging
Common gotchas
- "InvalidServiceError" / "Failed to start service" on iOS 17+ → tunneld is not running. Start
sudo pymobiledevice3 remote tunneld and retry. Confirm with ps aux | grep tunneld.
- "DeveloperDiskImage not mounted" →
pymobiledevice3 mounter auto-mount.
- Deprecated screenshot API hangs on iOS 17+ → use the DVT variant:
developer dvt screenshot (not developer screenshot).
--tunnel "" hangs in scripts → empty string means interactive picker; pass the UDID explicitly.
- Permissions on Linux → usbmuxd typically needs to be running; on macOS it's built in.
- Pairing lost after iOS update →
pymobiledevice3 lockdown unpair && pymobiledevice3 lockdown pair.
Scripting tips
- Set
PYMOBILEDEVICE3_UDID (and PYMOBILEDEVICE3_TUNNEL for developer services) once at the top of a script to avoid repeating flags.
- For capture-and-open recipes (screenshot +
open, syslog tail + grep, etc.), wrap in a shell function rather than re-typing the full path each time.
- Most subcommands accept
--rsd HOST PORT as an alternative to --tunnel, useful when you already have an RSD address from a manual pymobiledevice3 remote start-tunnel.
1---2name: ios-device-toolkit3description: Use when interacting with USB-attached iOS devices via pymobiledevice3 — screenshots, syslog, crash reports, app install/launch/pull, file transfer, sysmon perf, TCP port forwarding, WebInspector/CDP, and device diagnostics.4---5
6# iOS Device Toolkit
7
8Drive a physical iOS device over USB with `pymobiledevice3`. This skill covers the high-value workflows; deep reference per area is in `references/`.
9
10- Capture, logs, crashes → `references/capture.md`
11- Apps, app sandbox files, AFC media, debugserver → `references/apps-files.md`
12- Device info, perf, springboard, webinspector, tunneling → `references/diagnostics-perf.md`
13
14## Install
15
16```bash
17# uv (preferred) or pipx
18uv tool install pymobiledevice3
19pipx install pymobiledevice3
20
21pymobiledevice3 version # confirm; tested at 7.0.7
22```
23
24## Prerequisites
25
261. **Physical iOS device** attached via USB (or Wi-Fi-paired through usbmuxd).
272. **Developer Mode** enabled on device (Settings → Privacy & Security → Developer Mode). Verify with `pymobiledevice3 mounter query-developer-mode-status`.
283. **Trusted** computer — accept "Trust This Computer" prompt on the device after first connect.
294. **iOS 17+ only**: a long-running `tunneld` daemon is required for any developer-mode service (screenshots, DVT instruments, debugserver, pcap-with-process, etc.). Start it once per boot:
30 ```bash
31 sudo pymobiledevice3 remote tunneld
32 ```
33 The CLI auto-retries developer commands through tunneld; you no longer need `--tunnel ""` on every call in 7.x, though it still works.
34
35## Device selection
36
37For a single attached device, no flag is needed. For multiple, scope every call with one of:
38
39- `--udid <UDID>` — usbmux-discovered device
40- `--tunnel <UDID>` — tunneld-discovered device (developer services on iOS 17+)
41- `PYMOBILEDEVICE3_UDID=<UDID>` / `PYMOBILEDEVICE3_TUNNEL=<UDID>` env vars — set once, all subsequent invocations inherit
42
43Discover UDIDs:
44
45```bash
46pymobiledevice3 usbmux list # USB + Wi-Fi devices known to usbmuxd
47xcrun devicectl list devices # Apple's own listing (macOS)
48pymobiledevice3 lockdown info | head # full lockdown dump for the default device
49```
50
51Caveat: `--tunnel ""` (empty string) prompts interactively. In non-interactive shells, pass the UDID directly.
52
53## Quick reference
54
55```bash
56# --- Device info ---
57pymobiledevice3 usbmux list
58pymobiledevice3 lockdown info
59pymobiledevice3 diagnostics battery
60pymobiledevice3 mounter list
61
62# --- Capture ---
63# Screenshot (iOS 17+, DVT path — works where the deprecated developer screenshot fails)
64pymobiledevice3 developer dvt screenshot ~/Desktop/shot.png
65# Live syslog
66pymobiledevice3 syslog live
67# Crash reports
68pymobiledevice3 crash ls
69pymobiledevice3 crash pull ~/ios-crashes
70# Packet capture (filter by process is optional)
71pymobiledevice3 pcap --out trace.pcap --process Safari
72
73# --- Apps ---
74pymobiledevice3 apps list --user # only user-installed
75pymobiledevice3 apps install ./MyApp.ipa
76pymobiledevice3 apps uninstall com.example.MyApp
77pymobiledevice3 developer dvt launch com.example.MyApp
78pymobiledevice3 developer dvt process-id-for-bundle-id com.example.MyApp
79pymobiledevice3 developer dvt kill <PID>
80
81# --- Files (app sandbox + media) ---
82pymobiledevice3 apps pull com.example.MyApp Documents/log.txt ./log.txt
83pymobiledevice3 apps push com.example.MyApp ./seed.json Documents/seed.json
84pymobiledevice3 afc pull DCIM/100APPLE/IMG_0001.HEIC ./
85pymobiledevice3 afc ls -r DCIM
86
87# --- Perf ---
88pymobiledevice3 developer dvt sysmon system # one-shot system stats
89pymobiledevice3 developer dvt sysmon process # per-process loop
90pymobiledevice3 developer dvt proclist # PID + start times
91pymobiledevice3 developer dvt energy <PID> [<PID>...]
92
93# --- Networking / port forwarding ---
94pymobiledevice3 usbmux forward 8080 8080 # local:8080 -> device:8080
95pymobiledevice3 webinspector opened-tabs # requires Safari Web Inspector enabled on device
96pymobiledevice3 webinspector cdp # CDP server for WebView debugging
97```
98
99## Common gotchas
100
101- **"InvalidServiceError" / "Failed to start service" on iOS 17+** → tunneld is not running. Start `sudo pymobiledevice3 remote tunneld` and retry. Confirm with `ps aux | grep tunneld`.
102- **"DeveloperDiskImage not mounted"** → `pymobiledevice3 mounter auto-mount`.
103- **Deprecated screenshot API hangs on iOS 17+** → use the DVT variant: `developer dvt screenshot` (not `developer screenshot`).
104- **`--tunnel ""` hangs in scripts** → empty string means interactive picker; pass the UDID explicitly.
105- **Permissions on Linux** → usbmuxd typically needs to be running; on macOS it's built in.
106- **Pairing lost after iOS update** → `pymobiledevice3 lockdown unpair && pymobiledevice3 lockdown pair`.
107
108## Scripting tips
109
110- Set `PYMOBILEDEVICE3_UDID` (and `PYMOBILEDEVICE3_TUNNEL` for developer services) once at the top of a script to avoid repeating flags.
111- For capture-and-open recipes (screenshot + `open`, syslog tail + `grep`, etc.), wrap in a shell function rather than re-typing the full path each time.
112- Most subcommands accept `--rsd HOST PORT` as an alternative to `--tunnel`, useful when you already have an RSD address from a manual `pymobiledevice3 remote start-tunnel`.