Skip to content

tap-agent command reference

Experimental

tap-agent and its export format may change in any release until this notice goes away.

Every tap-agent verb, its arguments and the MCP tool that does the same. The page is generated from the CLI parser and the MCP server, so it matches tap-agent <verb> --help. The tap-agent pages explain the flow; this page is for looking things up.

Conventions

Term Meaning
Target A ref from snapshot (@e12), or key=value terms joined by commas, all of which must match. Keys: id, text, text~, desc, desc~, class, hint, pkg, index. ~= means contains. A target matches anywhere on the screen; pkg= keeps it to one app's nodes.
-s, --session NAME The session to use (default $TAP_AGENT_SESSION, else agent). Every verb but mcp and skill takes it.
-d, --device SERIAL Needed only when the session holds several devices. Every verb that runs on a device takes it.
--settle After the step, wait for the screen to stop changing and print the difference (+ added, - removed).
Durations --timeout, --idle, --wait-for-device: 500ms, 10s, 2m, or a number of seconds.
Files screenshot, capture and pull write under .tap/agent/ unless -o says otherwise, and print the path.
Exit codes 0 ok, 1 the step failed (the reason is on stderr), 2 usage, 3 no server running (tap start).
MCP Every tool also takes session; tools that run on a device take device. Actions take settle.

At a glance

Command What it does MCP tool
devices List the devices ADB sees and who holds them devices
attach Attach a device to the session (created if needed) attach
sessions List sessions with their devices sessions
release End the session and detach its devices release
snapshot Print the screen, one node per line with its ref snapshot
settle Wait for the screen to stop changing, then print what changed settle
wait Wait until a target is visible (or gone, or exactly one node) wait_for
activity Print the activity on top of the screen (package/class) foreground_activity
screenshot Save a PNG and print its path screenshot
capture Save screenshot, hierarchy, device info and driver log capture
tap Tap a node tap
fill Replace a field's text (no key events) fill
type Type key events into the focused field type_text
clear Clear a field's text clear
submit Run a focused field's keyboard action (Search, Go, Send, Done, …); API 30+ submit
action List a node's accessibility actions, or perform one as a screen reader does (no touch) accessibility_action
progress Set a slider (SeekBar, Slider, RatingBar) to a value in its own units set_progress
keyboard Whether a soft keyboard shows, or hide it keyboard
scroll Scroll a node towards a content edge (down reveals content below) scroll
swipe Swipe across a node, the finger moving in the direction swipe
fling Fling a node towards a content edge, as for scroll; content may keep moving fling
drag Long-press a node, move it onto another node and drop it drag
pinch Pinch a node open (fingers apart, zoom in) or closed pinch
key Press a key: back, home, recents, enter, tab, delete, … or a key code press_key
panel Open the notification shade or quick settings (key back closes it) open_panel
rotate Rotate the display and keep it there (auto: back to the sensor) rotate
screen Screen state, or turn it on/off, or wake it and dismiss a keyguard without a PIN screen
app App lifecycle: launch, cold-launch, foreground, background, open-link, stop, clear, install, uninstall, grant, revoke, granted, running, locale app
permission List the permission dialog's buttons, or press one permission
condition Device conditions (animations, dark mode, font scale, density, network switches, languages, stay awake, accessibility display): print or change until release condition
location Mock the device location until release set_location
notification List the device's notifications, or wait for, open or dismiss one (read as data; the shade stays closed) notification
toast Wait for a toast (shown in the last 3.5s or coming) and print it await_toast
clipboard Print the device clipboard, or set it clipboard
push Copy a local file to the device until release push_file
pull Copy a device file here and print the local path pull_file
media Add a photo or video to the device gallery until release add_media
export Print the session's event log as JSON (every device call, in order) export
mcp Run the MCP server on stdio (same sessions as the CLI) —
skill Print the agent skill (SKILL.md) —

Sessions and devices

A session is a held connection on the server: it outlives each CLI call, is shared by the CLI and the MCP server, and ends on release or after 15 idle minutes. --session NAME (or TAP_AGENT_SESSION) keeps several apart. A device is held by one session at a time, exactly as a test holds it.

devices

List the devices ADB sees and who holds them.

tap-agent devices [-s SESSION]

MCP: devices(): List the devices ADB sees, their state and the session holding each.

attach

Attach a device to the session (created if needed).

tap-agent attach [-s SESSION] [--idle IDLE] [--wait-for-device DURATION] serial
Argument Meaning
serial —
--idle IDLE end the session after this long unused (default 15m)
--wait-for-device DURATION wait this long for a device another session holds

