Skip to content

Snapshot notation

snapshot (and the diff act answers with) writes one line per element in a fixed notation: the same string the tool description, the cheat_sheet and the agent skill carry, printed straight from the engine so it cannot drift. Markers appear only when they apply, and every string the page controls is a JSON string — a button labelled x6 cannot pass for a duplicate count.

snapshot v2 — one line per element, markers only when they apply:
<ref> <role>[<index>] "<name>" [x<count>] [$<testId>|#<id>] [="<value>"] [?"<placeholder>"] [<flags>] [row:"<anchor>"] [in:<kind>"<name>"] [icon:<name>] [via:<signal>]
x<count> — how many elements the line's key matches, [<index>] which one this is; no x means the key already names one element.
$ = testId, # = stable id — prefer them; ="…" is the field's current value, ?"…" its placeholder.
flags: on off (checked) disabled focus selected offscreen (clipped or off the viewport).
row:"…" = the text beside it in the same row (never another control); in:dialog"…"/form/section/nav/table/list = the container it sits in.
icon:… = the picture on a wordless button; via:… = what proved a nameless clickable.
Selector to write: $ → { testId: … }, # → { id: … }, else { text: "<name>" }; add { index, of } when x>1, or { rightOf: "<row anchor>" } when the line carries one.
First lines: `snapshot v2` then `page "Title" url="…" settled`; `loading(Network 2)` means wait and snapshot again.
snapshot { detail: "full" } adds ?placeholder and row:/in:/offscreen on every line; { around: "e9" } returns only e9's container; { detail: "v1" } the old lines.
A ref stays with its element across actions (twins nothing but their position tells apart keep their order instead); a gone ref says so, and a new element gets a fresh number rather than a retired one.
After act: event lines (went, dialog, toast, focus, value, error, +N rows, gone), then the same notation prefixed + - ~ (~ names the facet: role, name, value, flags), then `net: 2 requests — POST /api/orders 201, GET /api/cart 200`.
try { step: "tapOn: 'Create order'" } acts only where the step names exactly one element (`done tapOn e41 button "Create order"` + the same event and net lines); otherwise it answers `none "…"` or `ambiguous "…": N` with up to five candidate lines and touches nothing. via:exact|norm|sub|score on a candidate says how far the name had to stretch to reach it.
snapshot { detail: "regions" } is the overview: one line per container — `main: 3 buttons`, `table "Orders": 20 rows`, `nav: 4 links` — then the controls no container holds, named while there are eight or fewer. Read it once on arrival.
A dialog is modal: while one is open, a match inside it wins over the same name outside it, and the receipt says in:dialog"…".

Levels: snapshot { detail: "compact" } (the default) leaves out placeholders and prints row:/in: only where the key is ambiguous; "full" prints everything; "v1" returns the pre-v2 lines for one release. snapshot { around: "e9" } returns full lines for the container e9 sits in and nothing else — the cheap way to inspect one form on a busy page.