Coverage, storage, fake clocks, autonomous crawling, visual diffing and network mocking. What Reticle does once look-act-observe-assert is not enough.
Most of the time you want the verify loop. Look, act, observe, assert.These are the tools for the times you want something else, and they are the ones people are most surprised exist. All of them live in the cold tail, reachable through reticle_run.
Not code coverage. Control coverage: which interactive elements this session has actually touched.Useful at the end of a drive, when the agent is about to report success. “I verified the page” reads differently next to exercised: 0.
localStorage, sessionStorage and readable cookies.This is where the “logged in but nothing persisted” bug lives. A login can fire its success signal, mutate state, and write nothing. Reload, and you are back at the login screen.
storageKeysChanged already appears in every act_and_wait summary, so you often do not need
this tool. Read it there first.
Toasts that auto-dismiss, debounced search, polling, session timeouts, retry backoff. All of these are normally verified by sleeping, which is slow and flaky in equal measure.Freeze the clock, advance it by exactly the interval, assert the consequence. No sleeping, no guessing, and the same result on a fast laptop and a loaded CI runner.
Autonomously clicks every reachable control and reports what went wrong. No script, no plan. The counts are the useful part: deadControls and contradictions are the two that indicate a real problem rather than a busy page.This is the tool for an app you did not write and do not understand yet.
It clicks everything, so point it at a dev environment. maxSteps bounds it, defaulting to
25.
Compares the data an endpoint returned against what the page actually displays.The bug it catches is specific and common: the API returned ten rows, the table shows nine, and nothing errored. Neither the network log nor the DOM is wrong on its own. Only the comparison is.
Read that summary again. Thirty-one of forty-seven flows assert no consequence, which means they replay green whatever the app does. That is a suite that looks like coverage and is not.Each flow comes back graded, with the consequence that must hold and a risk level:
{ "name": "console-compose", "grade": "assertion-free", "warning": "This flow performs actions but asserts no observable consequence — it will pass even if the feature is broken. Add a consequence assertion with reticle_annotate (assert-signal / assert-net) or a success-state."}
declaredUntestedSignals is the other half: signals your app emits that no flow ever checks. It is a to-do list for your test suite, generated from what the app says about itself.
Run this before writing a new flow. It tells you what is already covered, what is covered badly,
and which declared signal has never been asserted. All three are better starting points than
guessing.
Records the meaningful state of a page and compares later. Structure and content rather than pixels, so a font change does not fail your check and a missing row does.
Four tools apply their effects through the Chrome DevTools Protocol. The always-on SDK cannot do that, so they need a browser Reticle is driving.
A pooled lease is not enough. Verified: acquiring one with reticle_lease and calling these
still returns { "ok": false, "reason": "no-cdp-provider" } and "no-visual-provider".Point RETICLE_CDP_URL at a Chrome started with --remote-debugging-port. That is currently the reliable route.
Note the asymmetry. reticle_screenshot names the baseline with name; reticle_visual_diff
refers to it with baseline. Passing name to the diff is rejected, and it is an easy
mistake to make twice.
fullPage captures the whole scroll height. ref or clip scopes to one element or region. threshold sets the pixel-difference tolerance, defaulting to 0.01, and masks excludes regions that are expected to change.Reticle reads program truth, not pixels, so this is the deliberate exception: a font that failed to load or a compositing glitch is only visible in the actual frame.
Fixes the viewport so a visual baseline is reproducible across machines. Without it, a diff taken on a laptop and re-run in CI compares two different layouts and fails for a reason nobody wants to debug.
Return a 500, force offline, or delay a response. First matching rule wins. clear: true turns it off.Most error states have never actually run. This is how you find out whether yours works, without touching the backend or waiting for a real outage to tell you.
The argument names are not interchangeable. reticle_record takes recordingName,
reticle_flow_save takes flowName, and neither accepts name. Reticle rejects the call
rather than guessing, which is the right call and still costs you a turn.
Stopping a recording returns a large payload. A one-click recording came back at roughly 63,000 characters, and 69,000 of the 70,000 were the raw events array. There is currently no way to cap it: max_events and filters are rejected, even though the response’s own cost.recommendation suggests them.The parts you actually want are tiny. Read these and ignore the rest:
proposedConsequences is the useful part and the reason to record at all. Reticle watched the interaction and worked out what would have proved it, ranked by strength. Tier 0 is the app’s own signal. You do not have to invent the assertion; you pick one.
{ "name": "ship-a-deploy", "stepCount": 1, "assertions": { "grade": "assertion-free", "warning": "This flow performs actions but asserts no observable consequence — it will pass even if the feature is broken." }}
Reticle grades the flow as you save it, and tells you when you have just created a test that cannot fail. Take the warning seriously: an assertion-free flow replays green whatever the app does.A replay against a drifted app names what moved and where:
{ "status": "drift", "decision": { "whatChanged": "testid \"login-submit\" not found", "whereInSource": "src/components/Login.tsx:81", "suggestedFix": "rebind the anchor to \"sign-out\" (closest survivor)" }}
reticle_flow_heal proposes the rebind. It refuses when it is not confident:
{ "status": "unhealable", "applied": false, "message": "drift found, but no nearest match cleared the confidence floor (HEAL_CONFIDENCE_MIN=0.5); file left untouched — add a data-testid or fix the flow by hand"}
Flows live in .reticle/ as human-readable files, so they are reviewed in pull requests and diffed like code. They anchor on meaning, a testid plus a signal, rather than volatile refs or coordinates.
Flows in full
Recording, replay, self-healing, and what lives in .reticle/.
A versioned, machine-readable record of a verification run. This is what you hand to CI, a dashboard, or a platform embedding Reticle in its pipeline.oracle on a passing flow names the consequence that made it a pass, so a green row says what it proved rather than only that it was green.
Persists the app’s live capability registry to a git-checked file. A fresh agent can read it without booting the app, and a diff shows when someone removes a signal something depended on.
narrate writes a line into the presenter panel, so the person watching knows what you are doing. review drains the bugs they pinned on elements from that panel:
{ "marks": [], "pendingCount": 0 }
An empty list here is a real reading, not a missing one.
Returns every tool with a one-line summary, and the profile currently in force. Load the full argument grammar for the ones you want before calling them:
Do this rather than guessing at arguments. Reticle refuses a call with unknown parameters rather
than running it, and says why: “NOT applied, so any result would be an answer to a different
question.” Good behaviour, but a wasted turn you can skip.
Last modified on August 14, 2026
⌘I
Assistant
Responses are generated using AI and may contain mistakes.