A session, step by step¶
Below is a real session on an API 34 emulator, run from the command line. Over MCP the same steps are tool calls with the same output.
Attach a device¶
$ tap-agent devices
85e49002 FREE
emulator-5554 FREE
$ tap-agent attach emulator-5554
attached emulator-5554 to session 'agent', idle timeout 15m
A session is a held connection on the server. It outlives each CLI call, is shared by the
CLI and the MCP server, and holds the device exclusively, as a test does, until release or
15 idle minutes. --session NAME (or TAP_AGENT_SESSION) keeps several apart.
Read the screen¶
$ tap-agent app cold-launch com.android.settings
cold-launched com.android.settings (pid 14853)
$ tap-agent snapshot -i
# com.android.settings
@e4 [ScrollView] id=settings_homepage_container scrollable
@e8 [ImageView] desc="Profile picture, double tap to open Google Account" id=account_avatar
@e12 [ViewGroup] id=search_action_bar
@e15 [ScrollView] id=main_content_scrollable_container scrollable
@e21 [LinearLayout] (by index)
…
A snapshot prints the visible screen, one node per line, grouped by window (# package).
-i keeps only the nodes an action can target. Each line starts with a ref: @e12 names
a selector the server found to match exactly that node, and keeps naming it while the node stays
on screen. (by index) marks a node that only its position among similar nodes singles out:
it has no id, text or description of its own, an accessibility gap in the app.
An empty field showing its hint prints empty hint="Name", rather than presenting the hint
as a typed value. App validation state prints invalid and error="Cannot be blank".
Act, and see what changed¶
$ tap-agent tap @e12
tapped @e12
$ tap-agent fill id=open_search_view_edit_text dark --settle
filled id=open_search_view_edit_text
# com.google.android.settings.intelligence
+ @e266 [EditText] "dark" hint="Search settings" id=open_search_view_edit_text focused
+ @e267 [ImageButton] desc="Clear text" id=open_search_view_clear_button
+ @e272 [TextView] "Dark theme" id=android:id/title
+ @e273 [TextView] "Display" id=breadcrumb
+ @e279 [TextView] "Enable dark mode" id=android:id/title
…
# removed
- @e108 [EditText] "Search settings" id=open_search_view_edit_text focused
…
A target is a ref or key=value terms joined by commas: id=, text=, text~=
(contains), desc=, desc~=, hint=, class=, pkg=, index=. A target matches anywhere
on the screen; pkg= keeps it to one app's nodes.
--settle waits for the screen to stop changing after the action and prints the difference:
+ added and - removed nodes. Nodes with validation errors are also shown, marked = if
their ref is unchanged; validation state does not change a node's identity. That is usually
enough to pick the next step without another
snapshot. A screen that never goes quiet (a blinking cursor, a spinner) prints
(screen still changing after 10s) with the difference so far.
Check the result¶
$ tap-agent wait "text=Dark theme"
text=Dark theme is visible
wait polls on the device until the target is visible (--gone, --one), up to --timeout
(10 s by default). Use it instead of a sleep, and to confirm what an action was supposed to do.
When a step fails¶
$ tap-agent tap "text=Missing thing"
error: NOT_FOUND during tap node { match { property: PROPERTY_TEXT value: "Missing thing" mode: MATCH_EXACT } } on emulator-5554 (request 13, generation 312, 104 ms)
nothing matches now; run `snapshot` to see the screen
$ tap-agent tap "text~=dark"
error: AMBIGUOUS during tap node { match { property: PROPERTY_TEXT value: "dark" mode: MATCH_CONTAINS } } on emulator-5554 (request 14, generation 312, 113 ms)
several nodes match; use a ref from `snapshot` or a narrower selector
As in tests, every action needs exactly one match and fails before touching the device
otherwise. The error names the code and a next step for the agent. A tap whose point another
window covers (a dialog, the shade) fails as NOT_INTERACTABLE / OBSCURED. Exit codes: 0
ok, 1 the step failed, 2 usage, 3 no server running.
screenshot and capture (screenshot, hierarchy, device info, driver log) save evidence
under .tap/agent/ and print the paths.
Export and release¶
$ tap-agent export -o session.json
wrote 9 events (3 failed) to session.json
$ tap-agent release
released session 'agent' (detached emulator-5554)
Sessions to tests explains the export and turns it into a test.
What else it can do¶
Beyond reading and tapping, the agent can drive most of what a test can. Each line links to its commands in the reference.
| Area | Commands |
|---|---|
| Elements | tap (--long, --double), fill, type, clear, submit, accessibility actions, slider progress, keyboard |
| Gestures | scroll, swipe, fling, drag, pinch, always on a node, never at coordinates |
| Apps and permissions | app launch, cold-launch (with intent extras), stop, clear, install, grant, open-link, app languages; the runtime-permission dialog |
| System UI and display | key back, home, recents, …; the notification shade and quick settings; rotate; screen on, off and unlock |
| Device conditions | animations, dark mode, font scale, density, airplane mode, Wi-Fi, mobile data, languages, accessibility display settings, a mock location |
| Notifications and toasts | list, await, open (or press an action button) and dismiss notifications; await toasts; the clipboard |
| Files | push and pull files, add photos and videos to the gallery |
Whatever the agent changes on the device (rotation, conditions, location, files it pushed) is restored or removed when the session is released.