| name | device-use |
| description | iOS Simulator automation CLI for AI agents. Use this skill to observe, interact with, and automate iOS simulator apps — tap elements, type text, take screenshots, read accessibility trees, and stream screens. |
device-use
iOS Simulator automation CLI. Observe, interact, and stream iOS apps through structured commands.
Commands
Simulator Lifecycle
device-use list
device-use list --booted
device-use boot "iPhone 17 Pro"
device-use boot <UDID>
device-use shutdown "iPhone 17 Pro"
device-use shutdown --all
device-use open
Apps
device-use apps
device-use apps --user
device-use apps --system
device-use appstate com.apple.Preferences
device-use launch com.apple.Maps
device-use launch com.apple.Maps --relaunch
device-use terminate com.apple.Maps
Permissions
Pre-grant system permissions so authorization dialogs don't block your flow.
device-use permission grant location com.apple.Maps
device-use permission grant photos ai.deus.machine
device-use permission revoke microphone com.example.app
device-use permission reset all com.example.app
device-use permission reset all
Services: calendar, contacts, contacts-limited, location, location-always,
photos, photos-add, media-library, microphone, motion, reminders, siri, all.
Actions: grant, revoke, reset.
Observe the Screen
device-use snapshot
device-use snapshot -i
device-use snapshot -i --flat
device-use snapshot -i --diff
device-use snapshot -i --hidden
device-use screenshot
device-use screenshot output.png
device-use screenshot output.png --annotate
device-use screenshot --base64
snapshot returns a structured tree — interactive nodes get @refs, non-interactive
nodes (containers, StaticText) are kept for context. Use --flat if you only want the
flat ref list. Refs are only assigned to on-screen elements by default (visible-first);
--hidden includes off-screen interactive nodes for audits.
Interact
device-use tap @e1
device-use tap --id "loginButton"
device-use tap --label "Sign In"
device-use tap -x 200 -y 400
device-use swipe --from 200,500 --to 200,100
device-use swipe --from 100,400 --to 300,400 --duration 0.3
device-use type "hello@example.com"
device-use type "search query" --submit
device-use fill @e3 "me@example.com"
device-use fill --label Password "secret" --submit
device-use wait-for --label "Welcome"
device-use wait-for --id "spinner" --gone --timeout 20
device-use open-url https://example.com
device-use open-url myapp://home --accept
iOS platform gotchas (affect automation)
- SwiftUI
TabView tab buttons are NOT in the accessibility tree. Tap tabs by
coordinate (the tab bar is at y≈830 on a 402×874 logical screen) or use deep links.
SecureField reports type=TextField on iOS 26 — match by --id, not type.
- SwiftUI
Toggle reports type=CheckBox on iOS 26.
Slider.value is normalized 0..1 in the a11y tree, not the real range.
- Custom URL schemes trigger an iOS "Open in 'App'?" modal on iOS 26; tap
Open
to accept. Universal links (https://) don't.
simctl privacy grant location doesn't cover widget-specific location prompts.
Query (unified find / is / exists / get)
device-use query --label "Sign In"
device-use query --label "Sign In" --exact
device-use query --id loginButton --get bool
device-use query --type Button --get count
device-use query --type StaticText --get text
device-use query --label Welcome --wait 10 --get bool
Filters (combine with AND): --label, --id, --type, --role, --value.
Default match is substring; --exact flips to strict equality.
Output shape: --get refs | attrs | text | bool | count (default attrs).
Aliases: find, is, exists.
Stream
device-use stream enable
device-use stream status
device-use stream disable
Session State
Stores the default simulator + the last @ref map between commands.
device-use session show
device-use session set --simulator "iPhone 17"
device-use session clear
Diagnostics
device-use doctor
device-use install
Workflow Pattern
Follow this loop when automating iOS simulator interactions:
-
Boot a simulator if none is running:
device-use list --booted --json 2>/dev/null
device-use boot "iPhone 17 Pro"
-
Observe the current screen state:
device-use snapshot -i --json 2>/dev/null
Returns interactive elements with @ref identifiers (e.g., @e1, @e2).
-
Act on an element:
device-use tap @e1
device-use type "hello"
-
Re-observe after each action — @ref identifiers change between snapshots:
device-use snapshot -i --json 2>/dev/null
-
Verify with a screenshot if needed:
device-use screenshot verify.png
Important Notes
- @refs are ephemeral: They change after every interaction. Always re-run
snapshot -i before tapping.
- Use
--json for parsing: All commands support --json for structured output. JSON is also the default when stdout is piped.
- Redirect stderr:
simbridge emits diagnostics on stderr. Use 2>/dev/null when parsing JSON output.
- One simulator at a time: Use
--simulator <UDID> to target a specific device when multiple are booted.
- Session defaults: Use
device-use session set --simulator <UDID> to set a default for subsequent commands.
JSON Output Format
All commands return this envelope in JSON mode:
{
"success": true,
"command": "snapshot",
"data": { ... },
"message": "optional human-readable message",
"nextSteps": [{"command": "tap @e1", "label": "Tap first element"}],
"warnings": []
}
On failure:
{ "success": false, "error": "..." }
snapshot data shape
{
"tree": [
{
"type": "Application", "label": "Settings",
"frame": { "x": 0, "y": 0, "width": 402, "height": 874 },
"center": { "x": 201, "y": 437 },
"children": [
{ "type": "Button", "ref": "@e1", "label": "General",
"interactive": true, "enabled": true,
"frame": {...}, "center": {...} },
{ "type": "Group",
"children": [
{ "type": "StaticText", "label": "iOS Version, 26.1" },
{ "type": "Button", "ref": "@e2", "label": "iOS Version, 26.1", "interactive": true, ... }
]
}
]
}
],
"refs": [ { "ref": "@e1", "type": "Button", ... }, { "ref": "@e2", ... } ],
"counts": { "total": 16, "interactive": 2 }
}
- Only nodes with
interactive: true have a ref — these are tappable now.
- Non-interactive nodes (containers, StaticText, Headings) are kept for context: they
tell you what section an interactive element belongs to.
refs is the flat DFS-ordered list — use it when you don't need hierarchy.
Example: Complete Automation Flow
device-use boot "iPhone 17 Pro"
device-use open
device-use snapshot -i
device-use tap @e3
device-use type "test@example.com"
device-use tap @e5
device-use screenshot result.png
device-use snapshot -i