npx @reticlehq/server verify <preview-url> in CI when the preview deploy succeeds. It exits 0 when every saved flow passes and 1 otherwise, so the job’s own pass/fail becomes the check on the PR.
The strongest place to enforce verification is the moment code becomes a preview URL. Every deploy already makes one. Today you run Reticle from a CI job on the deploy event (Recipe A). A hosted check provider that needs no workflow file does not exist yet (Recipe B).
That makes the non-developer story complete: the SDK is auto-injected by the build plugin, flows are minted from toolbar recordings with auto-proposed consequences, and verification runs at publish, without anyone writing a test.
Recipe A works today; Recipe B does not exist yet. reticle verify exits 0/1 and persists a run artifact right now. What is not built is a hosted Reticle app that registers itself as a Vercel or Netlify check provider. Until it exists, use the CI recipe.
Using Reticle in CI or in a pipeline? Talk to a founder: book a call or write to hey@reticle.sh.
The shape
reticle verify <preview-url> is the whole integration surface:
- exits 0 when every saved flow passes, 1 otherwise (the only contract a check needs),
- prints a legible ✓/✗ report for the PR log,
- persists a
ReticleVerificationRunartifact (.reticle/runs/<id>.json) soreticle gateandreticle_run_exportcan consume the same verdict.
Recipe A: CI (works today, any provider)
localhost), Reticle injects reticle.connect() with a one-time token and allow-lists the preview origin, so the app does not need to be rebuilt per environment. Confirm the SDK actually runs on the deployed build: a production build that tree-shakes the dev-only SDK will connect to nothing, and verify will (correctly) fail with “no app connected.”
The Reticle GitHub Action
The Action replays your saved flows on each preview and posts one check with a verdict for each flow. Ondeployment_status, it reads the preview URL from the event, so you type no URL.
Recipe B: the Checks API pattern (what a hosted Reticle would do)
Both providers expose the same shape, which is why this is one integration rather than two:
The flow is: receive the deploy webhook →
reticle verify <target_url> → post the verdict (and the repair.failurePackets[] from the run artifact) back as the check output. The artifact is stable and versioned precisely so a host platform can render it without parsing logs.
Pair it with the local gate
The deploy check catches what reaches a preview.reticle gate catches it earlier: an agent that edits a covered file cannot “finish” without re-verifying:
gate in the agent’s Stop hook (see the agent cheat sheet), verify at the deploy. They read the same run artifacts, so a green gate locally and a green check on the PR mean the same thing.
Honest limits
verifyneeds one connected session. If several tabs of the app are open against the same daemon it refuses rather than guessing which to drive.- It replays flows sequentially against one tab, so flows must not depend on each other’s leftover state (a flow that logs in contaminates the next one). Author self-contained flows, or use
reticle_verify { action: "flows", parallel }, which gives each flow an isolated context. - No saved flows means nothing to verify.
verifyfails rather than reporting a vacuous pass.
FAQ
verify says ‘no app connected’ on my preview URL. Why?
Almost always because the deployed build tree-shook the dev-only SDK out, so there is nothing in the page dialling the bridge.reticle.connect() is meant to be dev-gated, and a production build honours that gate. Either build the preview with the dev guard satisfied, or accept that verify is correctly reporting that it cannot see the app. It is not a false alarm: with no SDK there is no program to read.
Does it work on a real preview URL, or only localhost?
Both. For a non-loopback origin Reticle injectsreticle.connect() with a one-time pairing token and allow-lists the preview origin, so you do not rebuild per environment. The bridge refuses to bind a non-loopback host without a token, which is the point.
One of my flows logs in and the next one starts logged in. How do I stop that?
verify replays flows sequentially against one tab, so leftover state carries. Either author each flow to be self-contained, or use reticle_verify { action: "flows", parallel: 4 } (parallel is how many flows run at once), which gives every flow its own isolated browser context with its own cookies and storage.
Should I run reticle gate as well as reticle verify?
If you want an agent to be unable to call a change finished without re-verifying, yes. They catch the same regression at different moments:gate runs locally against the files the agent just edited, verify runs against the deployed preview. They read the same run artifacts, so a green gate locally and a green check on the PR mean the same thing.
verify exited 1 but I cannot see which flow failed.
The verdict is in the run artifact, not only in the log. Each run writes.reticle/runs/<id>.json with repair.failurePackets[] naming what broke and where; reticle_run({ tool: "reticle_run_export", args: { format: "report" } }) prints it as a ✓/✗ report. The artifact is stable and versioned precisely so a CI surface can render it without parsing log lines. Each entry in checks[] carries intent, a sentence a person can read: the agent’s own intent when it gave one, else a sentence built from the predicate in the failure voice (“No PATCH request to /assignee was made”), marked intentDerived: true. A failed allOf also carries failedPart, the index of the part that failed, so a title can name the one thing that did not happen.