一键导入
iphone
Direct iPhone control via Appium/XCUITest. Use when the user wants to automate, inspect, or interact with a real iPhone tethered via USB.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Direct iPhone control via Appium/XCUITest. Use when the user wants to automate, inspect, or interact with a real iPhone tethered via USB.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | iphone |
| description | Direct iPhone control via Appium/XCUITest. Use when the user wants to automate, inspect, or interact with a real iPhone tethered via USB. |
Direct iPhone control via Appium. The iOS analogue of browser-harness by Browser Use — same doctrine, same skill system, translated from CDP/Chrome to XCUITest/iPhone.
For task-specific edits, use agent-workspace/agent_helpers.py. For setup/connection issues, run iphone-harness --doctor.
Domain skills (per-app playbooks under agent-workspace/domain-skills/<bundleId>/) are off by default. Set IPH_DOMAIN_SKILLS=1 to enable. When enabled, after launching an app call domain_skills(bundleId) to get the matching .md filenames — read every one before inventing an approach.
iphone-harness -c '
appium("mobile: launchApp", bundleId="com.apple.MobileSMS")
wait_for_app("com.apple.MobileSMS")
print(active_app())
'
iphone-harness — it's on $PATH. Helpers pre-imported. Daemon auto-starts.default). Use distinct IPH_NAME values for multiple phones.iphone-harness -c '
# any python. helpers pre-imported. daemon auto-starts.
'
run.py calls ensure_daemon() before exec — never start/stop manually unless you want to.
ui_tree() — use it for action targeting (find(label='Cancel')). Use screenshot() to verify visual state.tap_at_xy(x, y) goes through SpringBoard, alerts, modals — no foreground-app scoping issue. Pair it with element centers from find(): tap(find(label='Send')).appium(...). No dedicated wrappers — just call XCUITest directly:
appium("mobile: launchApp", bundleId="com.apple.MobileSMS") — cold-launchappium("mobile: activateApp", bundleId="...") — resume without resetting stateappium("mobile: terminateApp", bundleId="...") — force-quitappium("mobile: queryAppState", bundleId="...") — 0=not installed, 1=not running, 4=foregroundappium("mobile: pressButton", name="home") — Home button (or volumeUp/volumeDown)appium("mobile: lock") / unlock() — sleep / wake (unlock() is a real helper because it has a multi-step recipe)appium("mobile: isLocked") — boolalert() reads the buttons; alert_accept() / alert_dismiss() dispatch the default action. For in-app alerts, treat them as regular UI tree nodes.screenshot() after every meaningful action. UI trees can lie about visibility during animations.appium("mobile: anything", **params) — anything XCUITest supports, no helper required.If you struggle with a generic mechanic, look in interaction-skills/. They cover reusable iOS UI mechanics:
home-bar-tap-zone.md — taps in the bottom ~80px get eaten by the home gesturealerts.md — system vs. in-app alerts; how to dismisspicker-wheels.md — date/time/value pickers; use pick_wheel, never raw swipesscroll-into-tappable-zone.md — auto-scroll an element above the home-bar zone before tappingocr-fallback.md — when the accessibility tree fails (Camera, web views, custom-drawn UIs)wait-for-animations.md — let iOS settle before reading the treeappium(...) is the public escape hatch — prefer raw XCUITest scripts over typed wrappers. Helpers exist only when there's a real recipe inside (multi-step, framework workaround, format conversion). One-line wrappers around appium('mobile: …') are NOT added to helpers.py.run.py stays tiny. No argparse, no subcommands.agent-workspace/agent_helpers.py.tap_safe(el, refind=...) or use long_press (which is NOT eaten by the gesture).12:59 time / battery icons can trigger system overlays (e.g. clock to top, ringer overlay).tap_at_xy() fails silently when the screen is locked. Always unlock() first or check appium('mobile: isLocked').IPH_NEW_COMMAND_TIMEOUT seconds of inactivity. The daemon auto-reconnects on the next call, but if you see a sudden 5-second pause, that's why.find(label=...) returns None for an obvious button, screenshot first.alert() only sees system-level (SpringBoard) alerts. In-app modals appear as XCUIElementTypeAlert in ui_tree() — use find(type='XCUIElementTypeButton', label='Cancel').type_text(MSG) paces character-by-character (slow + flaky on Unicode). For text > ~80 chars or anything with em-dash / curly quotes / emoji, use set_value("name == 'fieldName'", MSG) instead — atomic and Unicode-safe.send_keys or raw swipes — use pick_wheel(predicate, target_substring, direction=...).click(predicate) not tap(coords) — atomic find+click avoids the layout race.Only applies when IPH_DOMAIN_SKILLS=1. Otherwise agent-workspace/domain-skills/ is dormant.
When enabled, after launching an app call domain_skills(bundle_id) to list matching skill files:
appium("mobile: launchApp", bundleId="com.apple.MobileSMS")
wait_for_app("com.apple.MobileSMS")
for f in domain_skills("com.apple.MobileSMS"):
print(f) # ['send-text.md', 'tapback-reaction.md']
# Read those .md files before inventing an approach.
When you learn anything non-obvious — a stable accessibility id, a quirky alert sequence, a hidden gesture, an app-specific timing — open a PR adding to agent-workspace/domain-skills/<bundleId>/. Capture durable shape (predicate names, sequence of actions); avoid pixel coordinates (break on layout/orientation) and secrets.