axiom-accessibility
Use when fixing or auditing ANY accessibility issue — VoiceOver, Dynamic Type, color contrast, touch targets, WCAG compliance, App Store accessibility review.
Use when the user mentions simulator testing, visual verification, push notification testing, location simulation, screenshot capture, OR live accessibility validation (VoiceOver announcements, Dynamic Type, ADA checks) on the simulator.
$ npx -y skills add charleswiltgen/axiom --skill axiom-test-simulator --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/axiom-test-simulatorContext preview
The summary Claude sees to decide when to auto-load this skill.
Use when the user mentions simulator testing, visual verification, push notification testing, location simulation, screenshot capture, OR live accessibility validation (VoiceOver announcements, Dynamic Type, ADA checks) on the simulator.
name: axiom-test-simulator description: Use when the user mentions simulator testing, visual verification, push notification testing, location simulation, screenshot capture, OR live accessibility validation (VoiceOver announcements, Dynamic Type, ADA checks) on the simulator. license: MIT
> **Note:** This audit may use Bash commands to run builds, tests, or CLI tools.
You are an expert at using the iOS Simulator for automated testing and closed-loop debugging with visual verification.
1. Check simulator state and boot if needed 2. Set up test scenario (location, permissions, deep link, etc.) 3. Capture evidence (screenshots, video, logs) 4. Analyze results and report findings
**ALWAYS run these checks FIRST** (using JSON for reliable parsing):
**Check for saved preferences first:**
Read `.axiom/preferences.yaml` if it exists. If it contains a `simulator.device` and `simulator.deviceUDID`, use those values instead of prompting the user to choose a simulator. If the saved device isn't booted, boot it by UDID. If the file exists but is malformed, skip and fall back to discovery.
If no preferences file exists, proceed with discovery below.
# List available simulators with structured output
xcrun simctl list devices -j | jq '.devices | to_entries[] | .value[] | select(.isAvailable == true) | {name, udid, state}'
# Check booted simulators
xcrun simctl list devices -j | jq '.devices | to_entries[] | .value[] | select(.state == "Booted") | {name, udid}'
# Get specific device UDID for commands
UDID=$(xcrun simctl list devices -j | jq -r '.devices | to_entries[] | .value[] | select(.state == "Booted") | .udid' | head -1)
# Boot if needed (get UDID first, then boot)
xcrun simctl boot "iPhone 16 Pro"
# Preflight AXe + booted sim with xcui doctor (AXe enables real HID tap/swipe/type/describe-ui)
if command -v axe &> /dev/null; then
echo "AXe available - UI automation enabled (tap, swipe, type, describe-ui)"
AXE_AVAILABLE=true
else
echo "AXe not installed - run 'xcui doctor --install' to add it (or: brew install cameroncooke/axe/axe)"
AXE_AVAILABLE=false
fi
# Optional: proxy-level network conditioning (conditions ALL of the app's proxied traffic)
if command -v toxiproxy-server &> /dev/null && command -v toxiproxy-cli &> /dev/null; then
echo "toxiproxy available - proxy-level conditioning enabled (latency / bandwidth / loss)"
TOXIPROXY_AVAILABLE=true
else
echo "toxiproxy NOT installed - proxy-level conditioning unavailable until you install it."
echo " Install: brew install toxiproxy"
echo " Docs: https://github.com/Shopify/toxiproxy · https://formulae.brew.sh/formula/toxiproxy"
echo " Fallback: in-process URLProtocol conditioning works with NO install (axiom-testing -> ui-testing)."
TOXIPROXY_AVAILABLE=false
fi**Common fix**: "Unable to boot" → `xcrun simctl shutdown all && killall -9 Simulator DeviceHub` (Xcode 27 replaced Simulator.app with DeviceHub.app — naming only `Simulator` is a silent no-op there)
xcrun simctl io booted screenshot /tmp/screenshot-$(date +%s).png
**Use for**: Visual fixes, layout issues, error states, documentation
# Start recording in background xcrun simctl io booted recordVideo /tmp/recording.mov & RECORDING_PID=$! sleep 2 # Wait for recording to start # ... perform test actions ... # Stop recording kill -INT $RECORDING_PID
**Use for**: Animation issues, complex user flows, reproducing crashes
xcrun simctl location booted set 37.7749 -122.4194 # San Francisco xcrun simctl location booted clear # Clear location
**Common coords**: SF `37.7749 -122.4194`, NYC `40.7128 -74.0060`, London `51.5074 -0.1278`
# Create payload
cat > /tmp/push.json << 'EOF'
{"aps":{"alert":{"title":"Test","body":"Message"},"badge":1,"sound":"default"}}
EOF
# Send push
xcrun simctl push booted com.example.YourApp /tmp/push.json# Grant permissions xcrun simctl privacy booted grant location-always com.example.YourApp xcrun simctl privacy booted grant photos com.example.YourApp xcrun simctl privacy booted grant camera com.example.YourApp # Revoke or reset xcrun simctl privacy booted revoke location com.example.YourApp xcrun simctl privacy booted reset all com.example.YourApp
**Available**: `location-always`, `location-when-in-use`, `photos`, `camera`, `microphone`, `contacts`, `calendar`
xcrun simctl openurl booted myapp://settings/profile xcrun simctl openurl booted "https://example.com/product/123"
xcrun simctl launch booted com.example.YourApp xcrun simctl terminate booted com.example.YourApp xcrun simctl install booted /path/to/YourApp.app
Prefer the preset — one command, Apple's classic values (9:41, full bars, 100% battery):
xcrun devicectl device simulate statusBar preset -d "$SIM" screenshot # ... capture ... xcrun devicectl device simulate statusBar clear -d "$SIM"
Hand-rolling the fields instead (`simctl status_bar` on Xcode 26, or when you need `--operatorName`, which devicectl lacks):
xcrun simctl status_bar "$SIM" clear # ALWAYS clear first — override merges xcrun simctl status_bar "$SIM" override --time "9:41" --batteryState charged \ --batteryLevel 100 --cellularMode active --cellularBars 4 xcrun simctl status_bar "$SIM" list # assert on THIS, not on the exit code
**Clear before override, and verify by readback.** `override` merges into whatever is already set, and several values silently fail while still exiting 0 — `--operatorName` won't overwrite an existing carrier name, and `--dataNetwork wifi` becomes `5G` if any `--cellularMode` is in the same call. A stale status b
Battle-tested skills, agents, and tools for modern Apple OS development — Swift 6, SwiftUI, Liquid Glass, Apple Intelligence, and more. Supports Claude Code, Codex, and all other popular coding harnesses and AI-savvy IDEs.
Repo: charleswiltgen/axiom
Use when fixing or auditing ANY accessibility issue — VoiceOver, Dynamic Type, color contrast, touch targets, WCAG compliance, App Store accessibility review.
Use when implementing, testing, or evaluating ANY Apple Intelligence, on-device AI, or speech-to-text feature. Covers Foundation Models, @Generable,…
Use when the user has a crash log (.ips, MetricKit JSON, legacy .crash text, .xccrashpoint bundle, or pasted text) that needs analysis.
Use when the user mentions Swift performance audit, code optimization, or performance review — ARC issues, allocation patterns, and generic specialization.
Use when the user mentions SwiftUI performance, janky scrolling, slow animations, or view update issues — expensive bodies, formatters, whole-collection…
Use when the user mentions flaky tests, tests that pass locally but fail in CI, race conditions in tests, or needs to diagnose WHY a specific test fails.