MCP: attach(serial, idle_minutes, wait_for_device_seconds): Attach a device to the session, creating the session if needed. Call this first.

sessions

List sessions with their devices.

tap-agent sessions [-s SESSION]

MCP: sessions(): List sessions, how long each has been idle, and their devices.

release

End the session and detach its devices.

tap-agent release [-s SESSION]

MCP: release(): End the session: detach its devices so others can use them.

Reading the screen

snapshot is the main way to see the screen: text, one node per line, grouped by window, each with a ref (@e12) to act on. A ref names a selector the server found to match exactly that node, and keeps naming it while it stays on screen. Prefer it to screenshot, which an agent has to look at.

snapshot

Print the screen, one node per line with its ref.

tap-agent snapshot [-s SESSION] [-d DEVICE] [-i | --all]
Argument Meaning
-i, --interactive only nodes an action can target
--all every node, layout containers too

MCP: snapshot(view, device): The current screen, one node per line with its ref (@eN).

settle

Wait for the screen to stop changing, then print what changed.

tap-agent settle [-s SESSION] [-d DEVICE] [--full] [--timeout TIMEOUT]
Argument Meaning
--full also print unchanged nodes (=)
--timeout TIMEOUT default 10s

MCP: settle(full, device): Wait for the screen to stop changing, then list what changed since the last snapshot.

wait

Wait until a target is visible (or gone, or exactly one node).

tap-agent wait [-s SESSION] [-d DEVICE] [--gone | --one] [--timeout TIMEOUT]
                      target
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
--gone —
--one —
--timeout TIMEOUT default 10s

MCP: wait_for(target, state, timeout_seconds, device): Wait, polling on the device, until target is visible, gone, or exactly one node.

activity

Print the activity on top of the screen (package/class).

tap-agent activity [-s SESSION] [-d DEVICE]

MCP: foreground_activity(device): The activity on top of the screen as package/class, or that none is resumed (the keyguard shows, or one is starting). Use it to check that a link or a notification opened the right screen.

screenshot

Save a PNG and print its path.

