Tools¶
Every tool below can be driven three ways: from the CLI
(bunx @kaeawc/auto-mobile --cli <tool>), over MCP from an AI client, or
directly against the daemon’s HTTP endpoint. The tool names and arguments are
the same across all three.
This page reflects the current tool schema. Availability can still vary by platform, runner, and enabled feature gates; inspect the registered schema for the exact arguments supported by your connection.
Observe & navigate¶
Screen-coordinate contract¶
observe reports platform-native, current-orientation screen coordinates. The
origin is the top-left of the complete current screen, including system UI:
- Android uses physical pixels; iOS uses XCTest logical points.
screenSize, skeleton bounds, full-hierarchy bounds, and future absolute coordinate input use that same platform-native coordinate space.- Valid coordinates are half-open:
0 <= x < widthand0 <= y < height. - A point already in the platform-native space is not density-, inset-, Retina-scale-, canonical-pixel-, or rotation-transformed.
This is separate from the daemon observation-stream’s
canonical-pixel mapping.
That stream contract is intentional and does not transform MCP observe or
native absolute-input coordinates.
observe, observe.screenSize, and tapAt use the device’s current-orientation
native coordinate space described above. captureScreenshot returns a
native-scale PNG whose orientation follows the device framebuffer: on the iOS
Simulator, the framebuffer can remain portrait after rotate, even while the
device orientation is landscape (this is simulator framebuffer behavior, not an
AutoMobile bug); on Android, the raster rotates with the device. Therefore,
after rotation, callers must apply a platform- and orientation-specific
transform before correlating iOS observe or tapAt coordinates with
captureScreenshot pixels. No such transform is needed on Android.
| Tool | What it does |
|---|---|
π observe |
Gets the current screen view hierarchy. |
π explore |
Explores an app to build a navigation graph. |
πΊοΈ navigateTo |
Navigates using the learned navigation graph. |
π getNavigationGraph |
Retrieves the navigation graph for debugging. |
π identifyInteractions |
Suggests likely interactions. |
ποΈ highlight |
Draws a visual highlight around a UI element. |
π debugSearch |
Shows selector matches, the chosen match, and near-misses. |
Interact with the UI¶
| Tool | What it does |
|---|---|
π tapOn |
Taps by text, content description, resource ID, or Android test tag; can idempotently ensure a toggle is checked or unchecked. |
π― tapAny |
Taps any clickable element, optionally scoped to a container. |
π swipeOn |
Swipes or scrolls the screen or an element. |
βοΈ dragAndDrop |
Drags one element to another. |
π€ pinchOn |
Pinches to zoom. |
β¨οΈ sendKeys |
Runs ordered text, clear, raw-key, and semantic-key commands. |
β¨οΈ inputText |
Legacy text input retained for compatibility; disabled by default. |
π§© setUIState |
Sets multiple form fields to a desired state. |
ποΈ clearText |
Legacy focused-input clear; disabled by default. |
β¨ selectAllText |
Selects all text in the focused input. |
β©οΈ imeAction |
Legacy standalone IME action; disabled by default. |
π pressButton |
Presses a device or navigation button. |
β¨οΈ keyboard |
Opens, closes, or detects the on-screen keyboard. |
π clipboard |
Copies, pastes, clears, or reads the clipboard. |
sendKeys accepts one optional field selector and an ordered sequence of up to
100 commands:
{
"selector": { "text": "Email" },
"commands": [
{ "action": "type", "text": "name@example.com" },
{ "action": "key", "key": "tab" },
{ "action": "type", "text": "replacement", "operation": "replace", "mode": "a11y" },
{ "action": "key", "key": "enter", "modifiers": ["shift"] }
]
}
Text defaults to operation: "insert" and mode: "auto". Modes are auto,
a11y, eventLast, eventAll, and eventOnly. They select Android delivery
strategies; iOS accepts the same values for cross-platform plans and reports the
actual xcuiTypeText mechanism as resolvedMode. Raw keys are enter, tab,
escape, backspace, delete, and the four arrow keys; they accept shift,
ctrl, alt, and meta. Semantic keys next, previous, done, search,
send, and go perform the corresponding IME action and ignore modifiers. A
standalone { "action": "clear" } command clears the focused field. Execution
stops on the first failure and returns compact command metadata plus the final
observation without copying type-command text into the metadata.
inputText reserves an error response for a failed text write. When the text
lands but the optional dismissKeyboard cleanup cannot be confirmed, the
response stays a success carrying keyboardDismissed: false and a
warnings: ["keyboard dismissal failed: ..."] entry β so a client never has to
parse prose to decide whether retyping would double the text. Inside
executePlan those warnings are promoted to the response’s own warnings list,
each entry naming the stepIndex, tool, and (for multi-device plans) the
device that reported it, so an ordinary plan does not have to opt into the
captureObserveSteps debug trace to see them.
sendKeys is the default text-input path on any AutoMobile release whose
CtrlProxy artifacts are 0.0.68 or newer, which is the case for current releases.
On older pinned releases inputText and clearText are default-enabled instead
and sendKeys is off; enable sendKeys there explicitly with setToolEnabled
or --enable-tool sendKeys.
Pinch rotation semantics
pinchOn.rotationDegrees describes how far the two-finger axis rotates
during the pinch. The fingers start horizontally and finish on the rotated
axis, so a non-zero value combines pinch and rotation. The default 0 is
a plain pinch. Android and iOS share this convention.
Apps, files & app data¶
| Tool | What it does |
|---|---|
π± listApps |
Lists installed apps with optional label/launchability when reported (device, type, search, profile; default type=launchable). |
π launchApp |
Launches an app by package name; on Android an app already in the foreground is a success flagged alreadyForeground. |
β terminateApp |
Terminates an app by package name. |
π₯ crashApp |
Intentionally crashes a running app through the platform crash path. |
π¦ installApp |
Installs an APK, app bundle, or IPA. |
ποΈ uninstallApp |
Uninstalls an app by package name or bundle identifier. |
π getDeepLinks |
Queries an app’s deep links. |
π putAppFile |
Writes local-file, UTF-8, or base64 content into an app container. |
π§Ύ resetAppLogs |
Resets explicitly named app-container log files and their rotated siblings on the session device, with per-path outcomes. |
π₯ stageSharedStorage |
Stages host-file, UTF-8, or base64 fixtures into a bounded Android Downloads namespace for system pickers (Android only). |
π stageSessionDownloads |
Stages fixtures into one bounded child directory of the session device’s shared Downloads tree, with optional reset and per-file media indexing (Android only). |
βοΈ getPreference / βοΈ setPreference |
Reads or writes Android system properties, SharedPreferences, or iOS UserDefaults. |
π setKeyValue / π removeKeyValue / π clearKeyValueFile |
Manages an app key-value storage file. |
ποΈ listDataStores / ποΈ getDataStore |
Lists or reads Android Jetpack DataStore entries with the SDK adapter. |
ποΈ sqlQuery |
Executes SQL against an app SQLite database. |
π resetKeychain |
Resets all Keychain data on an iOS Simulator after explicit confirmation; unsupported on Android and physical iOS devices. |
Intentional crash contract
crashApp accepts only an appId; it never accepts a PID,
signal, or shell command. Android uses ActivityManager’s VM-crash path for the
resolved user. iOS Simulator sends SIGABRT to the exact launchd application
process. Physical iOS devices return supported: false and never fall
back to normal termination.
Every result reports success, supported,
platform, appId, mechanism,
timestamp, and confirmed. It reports
wasRunning whenever preflight established process state;
confirmed crashes also report processId when available and include
immediate OS diagnostic evidence. success: true and
confirmed: true require fresh, target-specific crash evidence, not
merely command dispatch or process disappearance.
Copy a fixture into an app container
{
"tool": "putAppFile",
"params": {
"platform": "ios",
"target": {
"domain": "app_containers",
"appId": "com.example.app",
"container": "documents"
},
"files": [
{
"sourcePath": "/Users/me/fixtures/welcome.png",
"destinationPath": "fixtures/welcome.png"
}
]
}
}
File containers
Android externalFiles maps to /sdcard/Android/data/{appId}/files.
Private containers (documents, cache, and tmp) use
run-as and require a debuggable app. iOS simulator containers include
documents, library, cache, and tmp.
Devices & system state¶
| Tool | What it does |
|---|---|
π listDevices |
Lists booted devices using the shared device description: identity, runtime, form factor, lifecycle, and session summary; a note points to MCP resources for image detail. |
πΌοΈ listDeviceImages |
Lists configured images using the same canonical identity, runtime, display, lifecycle, provenance, and capability inventory shape as the images resource. |
π€ getAndroid / π getApple |
Finds or recovers an Android AVD or iOS Simulator for automation; Android identity includes API level and OS version when known. |
π§± provisionDevice |
Provisions an exact virtual-device identity, with optional resource configuration before automation readiness. |
βοΈ setDeviceResources |
Configures selected device resources and returns verified, unsupported, or unknown state; omitted settings stay unchanged. Disabled by default: enable it with setToolEnabled (case-sensitive setDeviceResources) or --enable-tool setDeviceResources before use. |
π§ setActiveDevice |
Sets the active device. |
β killDevice / π§Ή deleteDevice |
Stops a device, or stops and permanently deletes it. Both accept force: true, which drops every AVD-name comparison for a wedged Android emulator β the emulator-console confirmation and the platform kill’s own re-discovery check β and acts on whatever occupies the serial; it does not bypass serial selection, nor the refusals raised when the pooled entry was retired and replaced mid-action, or when no booted target can be identified at all. |
πΈ deviceSnapshot |
Captures or restores a device snapshot. |
π rotate |
Changes device orientation. |
π openLink |
Opens web URLs or routes app and universal deep links. |
π§° homeScreen / recentApps / systemTray |
Controls core system surfaces and notifications. |
π wakeAndUnlock |
Wakes and unlocks the keyguard. |
π changeLocalization |
Changes locale, time zone, text direction, time format, and calendar. |
βοΈ getDeviceState / βοΈ setDeviceState |
Reads or changes Do Not Disturb, simulator biometric enrollment, and network condition. getDeviceState also reads back the Android connectivity toggles β airplaneMode, wifiEnabled, bluetoothEnabled, locationEnabled β in a single adb round-trip, so a toggle can be checked before it is flipped; a bare call returns doNotDisturb + connectivity, and include selects any subset. A connectivity field is true/false, or omitted when the device could not answer it (key absent on this API level, or an unparsable value) β omitted never means off. Connectivity is unsupported on iOS: Airplane mode, Wi-Fi, Bluetooth and Location have no simctl/devicectl read verb, and a simulator shares the host’s network stack. Degraded profiles β including offline β are best-effort cellular shaping on an Android emulator (adb emu network β¦/gsm data off plus a best-effort Wi-Fi disable), reported partial: they may not affect Wi-Fi or app traffic. Only reset to none is fully verified. A session restores the network to a clean none state on release. Unsupported on physical Android and all iOS. |
π displayConfig |
Reads or sets font/text scale, effective display density, and light/dark theme for adaptive-layout and large-font accessibility testing. Android supports all three fields (density overrides are best-effort on physical devices); the iOS Simulator supports theme only, via simctl ui appearance; physical iOS is unsupported. Disabled by default β enable it with setToolEnabled (case-sensitive displayConfig) or --enable-tool displayConfig before use. |
𧬠getIosSimulatorCapabilities |
Discovers biometrics for a selected iOS Simulator device type and runtime. |
π« biometricAuth |
Simulates biometric authentication. |
π³ shake |
Shakes an Android emulator or iOS Simulator. |
π phoneCall / π¬ sendSms |
Simulates an Android emulator phone call or incoming SMS. |
π postNotification |
Posts a notification through Android SDK hooks or iOS Simulator push. |
π getNotificationPolicy / π setNotificationPolicy |
Reads or changes app notification and Do Not Disturb policy. |
π getAppPermissions / π setAppPermissions |
Reads or changes app permissions. |
During canonical-shape phase 1, every device surface returns the complete shared description:
static facts are top-level, changing state is under runtime, and the previous nested and flat
aliases remain present as compatibility fields.
Keeping an Android orientation locked¶
rotate preserves its existing behavior when lockOrientation is omitted: it
temporarily disables auto-rotate when necessary, then restores the prior
setting. To keep portrait or landscape orientation in effect for subsequent
actions, pass lockOrientation: true:
{ "orientation": "landscape", "lockOrientation": true }
The result reports orientationLockState as locked, unlocked, or unknown.
A persistent request succeeds only after live rotation and the lock are
confirmed. If lock verification fails, currentOrientation reports the latest
confirmed live orientation, or unknown when it cannot be read.
To restore automatic rotation, pass lockOrientation: false, for example
{ "orientation": "landscape", "lockOrientation": false }. These lock options
are supported only on Android.
Acquiring a device: avdName, udid, and the deviceId alias¶
getAndroid and getApple each accept two ways to name a target; pass one.
getAndroidβavdNamenames a configured Android Virtual Device (thenamefield ofautomobile:devices/images/android). It is the identity AutoMobile uses to boot and coordinate a named AVD: theavdNamepath passesmatchExactName,androidAvdName, and astableTargetfor exact AVD-identity and lifecycle coordination.deviceIdis the copy-paste-from-discovery convenience: it accepts either an already-booted serial such asemulator-5554(theruntime.deviceIdfield ofautomobile:devices/booted/android) or an AVD image name β if it names a defined-but-unbooted AVD,getAndroidcold-boots that image by name. The difference is the coordination hints theavdNamepath passes up front βmatchExactName, anandroidAvdNamestartup-lease hint, and an eagerstableTargetβ so preferavdNamewhen you specifically want to boot or coordinate a named AVD; usedeviceIdto attach to a running device or to boot straight from a discovered identifier.getAppleβudidis the iOS Simulator UDID.deviceIdis an accepted alias forudid: a booted simulator’sruntime.deviceId(fromautomobile:devices/booted/ios) is itsudid, so both fields resolve to the same value.
The deviceId fields exist so the value at runtime.deviceId in listDevices and the
automobile:devices/booted/* resources can be copied straight into
getAndroid/getApple β the discoveryβacquire path (#5870). See the
FAQ for the CLI equivalents.
Network, plans & recording¶
| Tool | What it does |
|---|---|
π network |
Controls network capture and error simulation. |
π mockNetwork / π§Ή clearMockNetwork |
Adds or clears mock network response rules. |
πΈοΈ getNetworkGraph |
Returns the aggregate captured network graph. |
π§ͺ executePlan |
Executes YAML plan steps and stops at the first failure. |
π criticalSection |
Synchronizes devices, then runs steps serially. |
π§ barrier |
Synchronizes devices, then lets them proceed concurrently. |
π recordSteps |
Records MCP calls to YAML; begin and end require –mcp-recording. |
βΊοΈ startTestRecording |
Starts recording user interactions for exportPlan. |
π€ exportPlan |
Stops the active recording and exports a YAML plan. |
π₯ videoRecording |
Starts or stops device video recording. |
Accessibility & session tools¶
| Tool | What it does |
|---|---|
βΏ accessibility |
Reads or controls Android TalkBack and iOS VoiceOver, returning fresh device state. |
π― accessibilityFocus |
Sets or clears Android TalkBack focus by resource ID, text, or content description. |
π setToolEnabled |
Enables or disables AutoMobile tools for the current MCP session β one exact name via toolName, or a batch via toolNames; unknown or hidden names reject the batch, while always-on names are returned in skipped. |
Before acquiring a device, read automobile:tools for every tool’s default enabled/gated state.
On Android and iOS, compact observations fold soft-keyboard keys into a single
keyboard: { visible: true, package: "β¦" } summary plus at most one skeleton row:
<ime> | Keyboard (com.google.android.inputmethod.latin) | input
On iOS, the row is labelled Keyboard (com.apple.keyboard).
That row appears only when the IME exposed at least one bounded accessible
descendant. A keyboard whose window carries no accessible keys β some IMEs
expose none β is still announced by the keyboard summary, with no <ime> row,
because a synthetic row must never claim a box it cannot measure. Treat the
summary as the presence signal and the row as optional.
<ime> is a marker, not a selector β use sendKeys for text input and semantic
keys, or keyboard to open or close it. Everything the IME itself owns folds
into that row, including its toolbar, emoji and clipboard affordances β Gboard
gives those the same key_pos_* ids it gives letter keys
(key_pos_header_access_points_menu, key_pos_switch_to_symbol), and many keys
carry no resource-id at all, so nothing distinguishes them from a keycap. What
stays individually actionable is framework chrome sharing the window: a control
whose resource-id belongs to a DIFFERENT package than the IME, such as
android:id/input_method_nav_back. observe with project: "full" or raw: true retains
the individual keys. Keys are identified from the IME window identity a re-cut
control proxy supplies, and otherwise from the β¦:id/key_pos_* keycap
resource-id family, so the fold also applies on older proxy builds and on the
uiautomator dump path. An absent summary means no IME identity was captured,
not a confirmed hidden keyboard.
A skeleton row omits label entirely when it has none β the key is never
present with a placeholder value. A state-carrying container with no text of its
own (the switchWidget of a Settings row, a scrollable fragment root) takes the
label of its nearest labelled enclosing row, so a checked state is attributable
to the setting it belongs to (com.android.settings:id/switchWidget | Airplane
mode | toggle checked=false).
Action-observation diffs under the default skeleton projection use those same
compact row fields for added and removed nodes; rows with no affordances are
omitted. Their fields.layoutWarnings value is an { added, removed } pair
rather than a whole { from, to } envelope, and excludes Android system-status
bar notification chrome. An artifact-spilled diff keeps its skeleton,
context, and capture metadata inline while the bulky node and field deltas are
available from its artifact pointer.
For the observe β act β observe behavior behind interaction tools, see the interaction loop. For per-session public tool selection, see Dynamic Tools.