xclaude-plugin
Modular iOS development automation for Claude Code Build, test, and automate iOS apps through natural conversation with Claude. 8 workflow-specific MCP servers with 24 tools across Xcode, Simulator, and IDB. Enable only what you need.
Production-ready skill for building, testing, and automating iOS apps. 29 scripts optimized for both human developers and AI agents. (If you'd prefer an MCP, XC-MCP -> NPM )
> /plugin marketplace add conorluddy/ios-simulator-skill> /plugin install ios-simulator-skill@conorluddy
What's inside
Production-ready skill for building, testing, and automating iOS apps. 29 scripts optimized for both human developers and AI agents.
(If you'd prefer an MCP, XC-MCP -> NPM )
This skill covers both sides of iOS development:
xcodebuild — compile, test, and parse results with progressive error disclosurexcrun simctl and idb — semantic UI navigation, accessibility testing, device lifecycleIf you only need Xcode build tooling without the simulator scripts, see the plugin version: xclaude-plugin
In Claude Code:
/plugin marketplace add conorluddy/ios-simulator-skill
/plugin install ios-simulator-skill@conorluddy
A skill is loaded from SKILL.md at the root of its directory — ~/.claude/skills/<name>/SKILL.md.
This repository is a plugin, so the skill itself lives at
ios-simulator-skill/skills/ios-simulator-skill/; cloning the whole repo into your skills
directory puts SKILL.md three levels too deep and the skill will not load.
From a release (simplest):
curl -L https://github.com/conorluddy/ios-simulator-skill/releases/latest/download/ios-simulator-skill.zip -o skill.zip
unzip skill.zip -d ~/.claude/skills/ios-simulator-skill
From a clone (to track main):
git clone https://github.com/conorluddy/ios-simulator-skill.git ~/src/ios-simulator-skill
cp -R ~/src/ios-simulator-skill/ios-simulator-skill/skills/ios-simulator-skill \
~/.claude/skills/ios-simulator-skill
For a project-local install, use .claude/skills/ios-simulator-skill as the destination instead.
Either way, restart Claude Code afterwards; verify with ls ~/.claude/skills/ios-simulator-skill/SKILL.md.
| Requirement | Version | Needed for |
|---|---|---|
| macOS | 15 (Sequoia)+ | everything |
| Xcode + Command Line Tools | 26+ (xcode-select --install) | building, simctl |
| Python | 3.12+ | every script |
idb (CLI + companion) | 1.5.1+ | tapping, swiping, typing |
| Pillow | any | visual diffs only (pip3 install pillow) |
Install idb — required for every interactive script (navigator.py, gesture.py, keyboard.py):
brew tap facebook/fb
brew install facebook/fb/idb-companion facebook/fb/idb-cli
brew install idb-companionno longer works: idb-companion was removed from Homebrew core and now lives in Meta's ownfacebook/fbtap. If you followed older instructions, see Updating idb.
To verify everything at once:
bash scripts/sim_health_check.sh # add --json for machine-readable output
On Xcode 27, idb-companion must be 1.5.1 or newer. Older builds look for
SimulatorKit.framework where Xcode 26 kept it. Under Xcode 27 the companion still starts and
the accessibility tree still reads correctly, but every tap, swipe and keystroke is silently
dropped — idb reports success and nothing happens on screen.
brew upgrade facebook/fb/idb-companion facebook/fb/idb-cli
brew list --versions idb-companion # expect >= 1.5.1
Coming from the old pip package? pip install fb-idb still provides a working idb CLI, but
the Homebrew idb-cli above is the maintained path. If both are installed, whichever comes
first on your PATH wins — check with which -a idb.
Simulator.app. Xcode 27 replaced it with DeviceHub.app, in
Xcode.app/Contents/Applications/. Scripts drive simulators headlessly via simctl and idb,
so you rarely need either — but open -a Simulator will fail.idb calls start failing with Connection refused after a crash or a manual pkill, a dead
companion is still registered. Clear it with idb disconnect <udid>; sim_health_check.sh
detects this.The build_and_test.py script wraps xcodebuild with token-efficient output. A build returns a single summary line with an xcresult ID:
Build: SUCCESS (0 errors, 3 warnings) [xcresult-20251018-143052]
Then drill into details on demand:
python scripts/build_and_test.py --get-errors xcresult-20251018-143052
python scripts/build_and_test.py --get-warnings xcresult-20251018-143052
python scripts/build_and_test.py --get-log xcresult-20251018-143052
This keeps agent conversations focused — no walls of build output unless you ask for them.
Instead of fragile pixel-coordinate tapping, all navigation uses iOS accessibility APIs to find elements by meaning:
# Fragile — breaks if UI changes
idb ui tap 320 400
# Robust — finds by meaning
python scripts/navigator.py --find-text "Login" --tap
The accessibility tree gives structured data (element types, labels, frames, tap targets) at ~10 tokens default output vs 1,600-6,300 tokens for a screenshot. See AI-Accessible Apps for more on why accessibility-first navigation matters for AI agents.
When screenshots are needed (visual verification, bug reports, diffs), the skill automatically resizes and compresses them to minimize token cost. Default output across all 29 scripts is 3-5 lines — 96% reduction vs raw tool output.
| 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% |
Every script supports --help and --json. See SKILL.md for the complete reference.
| Script | What it does | Key flags |
|---|---|---|
build_and_test.py | Build Xcode projects, run tests, parse xcresult bundles | --project, --scheme, --test, --get-errors, --get-warnings |
log_monitor.py | Real-time log monitoring with severity filtering | --app, --severity, --follow, --duration |
| Script | What it does | Key flags |
|---|---|---|
appearance.py | Switch dark mode, dynamic type, locale, region | --theme, --text-size, --locale, --region, --reset |
location.py | Simulate GPS coordinates and run built-in scenarios | --lat, --lng, --city, --gpx, --list-scenarios, --clear |
| 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 button control | --type, --key, --button, --clear, --dismiss |
app_launcher.py | Launch, terminate, install, deep link apps | --launch, --terminate, --install, --open-url, --list |
| Script | What it does | Key flags |
|---|---|---|
accessibility_audit.py | WCAG compliance checking on current screen | --verbose, --output |
visual_diff.py | Compare two screenshots for visual changes | --threshold, --output, --details |
test_recorder.py | Automated test documentation with screenshots | --test-name, --output |
app_state_capture.py | Debugging snapshots (screenshot, hierarchy, logs) | --app-bundle-id, --output, --log-lines |
sim_health_check.sh | Verify environment (Xcode, simctl, IDB, Python) | — |
model_inspector.py | Inspect Core Data / SwiftData models from project files | --project-path, --raw, --show-versions |
container.py | Inspect app sandbox: list, cat, UserDefaults, Core Data, export | --ls, --cat, --userdefaults, --core-data-path, --export |
hang_watcher.py (HangBuster) | Record + summarise os_log hang events with progressive disclosure (session mode + raw NDJSON + legacy stream); auto-restart on stream death, automatic disk-cap cleanup | --start [--raw-capture --max-size-mb N --no-gzip], --stop, --get-details, --list-sessions, --diff, --budget-tokens, --auto-sample (legacy: --watch, --since) |
localization_audit.py | Audit .xcstrings catalogs for missing keys, unused keys, placeholder mismatches | --catalog, --source, --strict |
| Script | What it does | Key flags |
|---|---|---|
clipboard.py | Copy text to simulator clipboard for paste testing | --copy, --test-name |
status_bar.py | Override status bar (time, battery, network) | --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 (15 services) | --bundle-id, --grant, --revoke, --reset |
| Script | What it does | Key flags |
|---|---|---|
simctl_boot.py | Boot simulators with readiness verification | --name, --wait-ready, --timeout, --all, --type |
simctl_shutdown.py | Gracefully shutdown 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 |
Every operational limit — timeouts, output caps, polling intervals, cache size, post-action delays — is tunable via an IOS_SIM_* environment variable. Defaults are tuned for local development on Apple Silicon. Raise them on slow CI runners, large monorepos, or accessibility audits over complex screens. Lower them when you need faster failure or tighter token budgets.
There's a universal tradeoff to keep in mind:
How long to wait on xcrun simctl operations.
| Variable | Default | Tradeoff |
|---|---|---|
IOS_SIM_BOOT_TIMEOUT | 300 (s) | Wait for simulator readiness after boot. Lower → faster failure on broken sims. Higher → survives cold-start on slow CI runners (GitHub-hosted macOS can need 4–6 min). |
IOS_SIM_BOOT_SUBPROCESS_TIMEOUT | 60 (s) | Timeout for the simctl boot call itself (before readiness polling starts). Rarely needs changing; bump only if you see Boot command timed out on resource-starved CI. |
IOS_SIM_ERASE_TIMEOUT | 90 (s) | Wait for factory-reset verification. Larger simulators (lots of installed apps + data) can need more than the old 30s. |
IOS_SIM_POLL_INTERVAL | 0.5 (s) | How often to re-check boot/erase state. Lower → more responsive (more CPU). Higher → quieter on slow CI but adds latency to “ready” detection. |
Modular iOS development automation for Claude Code Build, test, and automate iOS apps through natural conversation with Claude. 8 workflow-specific MCP servers with 24 tools across Xcode, Simulator, and IDB. Enable only what you need.
FAQ
ios-simulator-skill is a Claude Code plugin with 1 hand-picked skill for development work, indexed on Flowy. Install it with the command on its page. It includes ios-simulator-skill. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
Is this plugin yours?
Claim it with GitHubSubmit a pluginPromote it