Docs Operation reference screen operations
screen operations#
8 operations. Generated from assets/operations.json; all areas.
On this page (8)
screen.marks#
Mark tappable elements
Take a screenshot with numbered boxes over what can be tapped, and a list that says what each number is (label, text, description, resource id, class, bounds, centre), so a vision-capable agent can answer "tap 7" and call screen.tap. On Android the marks are the enabled clickable, long-clickable, checkable and editable elements of the UI hierarchy, in document order; content an app draws itself (a canvas, a game, much of a WebView) is not in it. On the virtual iPhone, which has no UI hierarchy, they are the lines of text Tesseract reads off the screenshot, each with its confidence (source ocr, which Android can use too): an icon without a label gets no mark, and text it misreads or misses is wrong or absent. The numbers belong to this look at the device; screen.tap checks the screen still matches before it taps. The result's path is the marked PNG, which MCP returns inline. Needs tesseract only for source ocr.
Annotations: writes, idempotent, open world.
| Argument | Type | Required | Default | Details |
|---|---|---|---|---|
device | string | yes | non-empty; Android serial from device.list, or virtual-iphone for the running virtual iPhone | |
path | string | yes | non-empty; Absolute path of the marked PNG to write; an existing file is replaced | |
source | string | "auto" | one of auto, hierarchy, ocr; hierarchy reads the UI hierarchy (Android); ocr reads text off the screenshot with Tesseract (any screen, and the only way on the virtual iPhone); auto takes the hierarchy where there is one | |
max_marks | integer | 60 | 1 to 200; Most marks; the first ones in reading order are kept and truncated says so | |
xml_path | string | non-empty; Also keep the UI hierarchy as UIAutomator XML at this absolute path, for screen.diff | ||
min_confidence | number | 40 | 0 to 100; Leave out words Tesseract reads with less confidence than this (0 to 100) | |
language | string | "eng" | matching ^[A-Za-z0-9_+]+$; Tesseract language code, such as eng or eng+deu; its data must be installed | |
region | object | Read only this part of the screen, in pixels. Tesseract reads a screen with both light and dark areas as one and can miss the minority area; a region reads it alone | ||
region.x | integer | yes | at least 0 | |
region.y | integer | yes | at least 0 | |
region.width | integer | yes | at least 1 | |
region.height | integer | yes | at least 1 |
tomaccoctl call screen.marks '{"device":"<device>","path":"<path>"}'
screen.tap#
Tap a mark
Tap the centre of a numbered mark from the last screen.marks (or screen.tree) of this device. First it checks the screen still has what the mark was made from: on Android the same element (class, resource id, text and bounds) in the UI hierarchy; for a mark read by OCR, the pixels where it was, unchanged. If not it answers mark_stale and taps nothing, so a number never lands on another element after the screen moved on. Pass duration for a long press.
Annotations: writes, not idempotent, open world.
| Argument | Type | Required | Default | Details |
|---|---|---|---|---|
device | string | yes | non-empty; Android serial from device.list, or virtual-iphone for the running virtual iPhone | |
mark | integer | yes | 1 to 200; The mark's number in the last screen.marks result for this device | |
duration | integer | 100 to 5000; Hold for this many milliseconds (a long press) instead of tapping | ||
verify | boolean | true | Check the screen still matches the mark before tapping; false taps where the mark was whatever is there now |
tomaccoctl call screen.tap '{"device":"<device>","mark":1}'
screen.tree#
Read UI tree as text
Read the Android UI hierarchy as a short indented text for a model's context: only the elements that carry text or a description, can be pressed or scroll, each with its class, text, id, bounds and state (checked, disabled, focused, editable), and #N on those screen.tap can tap. The first line says the screen size and the app's package. The text stops at max_chars with a last line that says how many nodes are missing. Android only: the virtual iPhone has no UI hierarchy (ui_hierarchy_unavailable); use screen.marks with source ocr there.
Annotations: writes, idempotent, open world.
| Argument | Type | Required | Default | Details |
|---|---|---|---|---|
device | string | yes | non-empty; Android serial from device.list, or virtual-iphone for the running virtual iPhone | |
max_chars | integer | 6000 | 500 to 100000; Longest text, in characters | |
only_interactive | boolean | false | Leave out text that cannot be pressed | |
xml_path | string | non-empty; Also keep the UI hierarchy as UIAutomator XML at this absolute path, for screen.diff |
tomaccoctl call screen.tree '{"device":"<device>"}'
screen.ocr#
Read text on screen
Read the text on a device's screen or in a PNG with Tesseract, for screens that have no UI hierarchy: the virtual iPhone, games, WebViews. Answers every word and line with its box and Tesseract's confidence (0 to 100), and with text (whole words, any letter case) or text_contains (part of a word or line), the matches with their centre, ready to tap. The recognition is of pixels, not of controls: small, low-contrast or decorative text can be misread or missed, a space can be lost ("Signin"), and a picture with light and dark areas may need region. A dark theme is handled by also reading the inverted picture. Needs tesseract (capabilities.ocr says whether it is installed).
Annotations: read-only, idempotent, open world.
| Argument | Type | Required | Default | Details |
|---|---|---|---|---|
device | string | non-empty; Android serial from device.list, or virtual-iphone for the running virtual iPhone | ||
image | string | non-empty; Absolute path of a PNG to read, instead of a device | ||
text | string | non-empty; Find these words, in this order, as whole words in one line | ||
text_contains | string | non-empty; Find this text inside a line, also as part of a word | ||
index | integer | 0 to 10000; Keep only the nth match, top to bottom | ||
fuzzy | boolean | false | Let a word of five or more letters match with one letter misread | |
min_confidence | number | 40 | 0 to 100; Leave out words Tesseract reads with less confidence than this (0 to 100) | |
language | string | "eng" | matching ^[A-Za-z0-9_+]+$; Tesseract language code, such as eng or eng+deu; its data must be installed | |
region | object | Read only this part of the screen, in pixels. Tesseract reads a screen with both light and dark areas as one and can miss the minority area; a region reads it alone | ||
region.x | integer | yes | at least 0 | |
region.y | integer | yes | at least 0 | |
region.width | integer | yes | at least 1 | |
region.height | integer | yes | at least 1 | |
invert | string | "auto" | one of auto, never, always; auto reads the picture as it is and with its colours inverted, and merges the words (twice the time, finds light text on dark ground); never reads it once; always reads only the inverted picture | |
max_words | integer | 400 | 1 to 5000; Most words and lines to list |
tomaccoctl call screen.ocr
screen.diff#
Compare two screens
Describe what changed between two screens in structured form. before and after are both UIAutomator XML files (hierarchies: elements added, removed and changed in text, state or position, or a different screen, from screen.tree or screen.marks with xml_path) or both PNG screenshots (the regions where pixels changed, each with its box, size, share of changed pixels and position, and a summary; status bar regions are marked). Leave after out and give device to compare before with the screen now. With text:true the screenshots are also read with Tesseract and the lines added and removed are listed. Screens of different sizes (a rotation) answer size_changed. before and after can also both be export bundles from screen.export (the directory or its screen.json): the answer then lists the metadata that changed (device, display, theme, locale, app), the element difference and the pixel regions.
Annotations: read-only, idempotent, open world.
| Argument | Type | Required | Default | Details |
|---|---|---|---|---|
before | string | yes | non-empty; Absolute path of a .xml hierarchy, a .png screenshot, or a screen.export bundle (its directory or screen.json) | |
after | string | non-empty; Absolute path of the second one, the same kind | ||
device | string | non-empty; Android serial from device.list, or virtual-iphone for the running virtual iPhone | ||
tolerance | integer | 24 | 0 to 255; A pixel counts as changed when a colour channel differs by more than this (screenshots) | |
ignore | array of object | up to 100 items; Regions in screen pixels that are not compared, such as the status bar clock | ||
ignore[].x | integer | yes | at least 0 | |
ignore[].y | integer | yes | at least 0 | |
ignore[].width | integer | yes | at least 1 | |
ignore[].height | integer | yes | at least 1 | |
max_regions | integer | 12 | 1 to 100; Most regions, or elements per list, to describe | |
text | boolean | false | Also list the lines of text added and removed, read with Tesseract (screenshots) | |
min_confidence | number | 40 | 0 to 100; Leave out words Tesseract reads with less confidence than this (0 to 100) | |
language | string | "eng" | matching ^[A-Za-z0-9_+]+$; Tesseract language code, such as eng or eng+deu; its data must be installed |
tomaccoctl call screen.diff '{"before":"<before>"}'
screen.wait#
Wait for text or a steady screen
Wait until text is on the screen, is gone, or the screen has stopped changing, polling every interval_ms. text and text_gone look in the UI hierarchy's text and descriptions where there is one (Android, case-insensitive, part of a text) and otherwise read the screenshot with Tesseract; source forces one. stable takes screenshots until stable_ms pass with at most threshold of the pixels (outside ignore) changed from one to the next, and answers screen_unstable with the last changed fraction when a video, animation or spinner keeps going. A timeout answers text_timeout or screen_unstable with what was seen. The same waits are the wait_text and wait_stable steps of testing.run scenarios.
Annotations: read-only, idempotent, open world.
| Argument | Type | Required | Default | Details |
|---|---|---|---|---|
device | string | yes | non-empty; Android serial from device.list, or virtual-iphone for the running virtual iPhone | |
until | string | yes | one of text, text_gone, stable; text: wait for it to appear; text_gone: wait for it to go; stable: wait for the screen to stop changing | |
text | string | non-empty; The text, for text and text_gone | ||
source | string | "auto" | one of auto, hierarchy, ocr; hierarchy reads the UI hierarchy (Android); ocr reads text off the screenshot with Tesseract (any screen, and the only way on the virtual iPhone); auto takes the hierarchy where there is one | |
timeout | integer | 30 | 0 to 300; Seconds | |
interval_ms | integer | 500 | 50 to 10000; Milliseconds between looks | |
stable_ms | integer | 1000 | 100 to 60000; For stable: how long the screen must stay unchanged | |
threshold | number | 0.001 | 0 to 1; For stable: the largest changed fraction of the pixels still counted as unchanged | |
tolerance | integer | 24 | 0 to 255; For stable: a pixel counts as changed when a colour channel differs by more than this | |
ignore | array of object | up to 100 items; Regions in screen pixels that are not compared, such as the status bar clock | ||
ignore[].x | integer | yes | at least 0 | |
ignore[].y | integer | yes | at least 0 | |
ignore[].width | integer | yes | at least 1 | |
ignore[].height | integer | yes | at least 1 | |
fuzzy | boolean | false | For text read by OCR: let a word of five or more letters match with one letter misread | |
min_confidence | number | 40 | 0 to 100; Leave out words Tesseract reads with less confidence than this (0 to 100) | |
language | string | "eng" | matching ^[A-Za-z0-9_+]+$; Tesseract language code, such as eng or eng+deu; its data must be installed | |
region | object | Read only this part of the screen, in pixels. Tesseract reads a screen with both light and dark areas as one and can miss the minority area; a region reads it alone | ||
region.x | integer | yes | at least 0 | |
region.y | integer | yes | at least 0 | |
region.width | integer | yes | at least 1 | |
region.height | integer | yes | at least 1 |
tomaccoctl call screen.wait '{"device":"<device>","until":"text"}'
screen.export#
Export a screen
Write one screen of a device as a bundle other tools can read: screen.png at full resolution and screen.json, a documented, versioned format (format "tomacco.screen", version 1; docs/screen-export.md and assets/schemas/screen-export-v1.schema.json). screen.json has the capture time, the device (platform, id, model, OS version, form factor), the display (pixels, density, size in dp or pt, orientation, rotation), the insets of the status bar, navigation bar and cutout where the platform reports them, the theme (dark or light), the locale, the foreground app, and every element of the screen as a flat list with ids and parent ids: role, class, text, description, resource id, bounds in pixels and in dp or pt, enabled, clickable, focusable, checked and selected, and the mark number screen.marks gives it. On Android the elements are the UI hierarchy. The virtual iPhone and USB iPhones (platform ios) have none, so there the elements are lines of text read off the screenshot with Tesseract (source ocr, state flags null) and hierarchy says unavailable. A field the platform does not report is null, never guessed. The marks are kept for screen.tap as after screen.marks. The directory must be new or empty. The result summarises the export; read screen.json for the elements.
Annotations: writes, not idempotent, open world.
| Argument | Type | Required | Default | Details |
|---|---|---|---|---|
device | string | yes | non-empty; Android serial from device.list, virtual-iphone for the running virtual iPhone, or a USB iPhone's UDID with platform ios | |
directory | string | yes | non-empty; Absolute path of the bundle directory to create; it must not exist or must be empty | |
platform | string | "android" | one of android, ios; ios for a USB iPhone (screenshot and device info, no hierarchy); virtual-iphone needs no platform | |
source | string | "auto" | one of auto, hierarchy, ocr; hierarchy reads the UI hierarchy (Android); ocr reads text off the screenshot with Tesseract; auto takes the hierarchy where the platform has one and OCR where it has not | |
max_marks | integer | 200 | 1 to 500; Most mark numbers; the first ones in reading order are numbered, as screen.marks numbers them, and marks.truncated says if more were left out. Every element is still listed | |
marked | boolean | false | Also write marked.png, the screenshot with the numbered boxes of screen.marks | |
min_confidence | number | 40 | 0 to 100; For OCR: leave out words Tesseract reads with less confidence than this (0 to 100) | |
language | string | "eng" | matching ^[A-Za-z0-9_+]+$; For OCR: Tesseract language code, such as eng or eng+deu; its data must be installed |
tomaccoctl call screen.export '{"device":"<device>","directory":"<directory>"}'
screen.export_batch#
Export screens of several devices
Export the screen now of several devices (Android serials and virtual-iphone) in one call, each as a screen.export bundle in NN-device/ inside one directory, with index.json (format "tomacco.screen-index", version 1) listing each screen's device, model, size, orientation, theme, locale, app, element count and files. A device that cannot be read is listed with its error and the others still run; ok is false then. It takes the current screen of each device, not a matrix of languages and themes: android.store_screenshots does that for store screenshots. The directory must be new or empty.
Annotations: writes, not idempotent, open world.
| Argument | Type | Required | Default | Details |
|---|---|---|---|---|
devices | array of string | yes | 1 to 16 items; Android serials from device.list, or virtual-iphone | |
directory | string | yes | non-empty; Absolute path of the directory to create; it must not exist or must be empty | |
source | string | "auto" | one of auto, hierarchy, ocr; hierarchy reads the UI hierarchy (Android); ocr reads text off the screenshot with Tesseract; auto takes the hierarchy where the platform has one and OCR where it has not | |
max_marks | integer | 200 | 1 to 500; Most mark numbers; the first ones in reading order are numbered, as screen.marks numbers them, and marks.truncated says if more were left out. Every element is still listed | |
marked | boolean | false | Also write marked.png, the screenshot with the numbered boxes of screen.marks | |
min_confidence | number | 40 | 0 to 100; For OCR: leave out words Tesseract reads with less confidence than this (0 to 100) | |
language | string | "eng" | matching ^[A-Za-z0-9_+]+$; For OCR: Tesseract language code, such as eng or eng+deu; its data must be installed |
tomaccoctl call screen.export_batch '{"devices":["<device>"],"directory":"<directory>"}'