Build Xcode projects, drive the simulator semantically, and ship features β all from inside a Claude Code conversation, in a fraction of the tokens.
Install Β· Quick Start Β· Scripts Β· Why Β· SKILL.md
Warning
STATUS: ARCHIVED CLAUDE NATIVELY SUPPORTS THIS NOW
Without this skill, Claude pokes at the iOS simulator with pixel coordinates and dumps walls of xcodebuild output into context. With it, Claude does real iOS work in a few turns:
$ python3 ${CLAUDE_SKILL_DIR}/scripts/build_and_test.py --project MyApp.xcodeproj --scheme MyApp
Build: SUCCESS (0 errors, 3 warnings) [xcresult-20251018-143052]
$ python3 ${CLAUDE_SKILL_DIR}/scripts/navigator.py --find-text "Sign In" --tap
Tapped: Button "Sign In" at (320, 450)
$ python3 ${CLAUDE_SKILL_DIR}/scripts/wait_for.py --element "Welcome" --timeout 5
OK: element "Welcome" matched in 1.2s
$ python3 ${CLAUDE_SKILL_DIR}/scripts/debug_failing_test.py \
--project MyApp.xcodeproj --scheme MyApp \
--test MyAppTests/LoginTests/testInvalidPassword \
--bundle-id com.example.MyApp
FAIL: testInvalidPassword β bundle: ./debug-20260424-153012/ (3 errors, 142 log lines, ui tree ok, screenshot ok)No pixel coordinates. No walls of build output. No polling loops in the agent turn.
Three design choices, and the rest follows:
|
Find elements by meaning β |
A build returns one summary line plus an |
Every script supports |
| Task | Raw tools | This skill | Savings |
|---|---|---|---|
| Screen analysis | 200+ lines | 5 lines | 97.5% |
| Find & tap button | 100+ lines | 1 line | 99% |
| Login flow | 400+ lines | 15 lines | 96% |
Tested with Claude Code evals
| Condition | Pass rate |
|---|---|
| With skill | π’ 100% (3/3) |
| Without skill | π΄ 46% (~1.4/3) |
claude evals run evals/evals.json --skill ios-simulator-skill/plugin marketplace add cpeaustriajc/ios-simulator-skill
/plugin install ios-simulator-skill@cpeaustriajc
# Personal β all your projects
git clone https://github.com/cpeaustriajc/ios-simulator-skill.git \
~/.claude/skills/ios-simulator-skill
# Project-scoped
git clone https://github.com/cpeaustriajc/ios-simulator-skill.git \
.claude/skills/ios-simulator-skillRestart Claude Code. The skill auto-loads when you open iOS files (.xcodeproj, .xcworkspace, .swift, .m, .h, Package.swift).
| Requirement | Notes |
|---|---|
| π macOS 12+ | |
| π οΈ Xcode CLT | xcode-select --install |
| π Python 3.12+ | |
| π€ IDB (two parts) | See below β needs both the brew companion daemon and the pipx CLI client |
| πΌοΈ Pillow | Only for visual_diff.py: pip3 install pillow |
The UI-navigation scripts (screen_mapper.py, navigator.py, gesture.py,
keyboard.py, accessibility_audit.py, wait_for.py) shell out to the idb
binary. IDB is two components β you need both:
idb-companionβ Swift daemon, installed via Homebrew.fb-idbβ Python CLI client (theidbbinary), installed via pipx.
# 1. Companion daemon
brew tap facebook/fb
brew install idb-companion
# 2. Python client β must run on Python 3.12 or 3.13.
# fb-idb calls asyncio.get_event_loop(), which raises on Python 3.14+.
# Pin the interpreter even if your system Python is newer:
pipx install --python python3.13 fb-idb
# 3. Verify
idb --version
bash ~/.claude/skills/ios-simulator-skill/scripts/sim_health_check.shLast verified install combo: macOS 15,
idb-companion1.1.x via Homebrew,fb-idb1.1.x viapipx --python python3.13. The Python 3.14 incompatibility is tracked in #16 β ifsim_health_check.shwarns about it, follow itspipx --python python3.13recipe.
Just want build tooling, no IDB? See xclaude-plugin β same
xcodebuildwrapper without the simulator scripts.
Once installed, ask Claude things like "build the app and run the login test" or "tap the Sign In button and screenshot the result" β Claude picks the right scripts automatically.
To drive things directly:
# 1. Verify the environment
bash ~/.claude/skills/ios-simulator-skill/scripts/sim_health_check.sh
# 2. See what's on the screen
python3 ~/.claude/skills/ios-simulator-skill/scripts/screen_mapper.py
# 3. Drive a flow
python3 ~/.claude/skills/ios-simulator-skill/scripts/navigator.py \
--find-type TextField --enter-text "user@example.com"
python3 ~/.claude/skills/ios-simulator-skill/scripts/navigator.py \
--find-text "Sign In" --tap
python3 ~/.claude/skills/ios-simulator-skill/scripts/wait_for.py \
--element "Welcome" --timeout 5π‘ Set
export SIMCTL_UDID=<your-device-udid>once and skip--udideverywhere.
For the full skill body Claude loads (decision tree + workflows), see SKILL.md. For the per-script flag reference, see reference.md. Every script also supports --help.
24 scripts. Every one supports
--helpand--json.
ποΈ Β Build & development
| Script | What it does | Key flags |
|---|---|---|
build_and_test.py |
Build Xcode projects, run tests, parse xcresult with progressive disclosure | --project --scheme --test --get-errors --get-warnings |
log_monitor.py |
Real-time log monitoring with severity filtering | --app --severity --follow --duration |
π Β UI navigation
| Script | What it does | Key flags |
|---|---|---|
screen_mapper.py |
Analyze current screen, list interactive elements | --verbose --hints |
navigator.py |
Find and interact with elements semantically | --find-text --find-type --find-id --tap --enter-text |
gesture.py |
Swipes, scrolls, pinches, long press, pull to refresh | --swipe --scroll --pinch --long-press --refresh |
keyboard.py |
Text input and hardware buttons | --text --key --button --clear --dismiss |
app_launcher.py |
Launch, terminate, install, deep link apps | --launch --terminate --install --open-url --list |
π§ͺ Β Testing & debug
| Script | What it does | Key flags |
|---|---|---|
wait_for.py β¨ |
Block until an element appears, app reaches a state, or a log line matches | --element --app-state --log-match --timeout |
debug_failing_test.py β¨ |
Run an XCTest; on failure capture xcresult errors + UI tree + logs + screenshot into one bundle | --test --bundle-id --retries |
accessibility_audit.py |
WCAG compliance check on current screen | --verbose --output |
visual_diff.py |
Compare two screenshots | --threshold --output --details |
test_recorder.py |
Automated test documentation with screenshots | --test-name --output |
app_state_capture.py |
Debugging snapshot bundle (screenshot + hierarchy + logs) | --app-bundle-id --output --log-lines |
model_inspector.py |
Inspect Core Data / SwiftData models from project sources | --project-path --raw --show-versions |
sim_health_check.sh |
Verify Xcode, simctl, IDB, Python | β |
π Β Environment & permissions
| Script | What it does | Key flags |
|---|---|---|
clipboard.py |
Set/assert simulator clipboard for paste testing | --copy --test-name --expected |
status_bar.py |
Override status bar for screenshots and demos | --preset --time --battery-level --clear |
push_notification.py |
Send simulated push notifications | --bundle-id --title --body --payload |
privacy_manager.py |
Grant, revoke, reset app permissions (13 services) | --bundle-id --grant --revoke --reset |
π Β Device lifecycle
| Script | What it does | Key flags |
|---|---|---|
simctl_boot.py |
Boot simulators with readiness verification | --name --wait-ready --timeout --all --type |
simctl_shutdown.py |
Gracefully shut down simulators | --name --verify --all --type |
simctl_create.py |
Create simulators by device type and OS version | --device --runtime --list-devices |
simctl_delete.py |
Delete simulators with safety confirmation | --name --yes --all --old |
simctl_erase.py |
Factory reset without deletion | --name --verify --all --booted |
This isn't a CLI library that happens to work with Claude. Every design choice optimizes the agent loop:
- π Default output is the minimum actionable signal. 3β5 lines, ~10 tokens. Verbose and JSON modes exist for when you need them.
- 𧬠Structured error envelopes with stable codes and optional
recovery_cmdfields β the script tells the agent how to fix itself. - π
wait_for.pyruns polling on the host. No more "let me check again" loops eating turns. - π
debug_failing_test.pycollapses 5 tools into one bundle when a test fails β xcresult errors + UI tree + logs + screenshot, indexed by a README. - ποΈ
SIMCTL_UDIDenv fallback β set once, work across all 24 scripts. - πͺ Auto-trigger scoped to iOS files β won't activate on your Rails project.
- π¬ Why accessibility-first navigation matters for AI agents
- π Claude Code skills documentation
- π§±
CLAUDE.mdβ architecture and contribution conventions
The skill follows the conventions in CLAUDE.md: class-based scripts, --json everywhere, terse default output, ruff/black clean. Run pre-commit run --all-files before sending a PR. Contract tests for the error envelope live in ios-simulator-skill/scripts/tests/.
PRs welcome β please check existing issues first and keep changes scoped.
MIT Β· Issues Β· Discussions Β· Forked from conorluddy/ios-simulator-skill
If this saved you an evening, β a star goes a long way.