Actions
For a complete discovery, strict selection, scroll, assertion, and capture workflow, see scoped selection walkthrough.
Purpose
Define the canonical ExecutionAction.type values, the exact parameters each action accepts, which values are validated by Node, and what success and failure data an agent can rely on.
Sources
- Canonical action types:
apps/node/src/contracts/aliases.ts - Shared parameter shape:
apps/node/src/contracts/execution.ts - Validation rules:
apps/node/src/domain/executions/validateExecution.ts - CLI-built payload defaults:
apps/node/src/domain/actions/andapps/node/src/domain/observe/ - Android payload parsing:
apps/android/shared/data/operator/src/main/kotlin/clawperator/operator/agent/AgentCommandParser.kt - Android action/result behavior:
apps/android/shared/data/task/src/main/kotlin/clawperator/task/runner/UiAction.ktandUiActionEngine.kt - Android text-entry runtime behavior:
apps/android/shared/data/uitree/src/main/kotlin/clawperator/uitree/UiTreeManagerAndroid.kt
General Rules
| Rule | Meaning |
|---|---|
| Canonical action names only | Stored payloads should use canonical types such as open_uri, wait_for_node, and take_screenshot. Input aliases are normalized before validation. The on-screen log aliases are exact input values, while their parameter keys remain canonical-only. |
| Canonical payload keys still win | Node accepts common input aliases such as snake_case top-level keys, package for applicationId, url for uri, selector for matcher, and value for text, but the normalized payload always uses the canonical field names. The on-screen log actions intentionally reject these parameter aliases. |
params is optional at the schema level |
Action-specific validation then decides whether it is actually required. |
| Selectors live on a separate page | matcher, container, expectedNode, and labelMatcher all use the Selectors NodeMatcher contract. |
StepResult.data is a string map |
Node may attach known keys such as text, path, warn, application_id, error, or message, but most actions do not have a richer static success schema. |
| CLI coverage is narrower than raw JSON | Some advanced fields in ActionParams are accepted only through clawperator exec JSON, not through flat CLI flags. |
| Runtime details are not always Node guarantees | When this page calls out Android-returned success keys, treat them as current runtime behavior verified from Android code, not as a stricter Node-side schema guarantee. |
Action receipts and failure evidence
An accepted click, text operation, swipe, drag, or scroll dispatch is evidence of the Android attempt. It does not verify navigation, persisted state, or any application postcondition. Follow it with a wait, query, read, or snapshot that checks the specific expected state. A wait for a label already present before the click cannot prove navigation.
With the v0.10 Operator, selector-targeted click, text, and scroll actions add
these string-valued fields to data:
| Field | Meaning |
|---|---|
target |
Serialized NodeSummary for the actual dispatch node, from that attempt's capture. Omitted when no target was resolved. |
matched_target |
Originally selected NodeSummary when click fallback dispatches to an ancestor or uses a coordinate gesture. |
candidate_count |
Base-10 count from the selector resolution used for dispatch. |
dispatch_method |
accessibility_action for Android accessibility operations (including service text-input APIs), coordinate_gesture for a gesture, or none before dispatch. |
dispatch_accepted |
"true" or "false". Gesture acceptance is recorded when Android accepts dispatch, before the asynchronous completion callback. |
elapsed_ms |
Base-10 elapsed milliseconds from the Android monotonic clock, including resolution and settling. |
Coordinate clicks report coordinate as serialized JSON { "x": 100, "y": 200 }
and omit target and candidate_count. A failed pre-dispatch action reports
dispatch_method: "none" and dispatch_accepted: "false". Receipts do not add a
copy of the entered text. For bounded scroll searches, the receipt describes the
last dispatch; scrolls_executed counts the loop's gestures. If the target is
already visible, no dispatch is claimed.
Thrown action failures stop the sequence and retain all completed steps plus
one failed step with its original id and actionType. Failed-step errorCode
and top-level errorCode identify the failure; error preserves its message.
Command timeout or cancellation retains collected evidence and emits one terminal
result. Cancellation still stops execution. Existing actions that return a
failed step continue to subsequent actions; Node still reports the execution as
failed. Returned failed steps add data.errorCode while retaining their legacy
data.error code. This sequence policy is unchanged.
Missing application hierarchies include serialized diagnostics JSON with
serviceAvailable, rootAvailable, windowCount, and foregroundPackage.
Unavailable service/window metadata is null; a known missing root is false.
These observations do not require an application root or select another window.
Raw on-screen log actions remain usable without an application hierarchy.
Migration: receipts require the matching v0.10 Operator. Parse JSON fields
explicitly; StepResult.data remains a string map. Coordinate receipt consumers
must parse the new JSON object rather than the older coordinate display string.
Handle the new scroll outcomes below instead of assuming unchanged content is an
edge. No mutation is replayed to obtain a receipt or recover from a failed
post-dispatch observation.
Retry Object Shape
Several actions accept retry, scrollRetry, or clickRetry objects in raw clawperator exec JSON. Node accepts these fields as part of ActionParams, and Android parses them into a retry policy with these keys:
{
"maxAttempts": 4,
"initialDelayMs": 400,
"maxDelayMs": 2000,
"backoffMultiplier": 2,
"jitterRatio": 0.15
}
Meaning:
maxAttemptscounts the initial attempt, so1means no retry.initialDelayMsis the delay before the first retry.maxDelayMscaps exponential backoff growth.backoffMultipliermust be>= 1.0.jitterRatiomust be in[0.0, 1.0].- Android clamps
maxAttemptsto1..10. - Android clamps
initialDelayMsto0..30000. - Android clamps
maxDelayMstoinitialDelayMs..60000. - Android clamps
backoffMultiplierto1.0..5.0. - Android clamps
jitterRatioto0.0..1.0. - if you omit a retry object, Android applies an action-specific default such as
UiReadiness,UiScroll,AppLaunch,AppClose, orNone.
Canonical Types And Input Aliases
Canonical public action types:
open_app
open_uri
close_app
start_recording
stop_recording
wait_for_node
click
scroll_and_click
scroll
scroll_until
read_text
query_ui
enter_text
snapshot
take_screenshot
sleep
press_key
wait_for_navigation
read_key_value_pair
set_on_screen_log
clear_on_screen_log
show_toast
cancel_toast
Input aliases normalized by Node before validation:
| Alias | Canonical type |
|---|---|
open_url |
open_uri |
tap |
click |
press |
click |
wait_for, find, find_node |
wait_for_node |
read |
read_text |
snapshot_ui |
snapshot |
screenshot, capture_screenshot |
take_screenshot |
type_text, text_entry, input_text |
enter_text |
key_press |
press_key |
on_screen_log_set |
set_on_screen_log |
on_screen_log_clear |
clear_on_screen_log |
Common payload-key aliases also accepted on input:
- top-level execution keys:
command_id,task_id,expected_format,timeout_ms - app/package fields:
package,package_id,application_id,app,app_id->applicationId - URI field:
url->uri - matcher fields:
selector,node,element->matcher - raw matcher-object fields:
id,resource_id,text,text_contains,content_desc,content_desc_contains,description,description_contains,accessibility_label,accessibility_label_contains - text-entry field:
value->text - screenshot path fields:
file,filePath,output_path->path - navigation fields:
expected_package,expected_node,timeout_ms - open_app fields:
skip_navigation_wait,navigation_timeout_ms - label selector fields:
label_matcher,label_selector
The on-screen log actions have a deliberately narrow input-alias rule:
- Stored payloads and result
actionTypevalues use canonicalset_on_screen_logandclear_on_screen_log. - At the Node input boundary, exact lower-case
on_screen_log_setandon_screen_log_clearnormalize to those canonical types before validation and dispatch. - Case changes and surrounding whitespace are rejected for both canonical types and aliases.
- Their
paramsobjects accept only the fields documented below and do not translate generic keys such asvaluetotext.
query_ui
Read-only structured inspection from one fresh Android tree capture. The CLI is
clawperator query; the named MCP tool is query_ui. All use the Android resolver
shared with existing node-targeted actions.
| Parameter | Default | Contract |
|---|---|---|
matcher |
omitted | Optional NodeMatcher; omit to match all eligible nodes. An explicit empty object is invalid. |
visibility |
"on_screen" |
"on_screen" or "all" |
limit |
100 |
Integer from 1 through 1000 |
Queries do not wait for navigation to settle. After a navigation action, use
clawperator wait with the expected destination selector (MCP: wait; raw:
wait_for_node), then query. Zero matches describe that capture only; they do not
prove that a destination has finished loading. A wait is also a separate capture,
so callers must still inspect the subsequent query result.
If Android supplies no hierarchy, the envelope fails with
errorCode="UI_TREE_UNAVAILABLE". Completed steps and the failed query_ui step
are retained, and later actions do not run. Failed-step data contains errorCode,
a human-readable error, and serialized JSON diagnostics with
serviceAvailable, rootAvailable, windowCount, and foregroundPackage.
Unknown facts are null; rootAvailable is false for the failed capture.
No data.query is emitted. A screenshot can remain available when accessibility
hierarchy access is unavailable. This error does not identify the platform cause
or promise that retrying will expose a restricted screen. Named MCP returns the
same error code and envelope.
Zero, one, or multiple matches all succeed. data.query is a serialized JSON
string with this shape:
{
"schemaVersion": 1,
"snapshotId": "observation-local-id",
"capturedAt": "2026-01-01T00:00:00Z",
"totalMatches": 1,
"returnedCount": 1,
"truncated": false,
"nodes": [{
"nodePath": "0.2",
"parentPath": "0",
"resourceId": "example:id/switch",
"className": "android.widget.Switch",
"role": "switch",
"label": "",
"contentDescription": null,
"bounds": {"left": 10, "top": 30, "right": 110, "bottom": 130},
"visibleToUser": true,
"onScreen": true,
"enabled": true,
"clickable": true,
"checkable": true,
"checked": false,
"selected": false,
"scrollable": false,
"accessibilityDataSensitive": false
}]
}
totalMatches counts nodes before the limit, including nodes with blank labels.
returnedCount is the array length. truncated means the limit omitted whole
nodes. Unavailable state stays null, distinct from false. clickable reports
the platform node's clickability when captured, rather than inherited ancestor
clickability used by legacy action dispatch.
accessibilityDataSensitive reports Android's per-node accessibility-data flag
at capture time. The flag is available on Android 14 (API 34) and later:
| Value | Meaning |
|---|---|
true |
Android reports the node's accessibility data as sensitive. |
false |
Android reports the node's accessibility data as non-sensitive. |
null |
The device runs an earlier Android version, the node is a fallback, or the flag could not be read. |
Queries emit this field even when it is null. When consuming a payload with the field absent, treat it as unknown. Queries and XML capture do not require API 34; only this flag does. A filtered query reports only its returned nodes, so use an unfiltered query to inspect root sensitivity.
Raw XML emits accessibility-data-sensitive="true" or "false" when known,
and omits the attribute when unknown. XML and queries capture independently;
compare stable fixture nodes, not observation paths. Sensitivity does not change
matching, success, redaction, or export behavior. It does not establish private
browsing, screenshot protection, password status, or whether content is safe to
share. Verify browser-mode indicators and behavior separately.
Nodes are in preorder. Paths use child indices in the captured UiNode tree,
rooted at "0", and retain their original indices across visibility filtering.
The root's parentPath is null. Paths and snapshot IDs are observation-local;
they are neither stable cross-capture IDs nor valid action targets. capturedAt
is the APK's UTC timestamp immediately after tree capture. XML is a separate
capture with no guaranteed shared node identity.
visibleToUser is the platform flag. onScreen follows the existing action
eligibility rule: positive normalized bounds, platform visibility, screen
intersection, and ancestor pruning. The existing root-retention exception remains:
the root is retained even when ineligible, with its descendants pruned. Neither
flag proves visual non-occlusion. all includes offscreen and hidden captured
nodes; their onScreen value still reports the same action eligibility.
A UTF-8 data.query payload above 256 KiB fails with PAYLOAD_TOO_LARGE; JSON is
never cut to fit. Reduce limit or narrow the matcher. This response guard is
separate from the execution request size limit. Raw XML snapshots remain
available and add visible-to-user without restructuring the hierarchy.
clawperator query --device <device_serial> --operator-package com.clawperator.operator.dev --visibility all --limit 100
clawperator query --matcher-json '{"descendant":{"textEquals":"Display"}}'
The CLI accepts each of --limit and --visibility at most once. Repeating
either flag, even with the same value, returns a structured USAGE error and
exit code 1 before device execution.
Runnable Node consumer
From a repository checkout, build and run the tested query consumer example:
npm --prefix apps/node ci
npm --prefix apps/node run build
node apps/node/dist/examples/query-consumer.js --device <device_serial> --operator-package com.clawperator.operator.dev --visibility all --limit 1000
The example invokes the CLI built in that checkout. It accepts query flags and
omits the matcher by default for all-node discovery. An explicit
--matcher-json '{}' (or --selector '{}') is invalid; remove that flag and its
value to discover all eligible nodes. Other node-targeted actions still require
an appropriate selector.
Before returning an inventory, the consumer checks the process exit, signal and
spawn error; canonical terminal evidence; successful envelope and every step;
and exactly one query_ui step with ID query. It parses that step's string
data.query, validates schema version 1 and node field types, checks count
consistency, and rejects truncation. consumeQuery(output, queryStepId) can
select an explicitly named step when adapting the local example to a multi-step
response. It is example-local validation, not an exported SDK accessor.
Success prints commandId, taskId, the decoded query, and the original
process output in diagnostics. Failure exits with code 1 and prints a message
and the original output to stderr, including any available envelope and IDs.
Preserve those diagnostics when investigating failures. Unknown nullable states
remain null; an omitted accessibilityDataSensitive remains unknown.
To observe refusal of a partial inventory on a screen with multiple nodes:
node apps/node/dist/examples/query-consumer.js --device <device_serial> --operator-package com.clawperator.operator.dev --visibility all --limit 1
A truncated inventory cannot prove absence or uniqueness. Increase the limit (up to 1000) or narrow the matcher, recognizing that a filtered result only covers that filter. Even a complete result describes one capture and its visibility scope, not future state or completion of navigation. Zero matches are valid for that capture. The original response remains available on both success and failure; the canonical envelope and string payload are unchanged.
--matcher-json and --selector name the same JSON input and are mutually
exclusive with simple selector flags (--text, --text-contains, --id, --desc,
--desc-contains, --role). Omitting all selector flags matches all eligible nodes.
Full Payload Example
{
"commandId": "open-settings-and-snapshot",
"taskId": "open-settings-and-snapshot",
"source": "agent-loop",
"expectedFormat": "android-ui-automator",
"timeoutMs": 30000,
"actions": [
{
"id": "open-1",
"type": "open_app",
"params": {
"applicationId": "com.android.settings"
}
},
{
"id": "wait-1",
"type": "wait_for_navigation",
"params": {
"expectedPackage": "com.android.settings",
"timeoutMs": 5000
}
},
{
"id": "snap-1",
"type": "snapshot"
}
],
"mode": "direct"
}
Success condition for that payload:
envelope.status == "success"- every
envelope.stepResults[i].success == true envelope.stepResults[2].actionType == "snapshot""text" in envelope.stepResults[2].data
Action Reference
Non-strict first-match selection adds data.selection_warning when duplicate
candidates are observed, with a hint to use --strict (params.strict=true).
This advisory field does not change action success. See
duplicate-selection hints.
All node-targeted actions below support optional boolean params.strict and an
optional params.container matcher: click, enter_text, read_text,
wait_for_node, scroll, scroll_until, and scroll_and_click. See
strict selection for action-specific
absence, ambiguity, container, and compatibility rules. Coordinate clicks cannot
use strict mode or a container. Strict failures return string-valued
data.error, data.candidate_count, and serialized JSON in data.candidates.
click
| Field | Valid values |
|---|---|
| Required | exactly one of params.matcher or params.coordinate |
matcher |
any non-empty NodeMatcher |
coordinate |
{ "x": <int >= 0>, "y": <int >= 0> } |
clickType |
optional string; CLI builders use "default", "long_click", or "focus" |
retry |
optional retry object in raw exec JSON; Android defaults to UiReadiness |
Rules:
matcherandcoordinateare mutually exclusive.clickType = "focus"is invalid withcoordinate.- CLI defaults to
"default"and omits the field from the payload.
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDfor missing selector, dual selector modes, invalid coordinates, or unsupportedclickTypecombinations- runtime step failures such as
NODE_NOT_FOUND,NODE_NOT_CLICKABLE,GESTURE_FAILED
Example:
{
"id": "click-1",
"type": "click",
"params": {
"matcher": { "textEquals": "Settings" },
"clickType": "long_click"
}
}
swipe
Move one finger immediately along a straight line between two screen coordinates, then release. This does not require a UI node or scrollable container. It has no initial hold and does not perform drag and drop. Use drag when the app needs a long press before movement.
| Field | Valid values |
|---|---|
start |
required object with only integer x and y, each in [0, 2147483647] |
end |
required object with only integer x and y, each in [0, 2147483647]; must differ from start |
durationMs |
required integer in [1, 10000]; no default |
Coordinates are physical screen pixels on the default display in its current
orientation, with origin at the top left. Both endpoints must be inside the
current display (x < width, y < height); Android checks these bounds before
dispatch. The action accepts no selector, container, retry, or additional params.
Gesture injection requires Android 7.0 (API 24) or later and an available
accessibility service.
clawperator swipe --start 100 500 --end 800 500 --duration-ms 300
Raw execution action (also usable through HTTP POST /execute):
{
"id": "swipe-1",
"type": "swipe",
"params": {
"start": { "x": 100, "y": 500 },
"end": { "x": 800, "y": 500 },
"durationMs": 300
}
}
Success means Android's gesture completion callback fired. It does not prove that a snackbar was dismissed or content moved; inspect the resulting app state with a query or snapshot. The action dispatches once without automatic replay.
Successful step data includes start and end as JSON-encoded coordinate
objects, duration_ms as a string, and the standard dispatch_method,
dispatch_accepted, and elapsed_ms receipt fields. A dispatched swipe uses
dispatch_method: "coordinate_gesture".
Missing, invalid, or extra parameters fail Node validation with
EXECUTION_VALIDATION_FAILED. Android reports GESTURE_FAILED if coordinates
are outside the display, gesture injection is unavailable, or the gesture is
rejected or cancelled. A gesture accepted and later cancelled retains
dispatch_accepted: "true" on the failed step. Command timeout/cancellation
retains dispatch evidence and does not replay the gesture; a gesture already
accepted by Android may finish after the caller stops waiting.
drag
Press at a screen coordinate, hold without moving, move in a straight line while
keeping the same pointer down, then release. Requires Android 8 (API 26) or later
and an available accessibility service. Unlike swipe, this action has an
explicit initial hold. Choose a hold long enough for the target app to enter
its drag state. The required hold duration depends on the target app.
| Field | Valid values |
|---|---|
start |
required object with only integer x and y, each in [0, 2147483647] |
end |
required object with only integer x and y, each in [0, 2147483647]; must differ from start |
holdDurationMs |
required integer in [1, 10000]; no default |
moveDurationMs |
required integer in [1, 10000]; no default |
Coordinates are physical screen pixels on the current default display, with origin at the top left. Android rejects endpoints outside its bounds before dispatch. No selector, grid position, path waypoints, retry, or extra params are accepted. Find the source item with a snapshot and start inside its bounds. Choosing a destination and interpreting the result belong in the agent or app-specific skill.
clawperator drag --start 600 1600 --end 200 1000 \
--hold-duration-ms 1200 --move-duration-ms 800 --device <device_serial>
The flat CLI defaults to a 30000 ms execution budget; --timeout <ms> overrides
it. Budget for the hold, movement, and scheduling overhead. In a multi-action
execution, timeoutMs covers the entire sequence, not each gesture separately.
For a local development Operator, also pass
--operator-package com.clawperator.operator.dev consistently on every command.
Raw execution action, also usable through HTTP POST /execute and the MCP
drag tool with the same four parameter fields:
{
"id": "drag-1",
"type": "drag",
"params": {
"start": { "x": 600, "y": 1600 },
"end": { "x": 200, "y": 1000 },
"holdDurationMs": 1200,
"moveDurationMs": 800
}
}
Success means Android completed the gesture, including pointer release. It does not prove a successful drop. Query or snapshot the resulting app state; check that the intended item reached the destination. This action provides a straight same-screen gesture; app-specific drop behavior is not guaranteed.
Successful step data includes JSON-encoded start and end, string-valued
hold_duration_ms and move_duration_ms, plus dispatch_method,
dispatch_accepted, and elapsed_ms. A dispatched drag uses
dispatch_method: "coordinate_gesture". Once the hold is accepted,
dispatch_accepted stays "true" even if movement fails.
Invalid parameters produce EXECUTION_VALIDATION_FAILED at the Node boundary.
Android reports GESTURE_UNSUPPORTED below API 26, or GESTURE_FAILED for
out-of-display coordinates, an unavailable service, rejection, or platform
cancellation. The execution deadline bounds missing or delayed callbacks and
reports COMMAND_TIMEOUT.
The action is never automatically replayed. On cancellation before movement, Android attempts to release the held pointer without moving it. Cleanup is best effort if the service or platform is unavailable. An already accepted movement can finish and release at its endpoint after command cancellation. Timeout and cancellation do not undo application effects; inspect current state before deciding whether to act again.
scroll
| Field | Valid values |
|---|---|
| Required | none |
direction |
optional string in down, up, left, right |
container |
optional NodeMatcher |
distanceRatio |
optional number in [0.0, 1.0] |
settleDelayMs |
optional number in [0, 10000] |
findFirstScrollableChild |
optional boolean in raw exec JSON; Android defaults to true |
retry |
optional retry object in raw exec JSON; Android defaults to None for plain scroll |
Semantics:
- if
directionis omitted in raw JSON, Node validation allows omission - Android defaults omitted
directiontodown - the flat CLI always sets a direction explicitly
containerscopes the scroll to a matched scrollable containerdistanceRatioandsettleDelayMsare advanced tuning fields for raw JSON execution- if
findFirstScrollableChild == trueand the matched container is not itself scrollable, Android walks down to the first scrollable descendant; strict mode requires that eligible descendant to be unique retrycovers pre-dispatch container resolution; an exception after dispatch does not replay the gesture
Success and progress data:
scroll_outcome,direction,distance_ratio,settle_delay_ms, and optionalresolved_containerretain their existing names; dispatch receipts are described above.progressis serialized JSON withbeforeSignature,afterSignature,comparable, andreason. Available signatures are bounded SHA-256 hashes; raw node text is not included. Missing signatures arenull.- Comparison re-resolves the same scoped container. Ambiguous or changed identity
is not comparable, even if the screen appears to have moved. A container that
remains identifiable but stops reporting
scrollablecan still produce comparable progress; eligibility loss alone is notcontainer_lost.
scroll_outcome |
Observation | Step success |
|---|---|---|
moved |
Comparable signatures changed | true |
no_movement |
Comparable signatures are unchanged | true |
unknown |
Missing signatures or an ambiguous/incomparable container | true |
container_lost |
Container or hierarchy disappeared after the gesture | false |
gesture_failed |
Gesture was rejected or did not complete successfully | false |
edge_reached |
Reserved for explicitly instrumented platform boundary evidence; the current runtime does not emit it | n/a |
An accepted gesture may later be cancelled by Android. In that case
dispatch_accepted remains "true", while scroll_outcome is gesture_failed.
Neither no_movement nor unknown proves the container is at an edge.
Common failures:
EXECUTION_VALIDATION_FAILEDfor invaliddirection,distanceRatio, orsettleDelayMs- runtime step failures such as
CONTAINER_NOT_FOUND,CONTAINER_NOT_SCROLLABLE,GESTURE_FAILED
Example:
{
"id": "scroll-1",
"type": "scroll",
"params": {
"direction": "down",
"container": { "resourceId": "android:id/list" },
"distanceRatio": 0.7,
"settleDelayMs": 250
}
}
scroll_until
| Field | Valid values |
|---|---|
| Required | none at schema level; matcher becomes required when clickAfter == true |
direction |
optional string in down, up, left, right |
matcher |
optional NodeMatcher |
container |
optional NodeMatcher |
clickAfter |
optional boolean |
distanceRatio |
optional number in [0.0, 1.0] |
settleDelayMs |
optional number in [0, 10000] |
maxScrolls |
optional integer in [1, 200] |
maxDurationMs |
optional number in [0, 120000] |
noPositionChangeThreshold |
optional integer in [1, 20] |
findFirstScrollableChild |
optional boolean in raw exec JSON; Android defaults to true |
clickType |
optional string in raw exec JSON; Android parses the same click types used by click |
Semantics:
- without
clickAfter, the action scrolls until the target becomes visible or the loop terminates - with
clickAfter: true, the same action requiresmatcherand turns into “scroll then click” - the flat CLI exposes only the core controls; advanced tuning requires raw JSON via
clawperator exec - Android defaults omitted
directiontodown,distanceRatioto0.7,settleDelayMsto250,maxScrollsto20,maxDurationMsto10000,noPositionChangeThresholdto3, andfindFirstScrollableChildtotrue maxScrollsis the hard cap on how many scroll steps Android will attemptmaxDurationMsis checked against monotonic elapsed time before each gesture; the current gesture and bounded settle/target checks may finish after that threshold, while the command timeout cancels executionnoPositionChangeThresholdstops the loop after that many consecutiveno_movement, signature-onlyunknown, or rejected gestures; loss of the original container identity terminates withCONTAINER_LOST- after choosing a scroll container, target observations and the requested click stay within that original container's descendants, including for legacy unscoped searches; an exhausted search cannot be changed to success by a target outside that scope
- an identifiable container that stops reporting
scrollablestill allows a revealed target to satisfy the search and the requested click to run once; if the target remains absent after bounded observation, the search terminates withCONTAINER_NOT_SCROLLABLEwithout scrolling a different container - initially visible targets retain legacy unscoped matching when neither strict selection nor a container is requested
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDfor invalid direction or out-of-range tuning fields- runtime step failures such as
NODE_NOT_FOUND,CONTAINER_NOT_FOUND,CONTAINER_NOT_SCROLLABLE
Example:
{
"id": "scroll-until-1",
"type": "scroll_until",
"params": {
"direction": "down",
"matcher": { "textEquals": "About phone" },
"maxScrolls": 25,
"maxDurationMs": 10000,
"noPositionChangeThreshold": 3
}
}
scroll_and_click
| Field | Valid values |
|---|---|
| Required | matcher |
direction |
optional string in down, up, left, right |
matcher |
required NodeMatcher |
container |
optional NodeMatcher |
clickAfter |
optional boolean in raw exec JSON; Android defaults it to true |
maxSwipes |
optional integer in raw exec JSON; Android defaults it to 10 and clamps it to [1, 50] |
distanceRatio |
optional number in raw exec JSON; Android defaults it to 0.7 and clamps it to [0.0, 1.0] |
settleDelayMs |
optional number in raw exec JSON; Android defaults it to 250 and clamps it to [0, 10000] |
findFirstScrollableChild |
optional boolean in raw exec JSON; Android defaults it to true |
clickType |
optional string in raw exec JSON; Android parses the same click types used by click |
scrollRetry |
optional retry object in raw exec JSON; Android defaults to UiScroll |
clickRetry |
optional retry object in raw exec JSON; Android defaults to UiReadiness |
Semantics:
- this is the canonical action type produced by
scroll-until --clickandscroll-and-click - unlike raw
scroll_until, this action is optimized for “scroll to target, then click target” maxSwipesis the safety cap on how many swipes Android performs before failing- scroll and view refresh remain bounded by
maxSwipes; mutations are not replayed after a post-dispatch failure - target observation, eligibility transitions, and final click scoping follow the same rules as
scroll_until clickRetryapplies only to the final click after the target is visible- setting
clickAfter: falseis accepted in rawexecJSON and makes Android stop after revealing the target, but the flat CLI does not emit that variant forscroll_and_click
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDifmatcheris absent- runtime scroll or click failures, including
NODE_NOT_FOUND
Example:
{
"id": "scroll-click-1",
"type": "scroll_and_click",
"params": {
"matcher": { "textEquals": "Submit" },
"direction": "down"
}
}
read_text
| Field | Valid values |
|---|---|
| Required | matcher |
matcher |
required NodeMatcher |
all |
optional boolean; when true, request all matches instead of the first match |
container |
optional NodeMatcher |
validator |
optional string; current validation adds special behavior only for "regex" |
validatorPattern |
required non-empty valid regex string when validator == "regex" |
retry |
optional retry object in raw exec JSON; Android defaults to UiReadiness |
Semantics:
- if
validatoris omitted, no validator-specific Node rule runs - if
validator == "regex",validatorPatternmust exist and compile as a regex - other validator strings are accepted by the current Node schema, but this repo does not add extra Node-side validation semantics for them
- current Android parser accepts only
temperature,version, andregex; any other validator string is rejected at runtime all: trueasks Android to return all matching text values instead of only the first match
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDfor missingmatcheror invalid regex configuration- runtime failures such as
NODE_NOT_FOUND
Example:
{
"id": "read-1",
"type": "read_text",
"params": {
"matcher": { "textContains": "Order" },
"validator": "regex",
"validatorPattern": "^ORD-[0-9]{6}$",
"all": false
}
}
read_key_value_pair
| Field | Valid values |
|---|---|
| Required | labelMatcher |
labelMatcher |
required NodeMatcher |
all |
optional boolean |
retry |
optional retry object in raw exec JSON; Android defaults to UiReadiness |
Semantics:
- built by the flat
read-valueCLI command - uses a label matcher rather than a generic element matcher
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDwhenlabelMatcheris absent
Example:
{
"id": "read-value-1",
"type": "read_key_value_pair",
"params": {
"labelMatcher": { "textEquals": "Battery" },
"all": false
}
}
enter_text
| Field | Valid values |
|---|---|
| Required | matcher, text |
matcher |
required NodeMatcher |
text |
required non-empty string |
clear |
optional boolean |
submit |
optional boolean |
retry |
optional retry object in raw exec JSON; Android defaults to UiReadiness |
Semantics:
submitdefaults tofalsein the built-in CLI builderscleardefaults tofalsein the built-in CLI builders- Android uses an internal first-match-wins text-entry ladder while keeping the public
enter_textshape unchanged - Android prefers the editable node
ACTION_SET_TEXTroute when it is available because that path already matches current replace-text semantics - on that
ACTION_SET_TEXTroute,clear == truefirst dispatchesACTION_SET_TEXT(""), then dispatchesACTION_SET_TEXTwith the requestedtext - on that same
ACTION_SET_TEXTroute,clear == falseor omitted keeps the existing singleACTION_SET_TEXTbehavior - if the requested clear step fails on the
ACTION_SET_TEXTroute, Android stops before the real text set for that legacy strategy; on Android 13+ it can still continue to the accessibility input-connection fallback when that route is available, otherwise the action fails - on Android 13+ (
Build.VERSION_CODES.TIRAMISU) when the legacyACTION_SET_TEXTroute is unavailable or does not complete successfully, Android can fall back to the accessibility input-connection path for custom editors - that API 33 fallback still preserves replace-style behavior by moving the cursor to the end, deleting preceding text, then committing the replacement text
- that API 33 replace sequence also preserves
clear == truesemantics even though there is no separate public strategy flag submit == trueis best effort after successful text entry- on the legacy route, Android prefers
ACTION_IME_ENTERwhen the node exposes it and falls back to a click when it does not - on the API 33 input-connection route, Android prefers
performEditorAction(...) - if text entry succeeds but no truthful submit action is available, the step still succeeds and
submitdoes not become a new hard-failure condition
Success data:
- Node does not declare a richer static schema here
data.text,data.clear, anddata.submitretain the requested values;submitis a request, not an outcomedata.text_entryis"accepted"after Android accepts text entrydata.submissionis"not_requested","accepted", or"unavailable"data.submit_methodis"not_requested","ime_action","click_fallback", or"submit_unavailable"
submission: "accepted" pairs with ime_action or click_fallback and means
Android accepted that action. A fallback click can merely focus the field.
submission: "unavailable" pairs with submit_unavailable when no supported
submission path succeeds, including rejected actions; text entry still succeeds.
No submission request produces not_requested in both fields.
These fields report action acceptance, not read-back verification of text or proof of navigation. After typing a URL or search query, the agent or browser skill must observe the destination before declaring navigation complete. Do not repeat text entry solely because submission is unavailable. Older Operators may omit these additive fields; absence means unknown, not submission success.
Common failures:
EXECUTION_VALIDATION_FAILEDfor missing matcher or blank text- runtime failures such as
NODE_NOT_FOUND - Android task-status failure payloads use
failure_point = set_text_failedwhen the clear or text-set step cannot be completed
Example:
{
"id": "type-1",
"type": "enter_text",
"params": {
"matcher": { "resourceId": "com.example:id/search" },
"text": "hello world",
"clear": true,
"submit": false
}
}
Verification pattern:
clawperator type "battery" --id "com.android.settings:id/search_src_text" --clear
Success conditions:
- exit code
0 envelope.status == "success"envelope.stepResults[0].actionType == "enter_text"envelope.stepResults[0].success == trueenvelope.stepResults[0].data.clear == "true"
Android live-route verification:
- when validating against the debug operator on device, operator logs include
enter_text strategy=<strategy_name> submit_method=<submit_method> - on the API 33 route, warning-level logs can also include
enter_text strategy=api33_input_connection partial_failure reason=<reason>when the fallback delete step succeeds but the finalcommitText(...)does not - current shipped strategy names are
legacy_action_set_textandapi33_input_connection
press_key
| Field | Valid values |
|---|---|
| Required | key |
key |
case-insensitive string in back, home, recents |
retry |
optional retry object in raw exec JSON; Android defaults to None |
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDfor missing or unsupported key
Example:
{
"id": "press-1",
"type": "press_key",
"params": {
"key": "back"
}
}
wait_for_node
| Field | Valid values |
|---|---|
| Required | matcher |
matcher |
required NodeMatcher |
timeoutMs |
optional number; the current Android parser clamps a provided value to 1..120000; when built by the CLI, it comes from --timeout |
retry |
optional retry object in raw exec JSON; Android defaults to UiReadiness |
Semantics:
- the action-level
timeoutMsis distinct from the execution-leveltimeoutMs - current Node validation does not add a stricter positivity check for this field
- the builder inflates the execution timeout to
max(actionTimeout + 5000, 30000)so the envelope does not expire before the wait finishes
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDwhenmatcheris missing- runtime failure when the target never appears
Example:
{
"id": "wait-1",
"type": "wait_for_node",
"params": {
"matcher": { "textEquals": "Settings" },
"timeoutMs": 5000
}
}
wait_for_navigation
| Field | Valid values |
|---|---|
| Required | at least one of expectedPackage or expectedNode, plus timeoutMs |
expectedPackage |
optional non-empty string up to matcher-length limits |
expectedNode |
optional NodeMatcher |
timeoutMs |
required number in (0, 30000] |
Semantics:
- at least one navigation target must be present
- the CLI builder inflates execution timeout to
max(timeoutMs + 5000, 30000)
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDfor missing target, missing timeout, or timeout above30000
Example:
{
"id": "wait-nav-1",
"type": "wait_for_navigation",
"params": {
"expectedPackage": "com.android.settings",
"timeoutMs": 5000
}
}
snapshot
| Field | Valid values |
|---|---|
| Required | none |
retry |
optional retry object in raw exec JSON; Android defaults to UiReadiness |
Semantics:
- the old
formatparameter is explicitly rejected as removed - built-in builders set execution timeout to
30000unless overridden - snapshots carry XML in canonical result step data with verified chunk transport for large envelopes; older Operators use command-tagged log extraction as described in Snapshot Format
Success data:
data.textcontains the extracted XML hierarchydata.warnmay be added when a snapshot immediately followsclickorscroll_and_clickwithout an intervening sleep
Common failures:
SNAPSHOT_EXTRACTION_FAILEDRESULT_ENVELOPE_TIMEOUT
Example:
{
"id": "snap-1",
"type": "snapshot"
}
show_toast
Request a native Android text toast from the Operator. Use it for brief announcements such as starting a test run. Each call cancels the previous API-requested toast before submitting its replacement. The current API toast is shared across callers for that Operator instance and is separate from incidental Operator messages.
| Parameter | Accepted values | Default |
|---|---|---|
text |
Required string, 1-2048 UTF-16 code units, including a non-whitespace character | None |
duration |
Exactly "short" or "long" |
"short" |
Text is preserved verbatim. Unknown fields, parameter aliases, blank text, null values,
and numeric durations are rejected with EXECUTION_VALIDATION_FAILED at the Node boundary.
There are no toast IDs, queue controls, custom styles, positions, buttons, or millisecond
durations. Use on-screen logs for persistent information.
{
"id": "announce-start",
"type": "show_toast",
"params": {
"text": "Starting test run",
"duration": "short"
}
}
Success means the Operator submitted the request to Android on its main thread. It
does not prove visibility and does not wait for dismissal. Success step data contains
exactly {"submitted":"true","duration":"short"} (or "long"), without echoing text.
An Android submission exception fails the action with ACTION_FAILED.
Android controls the actual duration, layout, and display. Background toasts are rate-limited; on Android 12 and newer with current target SDKs, text toasts show the app icon and at most two lines. Long input may be truncated. See the Android Toast reference and toast guidance.
CLI examples:
clawperator toast "Starting test run"
clawperator toast "Test run complete" --duration long
clawperator toast --cancel
Common flags include --device <device_serial>, --operator-package <package>,
--timeout <ms>, --output json|pretty, and --no-daemon. For local development,
use --operator-package com.clawperator.operator.dev. To send text beginning with
-, put options first and use toast -- "--literal text". The CLI validates before
dispatch and does not automatically replay an uncertain dispatch.
Raw exec, HTTP /execute, and MCP execute accept these actions in the usual
execution envelope, retaining commandId, taskId, and action IDs. A toast can be
the first action in a test sequence; later actions do not wait for it to disappear.
cancel_toast
Cancel the current API-requested toast, including one pending display. Omit params
or pass exactly {}. null and all parameter fields are invalid. Cancellation is
idempotent and succeeds when no API toast exists. It does not cancel another app's
toast or an incidental Operator message. API toast ownership lasts for the Operator
process; it does not survive a process restart.
{ "id": "dismiss-announcement", "type": "cancel_toast" }
The CLI form is clawperator toast --cancel, exclusive with text and --duration.
Success step data is exactly {"submitted":"true"}. This acknowledges completion
of the cancellation request, not observation that the toast has disappeared.
set_on_screen_log
Use this raw action to show one noninteractive diagnostic panel owned by the connected Operator accessibility service. Supply literal text or a live Android-resolved template. CLI conveniences are on-screen-log set --text <text> and on-screen-log set --template <template>. See On-screen logs for lifecycle, capture, and transport details.
| Field | Valid values | Default / meaning |
|---|---|---|
| Required | Exactly one of text or template |
Literal label or live metadata template. |
text |
String with 1..2048 UTF-16 code units, at least one non-whitespace character |
Literal text. LF and TAB are allowed; other control characters are rejected. |
template |
Same input bounds as text; only the nine documented placeholders |
See template vocabulary, escaping and expansion bounds. Mutually exclusive with text. |
anchor |
Exact left or right |
left; physical display edge. |
textAlign |
Exact left or right |
left; alignment inside the panel. |
topOffsetDp |
Integer-valued JSON number 0..1000 |
8; from the usable top edge. |
edgeOffsetDp |
Integer-valued JSON number 0..1000 |
8; inward from the selected usable horizontal edge. |
widthDp |
Integer-valued JSON number 80..600 |
280; full panel width including padding. |
fontSizeSp |
Integer-valued JSON number 8..24 |
12; follows Android font scale. |
textColor |
Exact #RRGGBB or #AARRGGBB |
#FFFFFFFF. |
backgroundColor |
Exact #RRGGBB or #AARRGGBB |
#B3000000. |
ttlMs |
Integer-valued JSON number 1000..3600000 |
300000; local stale-label expiry. |
Rules:
- only the fields in this table are accepted
- do not use named colors, fractional numbers, numeric strings,
null, parameter aliases, or unknown keys - six-digit colors normalize to uppercase opaque eight-digit colors, for example
#a1b2c3becomes#FFA1B2C3 - every successful set replaces the whole existing panel using supplied values and defaults, rather than patching existing state
- malformed input is rejected before dispatch and cannot modify a currently visible panel
Success data has the exact string-valued keys visible, rendered, truncated, anchor, text_align, top_offset_dp, edge_offset_dp, width_dp, font_size_sp, text_color, background_color, ttl_ms, and bounds. The result does not echo caller text or resolved metadata. Bounds and truncation describe the initial draw; live refreshes preserve the original TTL.
Common failures:
EXECUTION_VALIDATION_FAILEDbefore dispatch for malformed raw inputON_SCREEN_LOG_SERVICE_UNAVAILABLE,ON_SCREEN_LOG_LAYOUT_INVALID,ON_SCREEN_LOG_RENDER_FAILED, orON_SCREEN_LOG_RENDER_TIMEOUTfrom the runtime
Example:
{
"id": "set-panel",
"type": "set_on_screen_log",
"params": {
"text": "FLOW-001: Observe settings",
"anchor": "right",
"textAlign": "left",
"topOffsetDp": 0,
"edgeOffsetDp": 12,
"widthDp": 320,
"fontSizeSp": 16,
"textColor": "#a1b2c3",
"backgroundColor": "#7f0a0b0c",
"ttlMs": 12000
}
}
clear_on_screen_log
Remove the current Operator-owned on-screen log panel. It accepts omitted params or exactly {}. Any other value, including null or a nonempty object, is rejected.
Success data is exactly:
{
"visible": "false"
}
Clear succeeds while the panel is already hidden. It does not include a rendered field.
Example:
{
"id": "clear-panel",
"type": "clear_on_screen_log",
"params": {}
}
take_screenshot
| Field | Valid values |
|---|---|
| Required | none |
path |
optional non-empty string |
retry |
optional retry object in raw exec JSON; Android defaults to None |
Semantics:
- if
pathis present, it must not be blank - built-in builders set execution timeout to
30000unless overridden
Success data:
data.pathafter Node verifies and writes the host screenshotdata.captureSource: "host"anddata.persistedAt(host ISO timestamp after the PNG file write completes)data.captureWidthPxanddata.captureHeightPx: original, decoded PNG dimensions in pixels, encoded as decimal strings like other step datadata.coordinateSpace: "screenshot_pixels"anddata.origin: "top_left"
Migration: screenshot step data.capturedAt has been replaced by
data.persistedAt; no compatibility alias is emitted. Update screenshot
consumers to read the new field. It marks host file-write completion, not the
exact instant Android captured the screen. The separate query_ui payload
capturedAt field is unchanged.
These dimensions describe the saved image, not a resized preview or Android dp.
The x axis runs right and the y axis runs down. Pixel indices range from zero to
captureWidthPx - 1 and captureHeightPx - 1. Metadata is published only after PNG validation and
successful persistence. Older captures may omit it; read the original image's
dimensions instead of guessing from its preview.
For an uncropped preview rendered at previewWidthPx by previewHeightPx, map a
point inside the image to the original with
captureXpx = floor(previewXpx * captureWidthPx / previewWidthPx) and
captureYpx = floor(previewYpx * captureHeightPx / previewHeightPx). For example, a 1080 x 2400 PNG
shown at 360 x 800 maps preview point (120, 200) to image point (360, 600).
Measure preview coordinates relative to the image itself: remove padding or
letterboxing first. This formula is not sufficient for cropped or rotated previews.
Image coordinates are not a guarantee about the device's current input space. Before clicking or swiping, verify that the current display orientation and coordinate dimensions match the capture; recapture after rotation, display changes, or navigation. Do not use density scaling to convert pixels to dp. Prefer a fresh semantic selector when available.
The host capture occurs after the runtime envelope, not at the runtime step's
exact instant. A successful fallback clears the superseded
UNSUPPORTED_RUNTIME_SCREENSHOT error, errorCode, and message while preserving
other metadata. A failed capture or artifact write produces
EVIDENCE_CAPTURE_FAILED; it does not become success or expose a stale path.
Common failures:
EXECUTION_VALIDATION_FAILEDfor blank path- timeout or runtime screenshot capture failures
Example:
{
"id": "shot-1",
"type": "take_screenshot",
"params": {
"path": "/tmp/settings.png"
}
}
close_app
| Field | Valid values |
|---|---|
| Required | applicationId |
applicationId |
required non-empty package id string |
retry |
optional retry object in raw exec JSON; Android defaults to AppClose |
Semantics:
- built-in builders default execution timeout to
30000 - Node runs a pre-flight adb force-stop and may normalize an Android-side unsupported close into success
Success data:
data.application_idwhen pre-flight close succeeded
Common failures:
EXECUTION_VALIDATION_FAILEDfor missingapplicationId- adb force-stop failure or package/runtime failures
Example:
{
"id": "close-1",
"type": "close_app",
"params": {
"applicationId": "com.android.settings"
}
}
sleep
| Field | Valid values |
|---|---|
| Required | durationMs |
durationMs |
required number >= 0 and <= the maximum execution timeout constant |
retry |
optional retry object in raw exec JSON; Android defaults to None |
Semantics:
- builder sets execution timeout to
max(durationMs + 5000, globalTimeout, 30000)
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDfor negative or oversized duration
Example:
{
"id": "sleep-1",
"type": "sleep",
"params": {
"durationMs": 1500
}
}
open_app
| Field | Valid values |
|---|---|
| Required | applicationId |
applicationId |
required non-empty package id string |
skipNavigationWait |
optional boolean, defaults to false |
navigationTimeoutMs |
optional integer in [1000, 120000], defaults to 15000 |
retry |
optional retry object in raw exec JSON; Android defaults to AppLaunch |
Semantics:
open_appdispatches the launch intent, then waits until the launched package is the active foreground accessibility package before returning success.- set
skipNavigationWait: trueonly when you intentionally want the older fire-and-forget behavior. navigationTimeoutMscontrols the readiness wait only. It does not change the execution-level timeout.- already-foreground launches succeed without a package-transition race.
- callers that need content to be present after the package is foreground should follow with
wait_for_node. - the
clawperator openCLI exposes--skip-navigation-waitand--navigation-timeout-msfor package targets only; URI targets reject both flags withEXECUTION_VALIDATION_FAILED.
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDfor missingapplicationId- runtime step failures such as
NAVIGATION_TIMEOUTwhen the launched package does not reach the foreground within the wait budget
Example:
{
"id": "open-1",
"type": "open_app",
"params": {
"applicationId": "com.android.settings",
"skipNavigationWait": false,
"navigationTimeoutMs": 15000
}
}
open_uri
| Field | Valid values |
|---|---|
| Required | uri |
uri |
required non-empty string, max length enforced by MAX_URI_LENGTH |
retry |
optional retry object in raw exec JSON; Android defaults to AppLaunch |
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDfor missing or blankuri
Example:
{
"id": "open-uri-1",
"type": "open_uri",
"params": {
"uri": "https://clawperator.com"
}
}
start_recording
| Field | Valid values |
|---|---|
| Required | none |
sessionId |
optional non-blank string |
retry |
optional retry object in raw exec JSON; Android defaults to None |
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDfor blanksessionId- recording-state runtime errors such as
RECORDING_ALREADY_IN_PROGRESS
Example:
{
"id": "record-start-1",
"type": "start_recording",
"params": {
"sessionId": "session-001"
}
}
stop_recording
| Field | Valid values |
|---|---|
| Required | none |
sessionId |
optional non-blank string |
retry |
optional retry object in raw exec JSON; Android defaults to None |
Success data:
- no Node-guaranteed success keys
Common failures:
EXECUTION_VALIDATION_FAILEDfor blanksessionId- recording-state runtime errors such as
RECORDING_NOT_IN_PROGRESS
Example:
{
"id": "record-stop-1",
"type": "stop_recording",
"params": {
"sessionId": "session-001"
}
}
CLI To Action Mapping
| CLI command | Canonical action type | Notes |
|---|---|---|
click |
click |
tap is a CLI synonym |
swipe |
swipe |
explicit endpoints and --duration-ms; no initial hold |
drag |
drag |
explicit endpoints, --hold-duration-ms, and --move-duration-ms |
type |
enter_text |
built from selector + text |
read |
read_text |
supports optional container matcher |
read-value |
read_key_value_pair |
built from label selector flags |
wait |
wait_for_node |
action timeout comes from --timeout |
wait-for-nav |
wait_for_navigation |
requires --timeout |
snapshot |
snapshot |
no action params |
screenshot |
take_screenshot |
optional path |
close |
close_app |
close-app is a CLI synonym |
sleep |
sleep |
duration is positional |
toast <text> |
show_toast |
optional --duration short\|long |
toast --cancel |
cancel_toast |
no text or duration |
open |
open_app or open_uri |
dispatch depends on target string |
press, back |
press_key |
back hardcodes key = "back" |
scroll |
scroll |
container flags optional |
scroll-until |
scroll_until or scroll_and_click |
--click switches to scroll_and_click |
scroll-and-click |
scroll_and_click |
alias that implies click-after |
on-screen-log set --text <text> and on-screen-log clear map to set_on_screen_log and clear_on_screen_log. See On-screen logs for the flags and separate-execution capture sequence. Raw clawperator exec and existing generic execute transports remain supported.
Result Data You Can Rely On
| Action type | Success keys exposed by the current execution runtime |
|---|---|
snapshot |
data.text; optional data.warn |
drag |
JSON-encoded start and end; string-valued hold_duration_ms, move_duration_ms, dispatch_method, dispatch_accepted, and elapsed_ms; see drag |
take_screenshot |
data.path |
close_app |
data.application_id when Node pre-flight succeeded |
set_on_screen_log |
visible, rendered, truncated, normalized style values, and bounds; all values are strings and caller text is omitted |
clear_on_screen_log |
visible with value "false" |
show_toast |
submitted with value "true", and duration with value "short" or "long" |
cancel_toast |
submitted with value "true" |
| all others | no fixed success keys guaranteed by Node |
Concrete success example for take_screenshot:
{
"id": "shot-1",
"actionType": "take_screenshot",
"success": true,
"data": {
"path": "/tmp/settings.png"
}
}
Concrete success example for snapshot:
{
"id": "snap-1",
"actionType": "snapshot",
"success": true,
"data": {
"text": "<hierarchy rotation=\"0\">...</hierarchy>",
"warn": "snapshot captured without a preceding sleep step; UI may not have settled - consider adding a sleep step between click and snapshot"
}
}
For failures, inspect:
envelope.status- first failed
stepResults[i].success == false stepResults[i].data.errorstepResults[i].data.message
Related Pages
Notification and media actions
See notifications for list_notifications, dismiss_notification and invoke_notification_action; see media sessions for list_media_sessions, get_media_status, media_pause, media_play and media_seek. These share canonical execution and result correlation across CLI, HTTP and MCP. Nonempty lists containing only notification/media reads and media pause/play/seek bypass interactive readiness without waking the device. Notification mutations and UI-containing lists retain whole-execution interactive readiness.