Driving pages with caveman-browse
Four tools. The loop is: snapshot → act on a uid → focused re-snapshot to prove the action settled → recover exact bytes only when compression hid something you need.
The loop
browser_snapshot(url, query?)returns a compact accessibility tree:[uid] role "name" = "value" {state}lines plus one trailing accounting line (caveman before=… after=… ratio=… basis=inferred handle=ccr_…). uids are your action handles. They are valid for the current snapshot generation only.browser_act(action, uid, text?, option?)—click,type,select,scroll,wait. Non-wait actions returnsettled:false: that is CDP dispatch acknowledgement, NOT proof the app updated.- Prove settlement: re-run
browser_snapshotwith aqueryfocused on the expected outcome (e.g. the success toast text, the new row). Never chain a second action on top of an unproven first one. browser_recover(handle, query?)returns the byte-exact original AX payload for a snapshot handle (or BM25-narrowed sections withquery). Use it when the compressed view seems to be missing something — never guess.
Token discipline
- Large or unknown pages: pass
query.browser_snapshot(url, query)keeps at most 12 best-matching nodes plus ancestors. On a 200-row dashboard that is ~98 tokens instead of ~12k. Phrase the query with the words you expect on the target control ("Save order ORD-0173", "Email Plan"). interactive: truekeeps only uid-bearing lines plus placing ancestors — cheaper than a full snapshot, but it hides page text you may need to read. Use it when you already know the page and only need controls. It is never the default.- Full snapshot (no query) is for genuinely unknown task intent only.
- After navigation, old uids are stale; a failed/uncompressed snapshot keeps
the prior page's uid map and returns
cave_browser_snapshot_uncompressed— do not act on uids after that error until a fresh snapshot succeeds.
Boundaries (fail closed, don't fight them)
- Navigation allows
http(s),about:blank, boundeddata:text/html.file:,javascript:, and privileged Chrome schemes are denied. - Unknown uids/actions return
cave_snake_codeerrors — re-snapshot instead of retrying blind. - Disabled controls are rejected; make the control enabled first (fill the form, dismiss the overlay).
- Scope is same-origin, predictable controls. Cross-origin iframes appear as leaf nodes; OOPIF content, dialogs, downloads are out of scope — say so rather than looping.
browser_eval(expression)is the JS escape hatch for reading state the AX tree cannot express. Prefer snapshot queries first.- Every reported saving is
inferred(offline BPE count). Never present these numbers as provider-verified.