--- name: iphone-use-setup description: Set up PUA (Phone Use Agent): install, sign, and start the on-phone execution service on the user's own iPhone. A new chat initializes READY first by default; if the service is not started, reuse the existing config and build to start it, diagnose USB and Xcode connections, and open the phone screen side panel. Use for first-time setup, cold start, reconnecting after a disconnect, or expired signing. --- # Bring the iPhone to READY Use this plugin's MCP tools to do repeatable probing, building, starting, and connecting; do not generate a Python client on the fly in every task. When a working PUA already exists, reuse it first, and avoid rebuilding or reinstalling for every task. ## Determine the current state first When this chat has not yet obtained READY, first call `pua_ready(recover=true, screenshot=false)` to reuse the channel, and only then run the user's phone task; READY from an earlier chat or an installed plugin does not substitute for proof in the current one. When this chat is already READY and the channel has not gone stale, just continue, and do not repeat doctor, discover, build, and start for every task. For first-time setup or when READY returns a specific missing item, use `pua_doctor` and `pua_setup(action="discover")` to read Xcode, connected devices, signing, ports, and process state. With multiple iPhones, select the device the user names; if only one qualifies, use it directly. The device UDID, Team ID, logs, and signing config are stored on the user's own machine and are not written to source or Git. For normal tasks call `pua_ready(recover=true)` or omit recover to use the default true, and do not turn off recovery proactively out of precheck or caution. For read-only diagnosis or when the user explicitly forbids restarting, pass `recover=false` and keep the restriction. For routine tasks that need no screenshot you can pass `screenshot=false`; use the screenshot capability only when a screenshot is actually needed. The proof of a returned `ready=true, state="ready"` includes the PUA status, a usable session, the real foreground app, the device viewport, the unlock state, and the current observation; prepare the next step directly from the nested observation, and do not immediately repeat observe or run another round of navigation tests. If mirroring is occupying the device and the control tree is empty, the tool returns `mirroring_conflict`; exit mirroring and re-verify READY. A Runner icon, BUILD SUCCEEDED, or an open port is not enough to declare READY. READY is also tied to the phone screen side panel and opens it by default when the host supports it; to reopen the image on an existing channel use `pua_screen()`, and do not repeat READY. The preview uses a separate USB MJPEG channel (default device port 9100) and does not poll XML or screenshots; the preview being unavailable does not by itself negate control-channel READY, and does not call for a restart loop. READY proves the control channel is usable; routine app operations run optimistically by default, the observation the next step needs judges progress along the way, and only the final key result is verified explicitly. `phone_locked` automatically pauses the preview and records `device_locked`, so no explicit pause is needed. Wait for the actual unlock notice from the user and re-verify READY; on success it only lifts that same lock-screen pause, while app authentication and legacy unknown pauses stay until explicitly resumed. READY's `preview` returns the pause reason; do not treat a blank preview as a failed control channel. ## Continue initialization when the service is not started For a persistent `local.pid.0` / XCTest fault, `recover=true` can queue recovery of a service whose ownership has been verified; it does not mean first-time configuration or a cold start is completed automatically. Not-started results from READY such as `pua_unreachable`, connection refused, or `not_ready` should enter the startup branch below, and you must not just give a final answer declaring the phone task failed: 1. Call `pua_setup(action="status")`. When it returns `configured=true`, keep the existing device, signing, and port config; only with `configured=false` fill in the actually missing items per the first-time install flow in the next section. 2. Check the returned `jobs` array. If a start / recover job matching the current config / endpoint is queued or running, query that same job by its `id`; do not start again, and do not wait on an old unrelated job; when a matching fetch / build job is running, also reuse it first. `pua_setup(action="status", job_id=...)` still returns a `jobs` array, so do not assume it returns a single job. 3. `service.ready=true` means the service is probeable, but you still need a fresh READY to verify the full channel such as session / foreground / viewport. If the start job is still running and the service is usable, you can verify READY; for a recover job, verify READY once `recovery_phase="serving"` is reached, and the long-running Runner does not wait for succeeded. 4. When configured, the service is not running, and there is no matching active job, call `pua_setup(action="start")` once to reuse the valid build. Record the returned `job_id` for the new job; when `already_running=true`, record `job.id`, then query the same job. When start explicitly reports missing source, fetch; when it explicitly reports a missing valid build, expired signing, or an incompatible binary, build, then continue with start; do not fully reinstall or re-sign just because of a cold start. When a job fails, look at that job's exact log and next_steps and then handle the real missing item; do not loop on start. 5. After obtaining `ready=true`, reuse the current observation and continue the original task. Only real USB / Xcode / signing / permission blockers need corresponding handling; when the user personally must unlock, trust, sign in, or confirm, use the host question flow with "Done, continue" as the first option. When the user explicitly asks for read-only or forbids start / restart, keep the restriction and do not bypass it through initialization. When this chat already has a widget, re-running setup, starting / recovering the channel, and READY again all reuse the existing panel, and no extra `pua_screen()` call is made to open a new tab. When the user only asks to "open the widget first so I can look" and the panel is not yet open, call `pua_screen()` to open the preview and then continue initialization and the authorized task, without adding a gate that waits for approval; if the user explicitly asks to wait for confirmation first, do so. A temporarily blank preview while not started does not prove READY, and does not mean the whole task has failed. ## First-time install 1. Based on the specific missing items from doctor, guide the user to prepare a full Xcode matching their iOS, accept the first-launch license, and sign in to their own Apple Account in Xcode's account settings. Account sign-in, passwords, verification codes, and device unlock are completed by the user in the system UI; do not ask for credentials. 2. Connect the iPhone with a cable; on first pairing tap "Trust This Computer" on the phone. Confirm the device is recognized from Xcode's Devices and Simulators or from the discover result; being visible in Finder alone does not mean development pairing is done. 3. Per the actual system prompts, turn on "Settings > Privacy & Security > Developer Mode" and complete the confirmation after the restart. If that entry is missing, first let Xcode finish device pairing and development preparation and then check again; do not conclude that the lack of the entry means permanent non-support. If needed, check "Settings > Developer > Enable UI Automation". 4. Use `pua_setup(action="fetch")` to get the pinned-version on-phone execution service that PUA uses, then `configure` the user's `udid`, `team_id`, and a signable `bundle_id`; optionally `source_dir`, `local_port`, `device_port`, with defaults of local forwarding port 18100 and device port 8100. Local run data is by default in `~/.local/share/iphone-use`. Do not copy the author's UDID, Team ID, or signing. When automatic signing fails, follow the returned log to check Signing & Capabilities for the Runner target and select the user's own Team; adjust the bundle ID or provisioning only when the error requires it. 5. Use `build` to build, then `start` to install and launch the Runner test service and local USB forwarding. fetch/build/start are background jobs; record the job_id and query the existing job with `pua_setup(action="status", job_id=...)`, finding it by id in the returned `jobs` array, and do not assume status returns a single job. For fetch / build look at the terminal state, and on failure read the exact log; start is a long-running Runner, so when the job is still running and `service.ready=true` you can call READY, without waiting for succeeded or starting again. Query by status, logs, and the returned retry_after_seconds, not with fixed long intervals or a fixed number of blind waits. start uses the successful build artifact of the current config, keeps the cable connected by default, and leaves the device available for UI testing. 6. If the phone or Xcode reports that the developer is not trusted, complete verification via "Settings > General > VPN & Device Management" and its developer entry on the current device; go by the current prompt, and do not apply the enterprise-app flow to all development signing. Then run `status` and `pua_ready`. When account sign-in, passwords, device unlock, phone confirmation, or Xcode installation truly needs the user, state the exact page, the reason for the block, and the steps to continue after finishing, and you must call an available host question tool (in Default, prefer `AskUserQuestion` (Claude Code) / `functions.request_user_input_async` (Codex)), with the first option fixed as "Done, continue" and the second possibly "Cannot complete right now". An asynchronous return, a preselection, or elapsed time does not mean the user finished; continue the configuration that depends on that step only after receiving the user's actual choice of "Done, continue" or an explicit reply that it is done. Use a text wait notice only if the host has no question capability. Other independent configuration can continue. Do not add a uniform confirmation gate to an already authorized local install. Do not delete the user's existing development apps, revoke shared certificates, or pay to upgrade the account to bypass an error. ## READY verification and recovery READY has already returned the device, session, viewport, and current observation; reuse these to prepare the next step. Do not immediately read the tree again or add a navigation precheck for every task; test on a side-effect-free page only when a specific diagnosis truly needs it. Routine navigation defaults to observe=none, verify=false; when the next step needs unknown page information, return tree / screenshot / both on that action, and do not add a separate verification round. The final key action gets an explicit expect / verify or a single terminal read. After the channel is READY, the target app may still ask for a password, verification code, or Face ID. Per [authentication takeover and recovery](../iphone-use/references/authentication.md), first call `pua_screen(action="pause")` to stop the preview and clear the image, then call the question tool per that reference to prompt the user to finish on the iPhone, with "Done, continue" as the first option; pause phone calls during the takeover. After receiving the user's actual choice of "Done, continue" or an explicit completion notice, call `pua_screen(action="resume")` and re-observe the app and the target page. App authentication is not a PUA fault, and do not repeat build / start / recover for it; restore READY only when the phone is truly locked or the channel is interrupted. After a disconnect, restart, a stopped test process, or an exited USB forward, follow the not-started flow above to query status and reuse the existing job / build; call doctor only when a specific missing item needs it, restore the connection or start by the missing layer, and finally READY again. After the user takes over the phone, re-observe the current app, and do not keep using coordinates from before the takeover or guess the original page. `XCTDaemonErrorDomain Code=41`, `local.pid.0`, or `pua_foreground_unavailable` is a PUA / XCTest channel fault and cannot be solved by changing selectors or treating `status.ready=true` as proof of operability: call `pua_ready(screenshot=false)`. It first rebuilds the session and re-reads once, and only for a persistent fault does it recover in the background this plugin's service whose config, endpoint, worker, and listening-port ownership has been verified, without replaying the failed navigation, input, or submission. With `state="recovering"`, query the same job by recovery.job_id, re-verify READY once recovery_phase reaches serving, and do not start again or wait for succeeded; `state="recovery_required"` means recovery was turned off for this call, and only when the user's instructions allow it use recover=true again; for a `pua_recovery_required` error, handle it by the cooldown, ownership, or build reason in it, and do not kill by port. Neither not-ready state has an error, and neither still means READY. For the complete handling of each state see [channel recovery](references/recovery.md). Handle signing, capacity, connection, developer mode, and version problems by the actual logs, and read [troubleshooting](references/troubleshooting.md). When recovering, reuse the usable build and PUA; rebuild only when signing is expired, the binary is incompatible, or the build is invalid. Output READY or NEEDS_USER_ACTION, with the layers already verified, the exact missing item, and the next step; if verification is incomplete, keep it as not ready. ## Official references Apple's [developer account documentation](https://developer.apple.com/help/account/basics/about-your-developer-account) states that a Personal Team can install at most 3 apps per device, and a provisioning profile expires 7 days after issuance, after which it must be rebuilt and reinstalled. A free account can be used for testing on personal devices, but you cannot promise permanent operation based on it. [Apple Developer Mode](https://developer.apple.com/documentation/xcode/enabling-developer-mode-on-a-device) and [Appium real-device preparation](https://appium.github.io/appium-xcuitest-driver/latest/getting-started/device-setup/) provide pairing, developer mode, and signing requirements. The flow goes by the actual prompts and tool diagnostics of the current Xcode/iOS; this plugin does not require a jailbreak.