Snapshots
Snapshots provide a structured view of the UI and generate current-screen refs.
--actions constraints:
- iOS simulators only. Physical iOS devices, macOS, and Android targets reject the flag.
- It names the affordances an element merged away (iOS
UIAccessibilityCustomAction, React NativeaccessibilityActions), so a card whose reply/options controls are not separate elements still lists them. - The names are for planning and discovery, not invocation. There is no API to trigger one: reach the affordance through the element's detail screen, through the same control exposed as a labeled element elsewhere, or by coordinates from its rect.
- Each merged element costs one accessibility round trip, so the pass is opt-in and bounded. When it cannot read every candidate, the response says how many it read — an absent list on an unread element is not evidence that it has none.
- Mutually exclusive with
--raw. Custom actions are only readable through the private-AX capture path, which the raw diagnostic strategy does not take, so the pair is rejected asINVALID_ARGSbefore any device work — on the CLI, the Node client, and MCP alike. Choose one or the other.
Efficient snapshot usage
- iOS and Android share the same mobile snapshot contract: visible-first output, actionable-now refs, and hidden list content communicated via discovery hints.
- Default to
snapshot -ifor agent loops. - Repeated unfiltered Android snapshots with unchanged presented content and bounds return a compact acknowledgement.
-i,-d,-s,--json, and--rawretain full output. Use--force-fullto re-emit the tree explicitly. - Default snapshot text is an agent-facing, token-efficient view for planning and targeting actions. It is visible-first and may collapse helper/accessibility noise; use
--rawor--jsonwhen you need the full provider tree. - Off-screen interactive content is collapsed into discovery summaries such as
[off-screen below] 3 interactive items: "Privacy", "Battery", "About". - If a target only appears in an off-screen summary, use
scroll <direction>and re-snapshot until the target becomes visible. - When container ownership is known, hidden content is shown inline under the visible scroll/list container, for example
[content above scroll-area hidden]or[content below list hidden]. - Those summaries intentionally show only a few labels for token efficiency. Use
snapshot --rawwhen you need the full off-screen tree instead of the summary. - Add
-s "<label>"(or-s @ref) to keep results screen-local. - Add
-d <depth>when you only need upper hierarchy layers. - If
snapshot -i -d <n>says the interactive output is empty at that depth, retry once without-dbefore taking more shallow snapshots. - Re-snapshot after any UI mutation before reusing refs.
- On Android after navigation or submit, snapshot capture retries suspicious trees for a short post-action deadline and
@refinteractions refresh while that freshness window is active. Ifsnapshot -istill disagrees with the visible screen, trustscreenshot, wait briefly, then take one fresh snapshot instead of looping stale snapshots. - For automation runs affected by Android animation churn, use
settings animations offas an opt-in stabilizer and restore withsettings animations onafter the run. - On a device cloud the tree is read by the provider's driver, so a screen that never goes still — a looping video, a live ticker, continuous animation — gives that read no quiet moment and it can run out of its budget while
screenshotstill returns. The read is cancelled with the request that asked for it, so agent-device stops waiting on it and stops holding the session open for it; the driver's own walk can continue on the provider, where it may still occupy that session's queue. Two dead ends: the read carries its own budget, so a larger--timeoutcannot lengthen it, andsettings animationsis not implemented on hosted WebDriver sessions. - Use
diff snapshotbetween mutations to validate structural changes with lower output volume. - Use
snapshot --diffwhen you discover the feature from snapshot help, but keepdiff snapshotas the default exploration command. - Keep
--rawfor troubleshooting only when you need the full tree instead of visible-first output.
diff snapshot and snapshot --diff behavior:
- First run initializes baseline (
baselineInitialized: truein JSON). - Later runs return unified-style lines (
+added,-removed, unchanged context) and update baseline after each call.
Example output:
iOS capture behavior
Capture tiers are internal. There is no flag that selects a backend; --raw chooses a strategy, and
the strategy owns which tiers it may use.
- Regular (non-
--raw) capture uses the regular visible strategy: it starts with the recursive XCTest tree, and when that returns sparse output for a screen XCTest cannot serialize, it can recover through a query sweep and then, on simulators, a private accessibility backend. - The ladder is bounded by the capture budget rather than retried indefinitely; when the budget is spent, the best payload captured so far is returned.
- Recovery and degradation stay observable instead of being presented as an empty UI. A
recovered capture warns that it fell back to another backend and is safe to continue from; a
sparse capture reports that no backend could read the screen and points you at
screenshotas visual truth plus coordinate taps. Use--jsonand readsnapshotQualitywhen you need the state, backend, and reason behind degraded output. - A sparse
snapshottakes that screenshot for you and returns its path asfallbackScreenshotPath, so the visual fallback costs no extra command. Remote clients download the image through the normal artifact channel before exposing that path. When the screen was reachable but published no accessibility content at all, the warning also names it as a likely app accessibility bug — assistive technologies get the same empty tree. Reasons that describe a limit of this tool instead (a refused or budget-exhausted capture) are not attributed to the app. --rawuses the raw diagnostic strategy: it stays tree-first and preserves strict capture failures, so a real XCTest accessibility serialization error surfaces as an error rather than as an empty tree.- Private-accessibility recovery and
--actionsreads are simulator-specific. Physical iOS devices have no equivalent independent semantic backend; they bound the XCTest work with a probe instead.
Android node metadata
Android snapshot nodes and get attrs (including the digest response) carry the native
selected, editable, password, hintShowing, selectionStart, and selectionEnd facts
whenever the accessibility tree reports them. Explicit false and 0 are kept; an absent field
means the fact was unavailable, not false. hintShowing needs Android API 26 or later.
selectedis the accessibility selected state an app sets on a control — the active bottom-tab or segmented-control item, or the chosen row of a list. Android reports it explicitly astrueorfalse; an older helper APK omits the field, which means the answer is unavailable rather than unselected. Snapshot text marks the node[selected], andis selected, aselected=trueselector, and a Maestroselected:qualifier all match on it.value: ""is an explicitly empty accessibility text; a missingvaluemeans no text was reported. The text of an empty field is its hint on modern Android, so checkhintShowingbefore readingvalueas the entered contents.selectionStart/selectionEndare accessibility selection offsets. They are independent ofeditable(read-only selectable text exposes them too), they are not a character count, and they do not prove that a masked or secure value equals expected text.