tap-agent screenshot [-s SESSION] [-d DEVICE] [-o OUT]
Argument Meaning
-o, --out OUT file (default .tap/agent/-

MCP: screenshot(device): A PNG of the screen, also saved to disk. Prefer snapshot: it is text and has refs.

capture

Save screenshot, hierarchy, device info and driver log.

tap-agent capture [-s SESSION] [-d DEVICE] [-o OUT]
Argument Meaning
-o, --out OUT directory (default .tap/agent/capture--

MCP: capture(device): Save a screenshot, the hierarchy, device info and the driver log; returns the paths.

Acting on elements

Every action takes a target and needs exactly one matching node: zero is NOT_FOUND, several is AMBIGUOUS, and both fail before anything touches the device. A tap whose point another window covers (a dialog, the shade) fails as NOT_INTERACTABLE / OBSCURED. With --settle, the command then waits for the screen to stop changing and prints what changed, which is usually enough to pick the next step.

tap

Tap a node.

tap-agent tap [-s SESSION] [-d DEVICE] [--settle] [--long | --double] target
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
--settle wait for the screen to settle, then print what changed
--long long-press instead
--double double-tap instead

MCP: tap(target, long, double, settle, device): Tap the one node matching target.

fill

Replace a field's text (no key events).

tap-agent fill [-s SESSION] [-d DEVICE] [--settle] target text
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
text —
--settle wait for the screen to settle, then print what changed

MCP: fill(target, text, settle, device): Replace a field's text (accessibility set-text; no key events).

type

Type key events into the focused field.

tap-agent type [-s SESSION] [-d DEVICE] [--settle] text
Argument Meaning
text —
--settle wait for the screen to settle, then print what changed

MCP: type_text(text, settle, device): Type key events into whatever has input focus (tap a field first).

clear

Clear a field's text.

tap-agent clear [-s SESSION] [-d DEVICE] [--settle] target
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
--settle wait for the screen to settle, then print what changed

MCP: clear(target, settle, device): Clear a field's text.

submit

Run a focused field's keyboard action (Search, Go, Send, Done, …); API 30+.

tap-agent submit [-s SESSION] [-d DEVICE] [--settle] target
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
--settle wait for the screen to settle, then print what changed

MCP: submit(target, settle, device): Run a text field's keyboard action (Search, Go, Send, Done, ... as the app set it up), exactly as the keyboard's action key does; press_key enter is not the same. The field must have input focus (tap it first). Android 11 (API 30)+.

action

List a node's accessibility actions, or perform one as a screen reader does (no touch).

tap-agent action [-s SESSION] [-d DEVICE] [--settle] [--custom] target [name]
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
name a standard action (expand, collapse, dismiss, scroll-forward, ...) or, with --custom, a label; optional
--settle wait for the screen to settle, then print what changed
--custom NAME is a custom action's label (e.g. 'Archive')

MCP: accessibility_action(target, name, custom, settle, device): Perform an accessibility action on a node as a screen reader does (no touch), or list the actions it offers and its range. Use it for what a node offers instead of a gesture: expand/collapse a section, a list item's custom "Archive"/"Delete". An action the node does not offer fails before anything happens.

progress

Set a slider (SeekBar, Slider, RatingBar) to a value in its own units.

tap-agent progress [-s SESSION] [-d DEVICE] [--settle] target value
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
value —
--settle wait for the screen to settle, then print what changed

MCP: set_progress(target, value, settle, device): Set a slider (SeekBar, Slider, RatingBar) to an exact value through accessibility ACTION_SET_PROGRESS. A value outside the node's range fails before anything happens.

keyboard

Whether a soft keyboard shows, or hide it.

tap-agent keyboard [-s SESSION] [-d DEVICE] [--settle] [{state,hide}]
Argument Meaning
action one of state, hide; optional; default state
--settle wait for the screen to settle, then print what changed

MCP: keyboard(action, settle, device): The soft keyboard: is it showing, or hide it.

Gestures

Gestures run on one node, sized relative to it, never at screen coordinates.

scroll

Scroll a node towards a content edge (down reveals content below).

tap-agent scroll [-s SESSION] [-d DEVICE] [--settle] target {up,down,left,right}
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
direction one of up, down, left, right
--settle wait for the screen to settle, then print what changed

MCP: scroll(target, direction, settle, device): One scroll gesture on a scrollable node; down reveals content below.

swipe

Swipe across a node, the finger moving in the direction.

tap-agent swipe [-s SESSION] [-d DEVICE] [--settle] target {up,down,left,right}
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
direction one of up, down, left, right
--settle wait for the screen to settle, then print what changed

MCP: swipe(target, direction, settle, device): One swipe across a node, the finger moving in direction.

fling

Fling a node towards a content edge, as for scroll; content may keep moving.

tap-agent fling [-s SESSION] [-d DEVICE] [--settle] target {up,down,left,right}
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
direction one of up, down, left, right
--settle wait for the screen to settle, then print what changed

MCP: fling(target, direction, settle, device): One fast swipe on a scrollable node towards a content edge, as for scroll; the content may keep moving afterwards (use settle).

drag

Long-press a node, move it onto another node and drop it.

tap-agent drag [-s SESSION] [-d DEVICE] [--settle] target destination
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
destination where to drop it: a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
--settle wait for the screen to settle, then print what changed

MCP: drag(target, destination, settle, device): Long-press the node matching target, move it onto the node matching destination and drop it.

pinch

Pinch a node open (fingers apart, zoom in) or closed.

tap-agent pinch [-s SESSION] [-d DEVICE] [--settle] [--percent PERCENT]
                       target {open,close}
Argument Meaning
target a ref (@e3) or selector terms: id=login, text=Log in, desc=Close, class=Button, …
how one of open, close
--settle wait for the screen to settle, then print what changed
--percent PERCENT how far across the node, 1..100 (default 80)

MCP: pinch(target, how, percent, settle, device): Two-finger pinch on a node (a map, an image).

Keys, system panels and the display

Target the shade's and quick settings' nodes with pkg=com.android.systemui; key back closes them (twice from quick settings on newer Android). A rotation is kept until release, which restores the device's own setting.

key

Press a key: back, home, recents, enter, tab, delete, … or a key code.

tap-agent key [-s SESSION] [-d DEVICE] [--settle] name
Argument Meaning
name —
--settle wait for the screen to settle, then print what changed

MCP: press_key(key, settle, device): Press a key.

panel

Open the notification shade or quick settings (key back closes it).

tap-agent panel [-s SESSION] [-d DEVICE] [--settle] {notifications,quick-settings}
Argument Meaning
name one of notifications, quick-settings
--settle wait for the screen to settle, then print what changed

MCP: open_panel(panel, settle, device): Open a system panel, as a swipe down from the status bar would. Its nodes belong to com.android.systemui (target them with pkg=com.android.systemui); press_key back closes it.

rotate

Rotate the display and keep it there (auto: back to the sensor).

tap-agent rotate [-s SESSION] [-d DEVICE] [--settle]
                        {portrait,landscape,natural,left,upside-down,right,auto}
Argument Meaning
how one of portrait, landscape, natural, left, upside-down, right, auto
--settle wait for the screen to settle, then print what changed

MCP: rotate(how, settle, device): Rotate the display and keep it there. Returns where the display is afterwards: the app may pin its own orientation. The device's rotation settings are restored on release.

screen

Screen state, or turn it on/off, or wake it and dismiss a keyguard without a PIN.

tap-agent screen [-s SESSION] [-d DEVICE] [--settle] [{state,on,off,unlock}]
Argument Meaning
action one of state, on, off, unlock; optional; default state
--settle wait for the screen to settle, then print what changed

MCP: screen(action, settle, device): Screen power and lock screen. A keyguard with a PIN, pattern or password is never unlocked.

Apps and permissions

app <action> <package> [argument] covers the app lifecycle. permission handles the runtime-permission dialog an app shows, whatever app shows it.

app

App lifecycle: launch, cold-launch, foreground, background, open-link, stop, clear, install, uninstall, grant, revoke, granted, running, locale.

tap-agent app [-s SESSION] [-d DEVICE] [--any-app] [--extra KEY[:TYPE]=VALUE]
                     {launch,cold-launch,foreground,background,open-link,stop,clear,install,uninstall,grant,revoke,granted,running,locale}
                     package [argument]
Argument Meaning
action one of launch, cold-launch, foreground, background, open-link, stop, clear, install, uninstall, grant, revoke, granted, running, locale
package the app's package name, e.g. com.example.app
argument activity (launch), URI (open-link), APK path (install), permission (grant, revoke, granted) or languages (locale: fr-FR,en or system); optional
--any-app open-link: let any app handle the link, not only this one
--extra KEY[:TYPE]=VALUE launch/cold-launch: an intent extra; TYPE is string (default), int, long, float or bool; repeat for more

MCP: app(action, package, argument, any_app, extras, device): App lifecycle: launch, cold-launch (force-stop first), foreground (as the launcher would: back where it was), background (home key), open-link (a deep link, restricted to the app unless any_app), stop, clear data, install, uninstall, grant or revoke a runtime permission (revoking stops the app's process), ask whether a permission is granted, whether the app is running, or read or set the app's own languages (locale, API 33+, restored on release).

permission

List the permission dialog's buttons, or press one.

tap-agent permission [-s SESSION] [-d DEVICE] [--settle] [--timeout TIMEOUT]
                            [--accuracy {precise,approximate}]
                            [{allow,allow-foreground-only,allow-one-time,allow-always,allow-selected,allow-all,deny,deny-and-dont-ask-again,keep-foreground-only,keep-one-time}]
Argument Meaning
choice the button to press (omit to list them); one of allow, allow-foreground-only, allow-one-time, allow-always, allow-selected, allow-all, deny, deny-and-dont-ask-again, keep-foreground-only, keep-one-time; optional
--settle wait for the screen to settle, then print what changed
--timeout TIMEOUT how long to wait for the dialog (default 10s)
--accuracy ACCURACY pick Precise or Approximate first (location dialog, Android 12+); one of precise, approximate

MCP: permission(choice, timeout_seconds, accuracy, settle, device): Android's runtime-permission dialog: without a choice, wait for it and list the buttons (and location accuracies) it offers; with one, press that button.

Device conditions and location

Everything changed here is restored on release: animations, dark mode, font scale, density, the network switches, the languages and the accessibility display settings, and the mocked location.

condition

Device conditions (animations, dark mode, font scale, density, network switches, languages, stay awake, accessibility display): print or change until release.

tap-agent condition [-s SESSION] [-d DEVICE]
                           [{animations,dark-mode,font-scale,density,airplane-mode,wifi,mobile-data,locale,stay-awake,high-contrast-text,color-inversion,bold-text}]
                           [value]
Argument Meaning
name omit to print all; one of animations, dark-mode, font-scale, density, airplane-mode, wifi, mobile-data, locale, stay-awake, high-contrast-text, color-inversion, bold-text; optional
value animations/dark-mode/airplane-mode/wifi/mobile-data/stay-awake/high-contrast-text/color-inversion/bold-text: on|off; font-scale: 0.5..2.0; density: dpi or reset; locale: comma-separated BCP-47 tags, e.g. fr-FR,en (omit to print); optional

MCP: condition(name, value, device): Read the device conditions (animations, dark mode, font scale, display density, airplane mode, Wi-Fi, mobile data, the device languages, stay awake while plugged in, high-contrast text, colour inversion, bold text) or change one. A change lasts until release, which restores what the device had, and the result is the value read back. Dark mode and the network switches need API 29+, bold text API 31+; the network switches are real (nothing is mocked).

location

Mock the device location until release.

tap-agent location [-s SESSION] [-d DEVICE] [--accuracy ACCURACY]
                          [--altitude ALTITUDE]
                          latitude longitude
Argument Meaning
latitude -90..90
longitude -180..180
--accuracy ACCURACY in meters (default 5)
--altitude ALTITUDE in meters

MCP: set_location(latitude, longitude, accuracy_m, altitude_m, device): Mock the device location until release (the device's location providers report this fix, and location is turned on if it was off). Call again to move it; release restores the device.

Notifications, toasts and the clipboard

Notifications are read as data: the shade stays closed. Toasts are caught when shown in the last 3.5 s or while waiting.

notification

List the device's notifications, or wait for, open or dismiss one (read as data; the shade stays closed).

tap-agent notification [-s SESSION] [-d DEVICE] [--settle] [--title TITLE]
                              [--text TEXT] [--contains] [--package PACKAGE] [--button BUTTON]
                              [--timeout TIMEOUT]
                              [{list,await,open,dismiss}]
Argument Meaning
action one of list, await, open, dismiss; optional; default list
--settle wait for the screen to settle, then print what changed
--title TITLE the notification's title
--text TEXT the notification's text
--contains title/text are only part of it
--package PACKAGE only this package's notifications
--button BUTTON open: press the action button with this title instead
--timeout TIMEOUT await: default 10s

MCP: notification(action, title, text, contains, package, button, timeout_seconds, settle, device): The device's notifications as data (the shade stays closed; they never appear in snapshot). open and dismiss need exactly one match. The driver gets notification access for the session.

toast

Wait for a toast (shown in the last 3.5s or coming) and print it.

tap-agent toast [-s SESSION] [-d DEVICE] [--contains] [--package PACKAGE]
                       [--timeout TIMEOUT]
                       [text]
Argument Meaning
text the toast's text (omit for any toast); optional
--contains text is only part of the toast
--package PACKAGE only this package's toasts (default: any app's)
--timeout TIMEOUT default 10s

MCP: await_toast(text, contains, package, timeout_seconds, device): Wait for a toast (one shown in the last 3.5 s counts) and return its text and app. Toasts never appear in snapshot: use this to check one.

clipboard

Print the device clipboard, or set it.

tap-agent clipboard [-s SESSION] [-d DEVICE] [text]
Argument Meaning
text put this on the clipboard (omit to print it); optional

MCP: clipboard(text, device): Read the device clipboard as text, or set it.

The bytes stream through the server. What Tap created on the device is removed on release, and an existing file is never overwritten.

push

Copy a local file to the device until release.

tap-agent push [-s SESSION] [-d DEVICE] local device_path
Argument Meaning
local the file on this machine
device_path absolute path on the device; its directory must exist (e.g. /sdcard/Download/a.pdf)

MCP: push_file(local_path, device_path, device): Copy a local file to the device until release. A device file Tap did not push is never overwritten.

pull

Copy a device file here and print the local path.

tap-agent pull [-s SESSION] [-d DEVICE] [-o OUT] device_path
Argument Meaning
device_path absolute path of a regular file on the device
-o, --out OUT file (default .tap/agent/-

MCP: pull_file(device_path, out, device): Copy a device file to this machine; returns the local path.

media

Add a photo or video to the device gallery until release.

tap-agent media [-s SESSION] [-d DEVICE] [--name NAME] local
Argument Meaning
local the image or video on this machine (jpg, png, gif, webp, heic, bmp, mp4, 3gp, webm, mkv, mov)
--name NAME file name on the device (default the local name)

MCP: add_media(local_path, name, device): Add a photo or video to the device gallery (Pictures/Tap or Movies/Tap, indexed so gallery apps and photo pickers list it) until release.

Turning a session into a test

The event log lists every device call the session made, in order, with its outcome; refs appear as the selectors they stood for. See Sessions to tests.

export

Print the session's event log as JSON (every device call, in order).

tap-agent export [-s SESSION] [-o OUT]
Argument Meaning
-o, --out OUT write it to this file instead

MCP: export(path): The session's event log as JSON: every device call it made (commands and app changes), in order, with outcomes and the selectors refs stood for. Export before release: the log ends with the session. Converting it into a test is up to the user.

Agent setup

Register the MCP server with your agent, or give it the CLI with the skill text.

mcp

Run the MCP server on stdio (same sessions as the CLI).

tap-agent mcp

MCP: none (CLI only).

skill

Print the agent skill (SKILL.md).

tap-agent skill

MCP: none (CLI only).