@reticlehq/server 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE-ENTERPRISE +1 -1
- package/README.md +3 -3
- package/SKILL.md +12 -14
- package/dist/chromium-launch-options.d.ts +4 -3
- package/dist/chromium-launch-options.js +6 -2
- package/dist/command/cli/adhoc-suite.d.ts +22 -0
- package/dist/command/cli/adhoc-suite.js +90 -19
- package/dist/command/cli/adhoc-verdict.d.ts +35 -0
- package/dist/command/cli/adhoc-verdict.js +90 -3
- package/dist/command/cli/answers/gate-hook-message.d.ts +6 -0
- package/dist/command/cli/answers/gate-hook-message.js +6 -0
- package/dist/command/cli/auth/cloud-keystore.d.ts +0 -2
- package/dist/command/cli/auth/cloud-keystore.js +0 -3
- package/dist/command/cli/auth/cloud-session.d.ts +4 -0
- package/dist/command/cli/auth/cloud-session.js +2 -0
- package/dist/command/cli/cli-doctor.js +7 -5
- package/dist/command/cli/cli-flow-commands.d.ts +3 -6
- package/dist/command/cli/cli-flow-commands.js +67 -4
- package/dist/command/cli/cli-parse.d.ts +8 -1
- package/dist/command/cli/cli-parse.js +21 -3
- package/dist/command/cli/cli-update-commands.js +8 -1
- package/dist/command/cli/cli-verify.d.ts +24 -3
- package/dist/command/cli/cli-verify.js +54 -11
- package/dist/command/cli/cloud-cli.js +5 -2
- package/dist/command/cli/cloud-kit.js +3 -5
- package/dist/command/cli/cloud-login.js +21 -3
- package/dist/command/cli/demo/demo-page.js +6 -3
- package/dist/command/cli/doctor/browser/chromium-hint.d.ts +5 -0
- package/dist/command/cli/doctor/browser/chromium-hint.js +5 -0
- package/dist/command/cli/launch/cli-launch.d.ts +8 -0
- package/dist/command/cli/launch/cli-launch.js +21 -9
- package/dist/command/cli/launch/sdk-version-match.d.ts +84 -0
- package/dist/command/cli/launch/sdk-version-match.js +206 -0
- package/dist/command/cli/lifecycle/daemon-lifecycle.js +2 -16
- package/dist/command/cli/ports/resolve/cli-port.d.ts +25 -0
- package/dist/command/cli/ports/resolve/cli-port.js +125 -15
- package/dist/command/cli/setup-mcp-cli.js +13 -13
- package/dist/command/cli/tutorial.d.ts +2 -2
- package/dist/command/cli/tutorial.js +21 -7
- package/dist/command/cli.js +62 -10
- package/dist/command/daemon/binding/daemon-status-probe.d.ts +14 -2
- package/dist/command/daemon/binding/daemon-status-probe.js +34 -6
- package/dist/command/daemon/daemon-resolve.d.ts +9 -0
- package/dist/command/daemon/daemon-resolve.js +1 -1
- package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +7 -1
- package/dist/command/daemon/lifetime/daemon-usefulness.js +30 -7
- package/dist/command/dev/stale-issue-guard.d.ts +3 -4
- package/dist/command/dev/stale-issue-guard.js +8 -8
- package/dist/command/setup/bringup/connect-lease.d.ts +17 -0
- package/dist/command/setup/bringup/connect-lease.js +38 -0
- package/dist/command/setup/bringup/dev-server-files.d.ts +68 -0
- package/dist/command/setup/bringup/dev-server-files.js +131 -0
- package/dist/command/setup/bringup/dev-server-log-cap.d.ts +35 -0
- package/dist/command/setup/bringup/dev-server-log-cap.js +121 -0
- package/dist/command/setup/bringup/ensure-daemon.d.ts +65 -4
- package/dist/command/setup/bringup/ensure-daemon.js +135 -16
- package/dist/command/setup/bringup/static-page-server.d.ts +35 -0
- package/dist/command/setup/bringup/static-page-server.js +151 -0
- package/dist/command/setup/desktop-shape.d.ts +4 -0
- package/dist/command/setup/desktop-shape.js +18 -2
- package/dist/command/setup/init/init-port.d.ts +15 -0
- package/dist/command/setup/init/init-port.js +44 -0
- package/dist/command/setup/init/init-runtime.d.ts +1 -1
- package/dist/command/setup/init/init-runtime.js +39 -2
- package/dist/command/setup/node-effects.d.ts +27 -14
- package/dist/command/setup/node-effects.js +80 -44
- package/dist/command/setup/probe/loopback-probe-urls.d.ts +7 -0
- package/dist/command/setup/probe/loopback-probe-urls.js +40 -0
- package/dist/command/setup/probe/page-probe.d.ts +13 -2
- package/dist/command/setup/probe/page-probe.js +18 -3
- package/dist/command/setup/run-setup.d.ts +26 -1
- package/dist/command/setup/run-setup.js +96 -13
- package/dist/command/setup/session-pick.d.ts +13 -0
- package/dist/command/setup/session-pick.js +20 -0
- package/dist/command/setup/setup-command.d.ts +2 -14
- package/dist/command/setup/setup-command.js +105 -31
- package/dist/command/setup/setup-mcp.js +3 -3
- package/dist/command/setup/terminal/wait-progress.d.ts +8 -0
- package/dist/command/setup/terminal/wait-progress.js +17 -0
- package/dist/features/crawl/crawl-empty.js +1 -1
- package/dist/features/crawl/crawl-tools.d.ts +6 -0
- package/dist/features/crawl/crawl-tools.js +57 -0
- package/dist/features/crawl/crawl.js +171 -157
- package/dist/features/exhaust/app-coverage.d.ts +33 -0
- package/dist/features/exhaust/app-coverage.js +31 -0
- package/dist/features/exhaust/code-coverage.d.ts +47 -0
- package/dist/features/exhaust/code-coverage.js +77 -0
- package/dist/features/exhaust/exhaust-run.d.ts +33 -0
- package/dist/features/exhaust/exhaust-run.js +82 -0
- package/dist/features/exhaust/explorer.d.ts +103 -0
- package/dist/features/exhaust/explorer.js +195 -0
- package/dist/features/exhaust/failure-branches.d.ts +33 -0
- package/dist/features/exhaust/failure-branches.js +92 -0
- package/dist/features/exhaust/ledger.d.ts +202 -0
- package/dist/features/exhaust/ledger.js +252 -0
- package/dist/features/exhaust/session-fold.d.ts +31 -0
- package/dist/features/exhaust/session-fold.js +79 -0
- package/dist/features/exhaust/session-port.d.ts +36 -0
- package/dist/features/exhaust/session-port.js +102 -0
- package/dist/features/harness/drive-report.d.ts +0 -9
- package/dist/features/harness/drive-report.js +18 -0
- package/dist/features/harness/driver.js +4 -7
- package/dist/features/harness/fill-values.d.ts +6 -0
- package/dist/features/harness/fill-values.js +3 -0
- package/dist/features/harness/jev-driver.js +30 -13
- package/dist/features/harness/openai-driver.js +4 -7
- package/dist/features/harness/platform-config.js +5 -6
- package/dist/index.d.ts +9 -0
- package/dist/index.js +40 -11
- package/dist/judgement/domain/domain-model.js +3 -1
- package/dist/judgement/oracles/self-instrument.js +4 -2
- package/dist/judgement/runs/artifact/replay-mapping.d.ts +2 -2
- package/dist/judgement/runs/artifact/replay-mapping.js +44 -9
- package/dist/judgement/runs/verification-sync.d.ts +3 -1
- package/dist/judgement/runs/verification-sync.js +1 -1
- package/dist/language/flows/change/affected.d.ts +9 -0
- package/dist/language/flows/change/affected.js +35 -0
- package/dist/language/flows/change/gate.d.ts +20 -0
- package/dist/language/flows/change/gate.js +12 -1
- package/dist/language/flows/flow-author.d.ts +7 -0
- package/dist/language/flows/flow-author.js +19 -0
- package/dist/language/flows/flow-expect-grammar.js +1 -1
- package/dist/language/flows/flow-journey.d.ts +54 -0
- package/dist/language/flows/flow-journey.js +119 -0
- package/dist/language/flows/flow-replay-run.d.ts +2 -3
- package/dist/language/flows/flow-replay-run.js +13 -47
- package/dist/language/flows/flow-replay.d.ts +22 -8
- package/dist/language/flows/flow-replay.js +55 -9
- package/dist/language/flows/flow-result.d.ts +2 -0
- package/dist/language/flows/flow-result.js +25 -0
- package/dist/language/flows/flow-tools.js +17 -5
- package/dist/language/flows/flows.d.ts +10 -1
- package/dist/language/flows/flows.js +90 -14
- package/dist/language/flows/recording/replay-halt.js +3 -1
- package/dist/language/flows/recording/tape/recordings.d.ts +30 -1
- package/dist/language/flows/recording/tape/recordings.js +55 -1
- package/dist/language/flows/replay.d.ts +19 -0
- package/dist/language/flows/replay.js +42 -6
- package/dist/language/flows/verify-change-tools.js +5 -2
- package/dist/launch-chromium.d.ts +80 -0
- package/dist/launch-chromium.js +218 -0
- package/dist/memory/cloud/cloud-config.d.ts +11 -2
- package/dist/memory/cloud/cloud-config.js +47 -7
- package/dist/memory/cloud/cloud-sync.d.ts +4 -1
- package/dist/memory/cloud/cloud-sync.js +6 -9
- package/dist/memory/cloud/harness-offer.js +5 -6
- package/dist/memory/cloud/harness-switch.js +5 -6
- package/dist/memory/cloud/sync-cycle.d.ts +68 -3
- package/dist/memory/cloud/sync-cycle.js +298 -55
- package/dist/memory/cloud/sync-daemon.js +24 -20
- package/dist/memory/cloud/sync-disk.js +16 -2
- package/dist/memory/intent/intent-shard.d.ts +10 -32
- package/dist/memory/intent/intent-shard.js +0 -10
- package/dist/memory/journal/drive-flow.d.ts +18 -13
- package/dist/memory/journal/drive-flow.js +45 -37
- package/dist/memory/journal/on-disk/workspace-tiers.js +2 -0
- package/dist/memory/journal/session-end.d.ts +9 -1
- package/dist/memory/journal/session-end.js +24 -12
- package/dist/memory/project/dir/reticle-dir.d.ts +2 -0
- package/dist/memory/project/dir/reticle-dir.js +1 -0
- package/dist/memory/project/project-tools.js +3 -1
- package/dist/portal/bridge/auth-failure-reason.d.ts +1 -1
- package/dist/portal/bridge/auth-failure-reason.js +4 -2
- package/dist/portal/bridge/bridge.d.ts +8 -0
- package/dist/portal/bridge/bridge.js +43 -2
- package/dist/portal/input/js-coverage.d.ts +25 -0
- package/dist/portal/input/js-coverage.js +30 -0
- package/dist/portal/input/real-input.d.ts +11 -0
- package/dist/portal/input/real-input.js +29 -4
- package/dist/portal/pool/playwright-launcher.d.ts +6 -0
- package/dist/portal/pool/playwright-launcher.js +20 -13
- package/dist/portal/session/dev-server/dev-command.d.ts +2 -2
- package/dist/portal/session/dev-server/dev-command.js +30 -12
- package/dist/portal/session/dev-server/dev-server-probe.js +17 -1
- package/dist/portal/session/dev-server/route-status-probe.d.ts +24 -0
- package/dist/portal/session/dev-server/route-status-probe.js +57 -0
- package/dist/portal/session/facts/observed-state.d.ts +11 -0
- package/dist/portal/session/facts/observed-state.js +34 -0
- package/dist/portal/session/no-session-diagnosis.d.ts +29 -0
- package/dist/portal/session/no-session-diagnosis.js +62 -5
- package/dist/portal/session/no-session-next-action.d.ts +13 -0
- package/dist/portal/session/no-session-next-action.js +48 -9
- package/dist/portal/session/no-session-watch.d.ts +18 -0
- package/dist/portal/session/no-session-watch.js +88 -2
- package/dist/portal/session/session-health.js +3 -2
- package/dist/portal/session/session-manager.d.ts +20 -6
- package/dist/portal/session/session-manager.js +19 -3
- package/dist/portal/session/session-reaper.d.ts +28 -0
- package/dist/portal/session/session-reaper.js +49 -1
- package/dist/portal/session/session.d.ts +5 -0
- package/dist/portal/session/session.js +15 -19
- package/dist/surface/http-server.d.ts +2 -1
- package/dist/surface/http-server.js +4 -2
- package/dist/surface/mcp/mcp-proxy.d.ts +2 -2
- package/dist/surface/mcp/mcp-proxy.js +2 -2
- package/dist/surface/mcp/mcp.js +4 -2
- package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +13 -1
- package/dist/surface/mcp/proxy/proxy-daemon-probe.js +27 -2
- package/dist/surface/mcp/server-instructions.js +9 -7
- package/dist/surface/tools/act/after-match.d.ts +17 -0
- package/dist/surface/tools/act/after-match.js +30 -0
- package/dist/surface/tools/act/durable.d.ts +69 -0
- package/dist/surface/tools/act/durable.js +139 -0
- package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +13 -6
- package/dist/surface/tools/act/navigation/navigate-arrival.js +47 -10
- package/dist/surface/tools/act/navigation/navigate-result.d.ts +1 -12
- package/dist/surface/tools/act/navigation/navigate-result.js +21 -3
- package/dist/surface/tools/act/proved-controls.d.ts +9 -0
- package/dist/surface/tools/act/proved-controls.js +11 -0
- package/dist/surface/tools/act/sequence-grade.d.ts +5 -0
- package/dist/surface/tools/act/sequence-grade.js +32 -1
- package/dist/surface/tools/act-capsule.d.ts +7 -0
- package/dist/surface/tools/act-capsule.js +46 -1
- package/dist/surface/tools/act-sequence-tool.js +25 -8
- package/dist/surface/tools/act-tools.js +26 -50
- package/dist/surface/tools/assert/assert-grade.js +12 -1
- package/dist/surface/tools/assert/assert-verdict.js +2 -2
- package/dist/surface/tools/browser-tools.js +14 -2
- package/dist/surface/tools/coverage-tools.js +27 -1
- package/dist/surface/tools/error-recovery.js +4 -4
- package/dist/surface/tools/feedback-invite.js +6 -4
- package/dist/surface/tools/harness-explore.d.ts +3 -2
- package/dist/surface/tools/harness-explore.js +7 -6
- package/dist/surface/tools/lease-tools.js +15 -6
- package/dist/surface/tools/live-call-text.js +4 -1
- package/dist/surface/tools/observe-tools.js +9 -1
- package/dist/surface/tools/tools.js +4 -0
- package/dist/telemetry/argument-shape.d.ts +0 -2
- package/dist/telemetry/argument-shape.js +0 -4
- package/dist/telemetry/error-class.d.ts +2 -3
- package/dist/telemetry/error-class.js +2 -3
- package/dist/telemetry/harness-drive.d.ts +0 -2
- package/dist/telemetry/harness-drive.js +0 -4
- package/dist/wire-journal.d.ts +3 -0
- package/dist/wire-journal.js +4 -0
- package/dist/workspace-packages.d.ts +0 -2
- package/dist/workspace-packages.js +1 -9
- package/docs/README.md +4 -2
- package/docs/actions.mdx +3 -3
- package/docs/agent-cheatsheet.md +4 -4
- package/docs/architecture.md +6 -6
- package/docs/best-practices.mdx +1 -1
- package/docs/capabilities.mdx +32 -1
- package/docs/cli/cloud.mdx +14 -4
- package/docs/cli/doctor.mdx +4 -0
- package/docs/cli/feedback.mdx +2 -2
- package/docs/cli/gate.mdx +9 -4
- package/docs/cli/update.mdx +10 -0
- package/docs/cli.mdx +9 -0
- package/docs/desktop.mdx +14 -10
- package/docs/environment.mdx +87 -0
- package/docs/faq.mdx +18 -16
- package/docs/first-drive.md +5 -13
- package/docs/flows.md +21 -2
- package/docs/frameworks.mdx +29 -10
- package/docs/getting-started.md +3 -3
- package/docs/http-transport.md +6 -3
- package/docs/human-control.md +2 -2
- package/docs/index.mdx +16 -6
- package/docs/install-agentic.mdx +1 -1
- package/docs/install-manual.mdx +1 -1
- package/docs/integration-patterns.md +3 -3
- package/docs/multi-agent-testing.md +1 -1
- package/docs/packages/babel-plugin.mdx +1 -1
- package/docs/packages/browser.mdx +2 -2
- package/docs/packages/react.mdx +2 -2
- package/docs/packages/tauri.mdx +1 -1
- package/docs/packages/vite-plugin.mdx +2 -2
- package/docs/packages.mdx +9 -9
- package/docs/predicates.mdx +50 -5
- package/docs/quickstart.mdx +2 -2
- package/docs/recipes.mdx +2 -2
- package/docs/state-management.mdx +2 -2
- package/docs/system-map.md +1 -1
- package/docs/telemetry.md +1 -1
- package/docs/token-efficiency.md +3 -3
- package/docs/tools/act-and-wait.mdx +1 -0
- package/docs/tools/act-sequence.mdx +1 -1
- package/docs/tools/console.mdx +1 -1
- package/docs/tools/inspect.mdx +1 -1
- package/docs/tools/network.mdx +1 -1
- package/docs/tools/query.mdx +1 -1
- package/docs/tools/sessions.mdx +1 -1
- package/docs/tools/snapshot.mdx +1 -1
- package/docs/tools/state.mdx +1 -1
- package/docs/tools/wait-for.mdx +1 -1
- package/docs/usage.md +7 -6
- package/docs/use-cases.mdx +157 -0
- package/docs/vs-screenshots.mdx +3 -3
- package/docs/what-is-recorded.md +2 -2
- package/docs/what-is-reticle.mdx +17 -20
- package/docs/why-reticle.mdx +14 -21
- package/package.json +10 -9
- package/dist/judgement/capsule/minimize.d.ts +0 -12
- package/dist/judgement/capsule/minimize.js +0 -22
- package/dist/judgement/phenomena/phenomena.d.ts +0 -27
- package/dist/judgement/phenomena/phenomena.js +0 -101
- package/dist/language/flows/flow-report.d.ts +0 -22
- package/dist/language/flows/flow-report.js +0 -106
package/docs/telemetry.md
CHANGED
|
@@ -122,7 +122,7 @@ Reticle verifies apps for AI agents, and for a long time it had no way to hear w
|
|
|
122
122
|
|
|
123
123
|
| Who | How | What it carries |
|
|
124
124
|
| --- | --- | --- |
|
|
125
|
-
| Your agent | Calls the `
|
|
125
|
+
| Your agent | Calls the `reticle_session { action: "feedback" }` MCP tool (after a failure, **or to ask for a feature**) | What it wrote: an analysis, or a request with the goal behind it, what would improve, and how it works around the gap today. Plus the model it is running, which it tells us because MCP cannot |
|
|
126
126
|
| You | Run `npx @reticlehq/server feedback [--rating 1-5] [--bug] "your words"` | Your words and your rating |
|
|
127
127
|
| Your agent, before Reticle works | Runs `reticle feedback --agent --kind <bug\|gap\|ambiguity\|feature_request\|improvement> "what happened"` | The same words, filed from the shell. This exists for the phase where there is no daemon and no MCP tools (a failed `init`, half-finished wiring), which is the failure we are otherwise never told about |
|
|
128
128
|
|
package/docs/token-efficiency.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Why asking narrow questions costs a fraction of feeding the whole a
|
|
|
4
4
|
icon: coins
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
A full Reticle verify loop costs about **100 tokens**, against roughly **7,300** for a full-tree accessibility snapshot on the same page: about 73x leaner, because Reticle asks a narrow question instead of returning the page. If you re-look after an action with `
|
|
7
|
+
A full Reticle verify loop costs about **100 tokens**, against roughly **7,300** for a full-tree accessibility snapshot on the same page: about 73x leaner, because Reticle asks a narrow question instead of returning the page. If you re-look after an action with `reticle_look({ action: "page", diff: true })`, the re-read costs about 99% less again.
|
|
8
8
|
|
|
9
9
|
Agent browser tools that feed the **whole accessibility tree** to the model every step get expensive fast. Playwright MCP's own ecosystem notes its snapshots _"can exceed 50,000 tokens on complex pages,"_ with a _typical task ~114,000 tokens through MCP._ Reticle is built to ask **narrow questions** instead, so the per-interaction cost stays tiny.
|
|
10
10
|
|
|
@@ -28,7 +28,7 @@ Measured against the bench dashboard (`apps/bench-app`) **with a 1,000-item list
|
|
|
28
28
|
|
|
29
29
|
## Diffed snapshots: pay once, then only for changes
|
|
30
30
|
|
|
31
|
-
After the first snapshot, pass `
|
|
31
|
+
After the first snapshot, pass `reticle_look({ action: "page", diff: true })` to get back **only what changed** since your last look of the same scope/mode (`mode:delta` with added/removed lines, or `mode:unchanged`). A route change auto-resets to a full snapshot, so you never read a misleading cross-page diff.
|
|
32
32
|
|
|
33
33
|
Measured on a representative 150-row dashboard (the shipped regression benchmark `server/src/surface/tools/snapshot-cost.test.ts`, char/4 proxy):
|
|
34
34
|
|
|
@@ -40,7 +40,7 @@ Measured on a representative 150-row dashboard (the shipped regression benchmark
|
|
|
40
40
|
|
|
41
41
|
**~99% fewer tokens** to re-look after an action, and because a `delta` carries no stale full tree, it also removes the 60K to 80K-token stale-context buildup that makes long-running agents start hallucinating selectors that no longer exist.
|
|
42
42
|
|
|
43
|
-
Every `
|
|
43
|
+
Every `reticle_look { action: "page" }`/`reticle_look { action: "find" }` result also carries `cost:{ bytes, tokens }` (estimated) so you can **re-scope before reading** a large body (`mode:interactive`/`status`, a tighter `scope`, or a narrower `query`) instead of paying for it first.
|
|
44
44
|
|
|
45
45
|
## The other tax: tool schemas, paid on every request
|
|
46
46
|
|
|
@@ -162,6 +162,7 @@ A verification tool that cannot describe the quality of its own evidence is aski
|
|
|
162
162
|
| `predicate` | Alias for `until`, the name `assert` and `wait_for` use |
|
|
163
163
|
| `timeout_ms` | Maximum wait, defaulting to 4000. `0` evaluates the predicate once, no wait |
|
|
164
164
|
| `refuseWhenThrottled` | Throw rather than act on a throttled tab |
|
|
165
|
+
| `durable` | After a `yes`, reload the page and require the element, text and state parts of `until` to hold again. A consequence that is gone after the reload turns the verdict into `no`: the UI advanced, the change did not persist |
|
|
165
166
|
|
|
166
167
|
Omitting `until` waits for network and DOM idle, which is the deterministic replacement for a fixed sleep. To assert a consequence **and** settle, combine them:
|
|
167
168
|
|
|
@@ -5,7 +5,7 @@ icon: layer-group
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<Warning>
|
|
8
|
-
**reticle_act_sequence is not advertised.** The default surface is the merged
|
|
8
|
+
**reticle_act_sequence is not advertised.** The default surface is the merged ten, so an agent does not see
|
|
9
9
|
this name. Call **`reticle_act { steps: [...] }`** instead: the same call, routed on the steps array. Everything below describes what that call does;
|
|
10
10
|
only the spelling changed. A call to the old name is answered with the new one, but an
|
|
11
11
|
`allowedTools` allowlist or an MCP permission rule naming it refuses before Reticle is asked.
|
package/docs/tools/console.mdx
CHANGED
|
@@ -5,7 +5,7 @@ icon: terminal
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<Warning>
|
|
8
|
-
**reticle_console is not advertised.** The default surface is the merged
|
|
8
|
+
**reticle_console is not advertised.** The default surface is the merged ten, so an agent does not see
|
|
9
9
|
this name. Call **`reticle_observe { action: "console" }`** instead. Everything below describes what that call does;
|
|
10
10
|
only the spelling changed. A call to the old name is answered with the new one, but an
|
|
11
11
|
`allowedTools` allowlist or an MCP permission rule naming it refuses before Reticle is asked.
|
package/docs/tools/inspect.mdx
CHANGED
|
@@ -5,7 +5,7 @@ icon: crosshairs
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<Warning>
|
|
8
|
-
**reticle_inspect is not advertised.** The default surface is the merged
|
|
8
|
+
**reticle_inspect is not advertised.** The default surface is the merged ten, so an agent does not see
|
|
9
9
|
this name. Call **`reticle_look { action: "element" }`** instead. Everything below describes what that call does;
|
|
10
10
|
only the spelling changed. A call to the old name is answered with the new one, but an
|
|
11
11
|
`allowedTools` allowlist or an MCP permission rule naming it refuses before Reticle is asked.
|
package/docs/tools/network.mdx
CHANGED
|
@@ -5,7 +5,7 @@ icon: satellite-dish
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<Warning>
|
|
8
|
-
**reticle_network is not advertised.** The default surface is the merged
|
|
8
|
+
**reticle_network is not advertised.** The default surface is the merged ten, so an agent does not see
|
|
9
9
|
this name. Call **`reticle_observe { action: "network" }`** instead. Everything below describes what that call does;
|
|
10
10
|
only the spelling changed. A call to the old name is answered with the new one, but an
|
|
11
11
|
`allowedTools` allowlist or an MCP permission rule naming it refuses before Reticle is asked.
|
package/docs/tools/query.mdx
CHANGED
|
@@ -5,7 +5,7 @@ icon: magnifying-glass
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<Warning>
|
|
8
|
-
**reticle_query is not advertised.** The default surface is the merged
|
|
8
|
+
**reticle_query is not advertised.** The default surface is the merged ten, so an agent does not see
|
|
9
9
|
this name. Call **`reticle_look { action: "find" }`** instead. Everything below describes what that call does;
|
|
10
10
|
only the spelling changed. A call to the old name is answered with the new one, but an
|
|
11
11
|
`allowedTools` allowlist or an MCP permission rule naming it refuses before Reticle is asked.
|
package/docs/tools/sessions.mdx
CHANGED
|
@@ -5,7 +5,7 @@ icon: list-check
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<Warning>
|
|
8
|
-
**reticle_sessions is not advertised.** The default surface is the merged
|
|
8
|
+
**reticle_sessions is not advertised.** The default surface is the merged ten, so an agent does not see
|
|
9
9
|
this name. Call **`reticle_session { action: "list" }`** instead. Everything below describes what that call does;
|
|
10
10
|
only the spelling changed. A call to the old name is answered with the new one, but an
|
|
11
11
|
`allowedTools` allowlist or an MCP permission rule naming it refuses before Reticle is asked.
|
package/docs/tools/snapshot.mdx
CHANGED
|
@@ -5,7 +5,7 @@ icon: camera
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<Warning>
|
|
8
|
-
**reticle_snapshot is not advertised.** The default surface is the merged
|
|
8
|
+
**reticle_snapshot is not advertised.** The default surface is the merged ten, so an agent does not see
|
|
9
9
|
this name. Call **`reticle_look { action: "page" }`** instead. Everything below describes what that call does;
|
|
10
10
|
only the spelling changed. A call to the old name is answered with the new one, but an
|
|
11
11
|
`allowedTools` allowlist or an MCP permission rule naming it refuses before Reticle is asked.
|
package/docs/tools/state.mdx
CHANGED
|
@@ -5,7 +5,7 @@ icon: database
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<Warning>
|
|
8
|
-
**reticle_state is not advertised.** The default surface is the merged
|
|
8
|
+
**reticle_state is not advertised.** The default surface is the merged ten, so an agent does not see
|
|
9
9
|
this name. Call **`reticle_look { action: "state" }`** instead. Everything below describes what that call does;
|
|
10
10
|
only the spelling changed. A call to the old name is answered with the new one, but an
|
|
11
11
|
`allowedTools` allowlist or an MCP permission rule naming it refuses before Reticle is asked.
|
package/docs/tools/wait-for.mdx
CHANGED
|
@@ -5,7 +5,7 @@ icon: hourglass
|
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
<Warning>
|
|
8
|
-
**reticle_wait_for is not advertised.** The default surface is the merged
|
|
8
|
+
**reticle_wait_for is not advertised.** The default surface is the merged ten, so an agent does not see
|
|
9
9
|
this name. Call **`reticle_assert { action: "wait" }`** instead. Everything below describes what that call does;
|
|
10
10
|
only the spelling changed. A call to the old name is answered with the new one, but an
|
|
11
11
|
`allowedTools` allowlist or an MCP permission rule naming it refuses before Reticle is asked.
|
package/docs/usage.md
CHANGED
|
@@ -4,7 +4,7 @@ description: 'The full reference and cookbook: every tool, flag, and workflow, w
|
|
|
4
4
|
icon: book
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Every Reticle drive is the same four steps: **look** (`reticle_look { action: "page" }` / `reticle_look { action: "find" }`), **act** (`reticle_act` / `reticle_act { steps: [...] }`), **observe** (`reticle_observe` / `reticle_observe { action: "network" }` / `reticle_look { action: "state" }`), **assert** (`reticle_assert`).
|
|
7
|
+
Every Reticle drive is the same four steps: **look** (`reticle_look { action: "page" }` / `reticle_look { action: "find" }`), **act** (`reticle_act` / `reticle_act { steps: [...] }`), **observe** (`reticle_observe` / `reticle_observe { action: "network" }` / `reticle_look { action: "state" }`), **assert** (`reticle_assert`). Verdicts come from `reticle_act_and_wait`, `reticle_assert`, and `reticle_act { steps }` when a step declares `expect`, so a run that ends anywhere else proved nothing. This page is the full reference for every tool, predicate, action and flag in that loop.
|
|
8
8
|
|
|
9
9
|
If you haven't set up Reticle yet, start with [Getting Started](getting-started.md).
|
|
10
10
|
|
|
@@ -183,7 +183,7 @@ The timeline + summary of what happened.
|
|
|
183
183
|
|
|
184
184
|
Act, then wait for a predicate: the whole act→observe→assert loop in one hop.
|
|
185
185
|
|
|
186
|
-
- **args:** `ref`, `action`, `args?`, `until: <predicate>`, `timeout_ms?` (default 4000; 0 = evaluate once), `refuseWhenThrottled?`, `intent?`, `sessionId?`.
|
|
186
|
+
- **args:** `ref`, `action`, `args?`, `until: <predicate>`, `timeout_ms?` (default 4000; 0 = evaluate once), `refuseWhenThrottled?`, `intent?`, `durable?` (after a yes, reload and require `until`'s element/text/state parts to hold again), `sessionId?`.
|
|
187
187
|
- **returns:** `{ effect, verdict, trace, session, warning? }`. `effect` is the action result (`{ ok, ref, action }`), `verdict` is `{ pass, evidence?, failureReason? }`, `trace` is the reaction report of everything the app did after the action, and `session` is the tab-health block `{ lastSeenMs, throttled, focused }` (with a `warning` when throttled). A failing `verdict` still returns `effect` + `trace` so you can see what _did_ happen. The predicate is automatically floored at this act's cursor, so it only matches events the action actually caused.
|
|
188
188
|
|
|
189
189
|
### `reticle_assert { action: "wait" }`
|
|
@@ -350,7 +350,7 @@ A **predicate** declares what should be true. `reticle_assert` / `reticle_assert
|
|
|
350
350
|
// An element exists / is in a state
|
|
351
351
|
{ "kind": "element", "query": { "role": "dialog", "name": "Confirm" }, "state": "visible" }
|
|
352
352
|
// query supports: role, name, text, label, placeholder, testid, alt, scope
|
|
353
|
-
// state: visible | hidden | enabled | disabled | checked | expanded | focused | present | inViewport
|
|
353
|
+
// state: visible | hidden | enabled | disabled | checked | expanded | pressed | focused | present | inViewport
|
|
354
354
|
// inViewport asserts the element is in the viewport NOW (not just in the DOM), so a scrollIntoView is gradeable
|
|
355
355
|
// add "absent": true to assert it is NOT there (regression / removal)
|
|
356
356
|
|
|
@@ -396,7 +396,7 @@ A `state` assertion is graded as a **consequence** (a wrong element or stale ren
|
|
|
396
396
|
- `timeout_ms` (on `assert`/`wait_for`): wait up to N ms for it to become true.
|
|
397
397
|
- `since` (on `net`/`console` leaves): only consider events after this cursor (from `act`).
|
|
398
398
|
|
|
399
|
-
`dataMatches`
|
|
399
|
+
`dataMatches` matches field by field; a key can be a dotted path (`"order.total"`, `"items.0.id"`), and `*` means "present, any value".
|
|
400
400
|
|
|
401
401
|
---
|
|
402
402
|
|
|
@@ -640,7 +640,7 @@ Capture everything that happens across a span. Useful for "run my whole checkout
|
|
|
640
640
|
|
|
641
641
|
```jsonc
|
|
642
642
|
reticle_record {action:"start"}({ recordingName: "checkout" })
|
|
643
|
-
// …agent performs the flow (reticle_act
|
|
643
|
+
// …agent performs the flow (reticle_act, single or with steps)…
|
|
644
644
|
reticle_record {action:"stop"}({ recordingName: "checkout" })
|
|
645
645
|
// → {
|
|
646
646
|
// recordingName,
|
|
@@ -732,7 +732,7 @@ No, for basic look/act/observe. You'll get better results by adding `data-testid
|
|
|
732
732
|
|
|
733
733
|
### Does it work without React?
|
|
734
734
|
|
|
735
|
-
The core (DOM/network/route/console/animation/snapshot/actions) is framework-agnostic and is gated against a vanilla-TS app.
|
|
735
|
+
The core (DOM/network/route/console/animation/snapshot/actions) is framework-agnostic and is gated against a vanilla-TS app. What is proven for each framework, from driven to a verdict in CI to install-gated to wired but unverified, is listed once in [Frameworks](frameworks.mdx). See also [what Svelte support is and is not](getting-started.md#what-svelte-support-is-and-what-it-is-not).
|
|
736
736
|
|
|
737
737
|
### Can it judge whether my UI looks good?
|
|
738
738
|
|
|
@@ -858,6 +858,7 @@ It does **not** freeze `requestAnimationFrame`/microtasks (React's scheduler kee
|
|
|
858
858
|
"dataMatches": { "count": { "$gte": 1 }, "sections": { "$contains": "hook" } },
|
|
859
859
|
}
|
|
860
860
|
// operators: $gte $lte $gt $lt $contains (array/substring) $length ; "*" = present
|
|
861
|
+
// keys: a field name, or a dotted path into nested data ("order.total", "items.0.id")
|
|
861
862
|
```
|
|
862
863
|
|
|
863
864
|
On a failed signal assert, the result includes a **near-miss**: the signals that _did_ fire with that name + their data. And `reticle_observe`'s summary now includes `domChanged` (in-place text/attribute re-renders, not just added/removed nodes).
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: 'Use cases: what people verify with Reticle'
|
|
3
|
+
sidebarTitle: Use cases
|
|
4
|
+
description: 'Verifying agent-built changes, security behaviour, accessibility and UX, performance, SEO basics, and driving the app as different users. What Reticle checks in each, with a call you can run.'
|
|
5
|
+
icon: list-check
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Reticle runs inside your app while it is running, so anything the app does (a request, a state change, a console line, a focus move, a route change, a performance entry) is something an agent can check and get a verdict on. People use it for more than "did my change work". This page covers the main uses. Each section lists what Reticle checks and gives one call you can run.
|
|
9
|
+
|
|
10
|
+
Every predicate below is a `json` value you pass as `until` to `reticle_act_and_wait` (the consequence of an action) or as `predicate` to `reticle_assert` (a check with no action). The URLs, names and store paths are placeholders for your own. The full grammar is in [Predicates](/predicates).
|
|
11
|
+
|
|
12
|
+
## Verifying agent-built changes
|
|
13
|
+
|
|
14
|
+
This is what Reticle was built for: an agent says a change works, and Reticle checks it against the running app.
|
|
15
|
+
|
|
16
|
+
- The request fired, returned the status you expected, and fired **once** (a double-submit is a `count` of 2).
|
|
17
|
+
- Application state moved the way the UI says it did. A total on screen that disagrees with the store is a failure.
|
|
18
|
+
- No console error appeared during the action.
|
|
19
|
+
- A failure names the `file:line` to open (on React, and on any framework whose build plugin stamps source; see [Frameworks](/frameworks)).
|
|
20
|
+
|
|
21
|
+
Click "Place order", then check all three at once:
|
|
22
|
+
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"kind": "allOf",
|
|
26
|
+
"predicates": [
|
|
27
|
+
{ "kind": "net", "method": "POST", "urlContains": "/api/orders", "status": 201, "count": 1 },
|
|
28
|
+
{ "kind": "state", "store": "cart", "path": "count", "equals": 0 },
|
|
29
|
+
{ "kind": "console", "level": "error", "absent": true }
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Once a journey has been driven, it is saved as a flow and replays with no model in the loop. `npx @reticlehq/server gate --since HEAD~1` fails unless a passing run covers every saved flow your edit touched.
|
|
35
|
+
|
|
36
|
+
## Security checks
|
|
37
|
+
|
|
38
|
+
This proves how your app behaves around security. It does not search for vulnerabilities, so it complements a vulnerability scanner rather than replacing one.
|
|
39
|
+
|
|
40
|
+
- **Access control.** Signed in as a role that should be refused, the protected call returns `403` and the app shows the denial, not a success toast.
|
|
41
|
+
- **Forbidden calls.** An endpoint that must not fire (an analytics beacon before consent, an admin API from a viewer's page) fires zero times: `{ "kind": "net", "urlContains": "/collect", "count": 0 }`.
|
|
42
|
+
- **Secrets not rendered.** A value that must never reach the page is absent from its text. Separately, the SDK redacts credential-shaped values (tokens, API keys, passwords, card numbers) from captured request and response bodies, storage and state before they reach the agent, and shows them as `[REDACTED]`.
|
|
43
|
+
- **CSP violations.** A Content Security Policy violation shows up as a console error (as a warning for report-only policies), so a CSP check needs nothing extra.
|
|
44
|
+
|
|
45
|
+
As a viewer, click "Delete user" and require the refusal:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"kind": "allOf",
|
|
50
|
+
"predicates": [
|
|
51
|
+
{ "kind": "net", "method": "DELETE", "urlContains": "/api/admin/users", "status": 403 },
|
|
52
|
+
{ "kind": "element", "query": { "role": "alert" }, "state": "visible" },
|
|
53
|
+
{ "kind": "text", "contains": "sk_live_", "absent": true },
|
|
54
|
+
{ "kind": "console", "contains": "Content Security Policy", "absent": true }
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
To check reachability for each role, see [Personas and simulation](#personas-and-simulation) below.
|
|
60
|
+
|
|
61
|
+
## Accessibility and UX
|
|
62
|
+
|
|
63
|
+
Reticle finds elements the way assistive technology does: by role and accessible name. That makes some accessibility behaviour directly checkable. For contrast, full screen-reader behaviour and complete WCAG coverage, pair it with an audit tool such as axe.
|
|
64
|
+
|
|
65
|
+
- A control is reachable by its **role and accessible name**. An icon button with no name cannot be found with `{ "role": "button", "name": "Close" }`.
|
|
66
|
+
- **Focus lands where it should.** When a dialog opens, focus moves into it (`state: "focused"`), and Reticle records focus dropping to `<body>` when a dialog closes.
|
|
67
|
+
- **The keyboard works.** `press` with `Enter` or `Escape` fires the control's action, not just a mouse click. The [verify-keyboard-access](https://github.com/reticlehq/reticle/tree/main/skills/verify-keyboard-access) skill walks through it.
|
|
68
|
+
- **Visible, enabled, checked, expanded, pressed and in-viewport** are all element states you can assert.
|
|
69
|
+
|
|
70
|
+
A synthetic Tab key does not move focus in a browser, so Reticle cannot verify Tab order, and it reports that as unknown rather than as a pass.
|
|
71
|
+
|
|
72
|
+
Open the "Delete project" dialog with `press` (`args: { "text": "Enter" }`) and require focus to move into it:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"kind": "allOf",
|
|
77
|
+
"predicates": [
|
|
78
|
+
{
|
|
79
|
+
"kind": "element",
|
|
80
|
+
"query": { "role": "dialog", "name": "Delete project" },
|
|
81
|
+
"state": "visible"
|
|
82
|
+
},
|
|
83
|
+
{ "kind": "element", "query": { "role": "button", "name": "Cancel" }, "state": "focused" }
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## Performance and monitoring
|
|
89
|
+
|
|
90
|
+
- **Request cardinality.** One keystroke in a debounced search sends one request, not one per character. The `duplicate-request` finding flags a write that fired more than once in a single action.
|
|
91
|
+
- **Page performance entries.** The SDK records largest-contentful-paint, a running layout-shift total and long tasks as `perf` events, which you read with `reticle_observe { filters: ["perf"] }`. The layout-shift figure is a running sum without the windowing a Core Web Vitals CLS score uses, so it works for "no layout shift on load" and trends, not as an exact CWV number.
|
|
92
|
+
- **Request timing.** Every captured request carries its duration in `reticle_observe { action: "network" }`.
|
|
93
|
+
- **React render rate.** With the React adapter, the commit count is readable as the `__reticle_renders` store, so a component that re-renders continuously while the screen looks idle shows up.
|
|
94
|
+
- **Recurring re-verification.** `npx @reticlehq/server verify <url>` replays your saved flows against a dev server or a staging/preview deployment and exits non-zero on a failure, so it runs in CI or on a schedule. The SDK refuses to connect in a production build, so this covers environments you control, not live production traffic.
|
|
95
|
+
|
|
96
|
+
Type "shoes" into a debounced search box and require exactly one request:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{ "kind": "net", "method": "GET", "urlContains": "/api/search", "count": 1 }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## SEO checks
|
|
103
|
+
|
|
104
|
+
Reticle sees the rendered page and the routes, so it covers the behavioural half of SEO. It does not read `<head>` meta tags or score a page, so pair it with an SEO crawler for those.
|
|
105
|
+
|
|
106
|
+
- `reticle_look { action: "page" }` reports the document `title` and the current route.
|
|
107
|
+
- **Headings and links.** The page's heading exists under its accessible name, and `reticle_look { action: "find", by: "role", value: "link", attrs: ["href"] }` lists every link with its `href`.
|
|
108
|
+
- **Redirects and routing.** A legacy URL lands on the right path: `{ "kind": "route", "pathname": "/pricing" }`.
|
|
109
|
+
- **Broken links and dead controls.** `reticle_verify { action: "crawl" }` drives every reachable control and reports failed requests, console errors and controls that do nothing.
|
|
110
|
+
|
|
111
|
+
After navigating to the old `/plans` URL, require the redirect and the page's main heading:
|
|
112
|
+
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"kind": "allOf",
|
|
116
|
+
"predicates": [
|
|
117
|
+
{ "kind": "route", "pathname": "/pricing" },
|
|
118
|
+
{ "kind": "element", "query": { "role": "heading", "name": "Pricing" }, "state": "visible" }
|
|
119
|
+
]
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Personas and simulation
|
|
124
|
+
|
|
125
|
+
- **Drive the app as a user.** `explore` takes a persona in plain words, drives that whole journey with a model inside the daemon, and saves what it drove as a flow that later replays with no model.
|
|
126
|
+
- **One context per role.** `reticle_lease { action: "acquire" }` opens an isolated browser context (its own cookies, storage and DOM) and can seed storage or cookies first, so an admin and a viewer drive the same app side by side. Reach it with `reticle_run`, or use `reticle verify <url> --storage-state <file>` from a terminal.
|
|
127
|
+
- **Reachability testing.** Signed in as a role, a control that role must not have is absent, and the call behind it never fires. `reticle_verify { action: "coverage" }` lists the controls you have and have not driven this session.
|
|
128
|
+
- **Multi-agent runs.** Several agents lease contexts from one shared headless Chromium, capped and queued, instead of starting a browser each. See [Multi-agent](/multi-agent-testing).
|
|
129
|
+
|
|
130
|
+
Have Reticle drive a first-time user's journey and record it:
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
npx @reticlehq/server verify http://localhost:3000 --explore --persona "a new user who signs up and creates a first project"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Then, signed in as a viewer, check what that role can reach:
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"kind": "allOf",
|
|
141
|
+
"predicates": [
|
|
142
|
+
{ "kind": "element", "query": { "role": "button", "name": "Invite member" }, "absent": true },
|
|
143
|
+
{ "kind": "net", "urlContains": "/api/billing", "count": 0 }
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Pairs well with
|
|
149
|
+
|
|
150
|
+
Reticle checks what your app does from inside it. Some jobs belong to other tools, and it works alongside them:
|
|
151
|
+
|
|
152
|
+
- **Pixel-level visual diffs:** a visual testing tool. Reticle can take screenshots, but its verdicts come from behaviour, not pixels.
|
|
153
|
+
- **Driving sites you don't own, or a cross-browser matrix:** Playwright. Reticle needs its dev-only SDK in the app, and its driven browser is Chromium.
|
|
154
|
+
- **Full WCAG audits:** axe or a similar audit tool.
|
|
155
|
+
- **Vulnerability discovery:** a security scanner.
|
|
156
|
+
|
|
157
|
+
What Reticle cannot see yet: IndexedDB, Web Workers, closed shadow roots and cross-origin iframes. When part of the page was out of reach, the verdict carries a `coverage` note, so a pass reads as "nothing failed in the part I could see". When the evidence cannot decide, the verdict is `unknown`, which is never counted as a pass.
|
package/docs/vs-screenshots.mdx
CHANGED
|
@@ -80,11 +80,11 @@ Those are real bugs and structural reads can miss them. Reticle has `reticle_scr
|
|
|
80
80
|
|
|
81
81
|
The argument is not "screenshots are bad". It is that a screenshot cannot answer "did the code work", and that is the question an AI coding agent needs answered on every change.
|
|
82
82
|
|
|
83
|
-
##
|
|
83
|
+
## What is measured, and what is not
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
What is measured is detection: 10 of 10 injected regressions caught with zero false alarms, against 9 and 8 for the alternatives, and one false green against a Playwright script's 29 over an 88-bug registry.
|
|
86
86
|
|
|
87
|
-
What is
|
|
87
|
+
What is not established is that Reticle makes agents _fix_ more bugs. A fix-loop test on a small fixture found the same fix rate with and without it; [Why Reticle](/why-reticle#what-the-fix-rate-test-measured) says what that test could and could not show.
|
|
88
88
|
|
|
89
89
|
## FAQ
|
|
90
90
|
|
package/docs/what-is-recorded.md
CHANGED
|
@@ -5,7 +5,7 @@ description: What Reticle keeps on your machine, what is redacted, and what it t
|
|
|
5
5
|
|
|
6
6
|
Reticle drives your app and reads what it did. That means it holds real content from real pages, so this page says exactly what it keeps, where it keeps it, and what it takes to make any of it leave.
|
|
7
7
|
|
|
8
|
-
If you read one line: **a verdict is entirely local and needs no account.** Nothing is sent anywhere until you run `reticle login` and `reticle link`. Without them there is nowhere for
|
|
8
|
+
If you read one line: **a verdict is entirely local and needs no account.** Nothing from your project is sent anywhere until you run `reticle login` and `reticle link`. Without them there is nowhere for it to go. (Anonymous usage counts, which carry nothing from your app, are separate and described in [Telemetry](telemetry.md).)
|
|
9
9
|
|
|
10
10
|
## On your machine
|
|
11
11
|
|
|
@@ -31,7 +31,7 @@ Network bodies are **not** captured by default. Page content that reaches a verd
|
|
|
31
31
|
|
|
32
32
|
## What leaves, only if you ask
|
|
33
33
|
|
|
34
|
-
`reticle login` signs this machine in. `reticle link` binds one repo to one cloud project. Until both have happened, `reticle push` has nothing to talk to and the sync path is a no-op. The code calls this the no-phone-home default.
|
|
34
|
+
`reticle login` signs this machine in. `reticle link` binds one repo to one cloud project. Until both have happened, or `RETICLE_API_KEY` is set in the environment, `reticle push` has nothing to talk to and the sync path is a no-op. The code calls this the no-phone-home default. A key in the environment is how CI syncs with no login and no link, and it goes to the hosted service unless `RETICLE_CLOUD_URL` names another host.
|
|
35
35
|
|
|
36
36
|
Once linked, you choose what syncs:
|
|
37
37
|
|
package/docs/what-is-reticle.mdx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: What is Reticle?
|
|
3
3
|
sidebarTitle: What is Reticle
|
|
4
|
-
description: Reticle is a verification layer for AI coding agents. It runs a dev-only SDK inside your running web app so an agent can prove a change works, instead of guessing. What it is,
|
|
4
|
+
description: Reticle is a verification layer for AI coding agents. It runs a dev-only SDK inside your running web app so an agent can prove a change works, instead of guessing. What it is, where it fits beside other tools, and what it needs.
|
|
5
5
|
icon: circle-question
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -12,37 +12,33 @@ It exists because an agent that writes code cannot otherwise tell whether that c
|
|
|
12
12
|
## How it works, in three parts
|
|
13
13
|
|
|
14
14
|
1. **An SDK inside the app.** Dev-only, stripped from production builds, added by a build plugin. It instruments the DOM, network, routing, console, animations, and your state library.
|
|
15
|
-
2. **A local bridge.** The SDK connects over a WebSocket to a daemon on your machine. The daemon never
|
|
16
|
-
3. **An MCP server.** The daemon exposes the app to your agent as tools. `
|
|
15
|
+
2. **A local bridge.** The SDK connects over a WebSocket to a daemon on your machine, bound to `127.0.0.1`. The daemon never manages your dev server; it attaches to the app that is running. On first setup, `npx @reticlehq/server init` starts the dev server with your project's own dev script and opens the app.
|
|
16
|
+
3. **An MCP server.** The daemon exposes the app to your agent as tools. `reticle_look` to look, `reticle_act_and_wait` to act and prove in one call, `reticle_observe` to read what the app did, `reticle_assert` to check.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Your app's data stays on your machine: no application code, DOM, network traffic, state or console output leaves it. Anonymous usage counts are sent by default and can be [turned off](/telemetry).
|
|
19
19
|
|
|
20
|
-
##
|
|
20
|
+
## Where it fits
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
Reticle sits next to several familiar categories, and it works alongside each of them.
|
|
23
23
|
|
|
24
|
-
**
|
|
24
|
+
**Browser automation.** Playwright, Cypress and Selenium drive a browser from the outside. Reticle runs inside the page you already have open and answers "did the thing I just changed actually work?" Playwright remains the tool for sites you don't own and for a cross-browser matrix.
|
|
25
25
|
|
|
26
|
-
**
|
|
26
|
+
**Your test suite.** Unit and integration tests keep doing their job. Reticle covers the layer they cannot reach: behaviour that only exists when the whole application runs, which is often where a suite passes over a broken app.
|
|
27
27
|
|
|
28
|
-
**
|
|
28
|
+
**Visual testing.** Reticle can take screenshots, but its verdicts come from predicates over real events (a request with a status, a state path, a signal your code fired), so they do not break when a button moves four pixels. For pixel-level diffs, pair it with a visual testing tool.
|
|
29
29
|
|
|
30
|
-
**
|
|
30
|
+
**Security, accessibility, performance and SEO.** Reticle checks how your running app behaves in each: access control by role, calls that must never fire, focus and keyboard behaviour, request counts and long tasks, titles, links and redirects. It pairs with a vulnerability scanner, a full WCAG audit tool such as axe, and an SEO crawler. [Use cases](/use-cases) has what each check covers.
|
|
31
31
|
|
|
32
|
-
**
|
|
32
|
+
**Monitoring.** Reticle runs against environments you control (a dev server, a staging or preview deployment) and replays saved flows in CI. The SDK refuses to connect in a production build, so it complements an APM or error tracker rather than watching live traffic.
|
|
33
33
|
|
|
34
|
-
**
|
|
34
|
+
**Your agent.** Reticle has no model of its own for the verify loop. It gives the agent you already use a way to see the running app. Your agent, your model, your keys. (`explore` can drive a journey for you with a model inside the daemon; see [Autodrive](/autodrive).)
|
|
35
35
|
|
|
36
|
-
**
|
|
37
|
-
|
|
38
|
-
**Not a way to make a failing check pass.** A verdict of `unknown` means Reticle drove the app and could not tell. It is deliberately not rounded up to a pass, because a verification tool that flatters you is worse than none.
|
|
36
|
+
**The verdict.** A verdict of `unknown` means Reticle drove the app and could not tell. It is deliberately not rounded up to a pass.
|
|
39
37
|
|
|
40
38
|
## What Reticle needs
|
|
41
39
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- **A web application you can run locally**, with its dev server. Reticle attaches; it does not start one.
|
|
45
|
-
- **A build step it can hook**, or two lines added by hand. Vite, Next.js, Remix and Astro are proven by gates in the repository. The SDK is framework agnostic and usually connects elsewhere, with reduced source mapping.
|
|
40
|
+
- **A web application you can run**, with a dev build. `init` starts its dev server for you.
|
|
41
|
+
- **A build step it can hook**, or two lines added by hand. [Frameworks](/frameworks) lists what is proven for each.
|
|
46
42
|
- **An agent that speaks MCP.** Claude Code, Cursor, Codex, Copilot, Windsurf, OpenCode and others.
|
|
47
43
|
- **Node 20 or newer.**
|
|
48
44
|
|
|
@@ -59,5 +55,6 @@ Side by side with the tools people ask about most:
|
|
|
59
55
|
## Where to go next
|
|
60
56
|
|
|
61
57
|
- [Quickstart](/quickstart) gets a real verdict out of your own app in about five minutes.
|
|
62
|
-
- [Why Reticle](/why-reticle) is the argument, with the evidence and
|
|
58
|
+
- [Why Reticle](/why-reticle) is the argument, with the evidence and what pairs well with it.
|
|
59
|
+
- [Use cases](/use-cases) covers what people verify with it.
|
|
63
60
|
- [For agents](/for-agents) is written for the agent rather than for you.
|
package/docs/why-reticle.mdx
CHANGED
|
@@ -63,37 +63,30 @@ Observing one real dashboard once, with no bug involved:
|
|
|
63
63
|
That last column is the one that matters more than the token counts. The other tools can _describe_ what a page looks like. Only Reticle can check whether the thing the app itself considers success actually happened.
|
|
64
64
|
|
|
65
65
|
<Card title="How every number was measured" icon="chart-column" href="/benchmarks">
|
|
66
|
-
The full method, the raw data, and the scenarios where
|
|
66
|
+
The full method, the raw data, and the scenarios where the tools tie.
|
|
67
67
|
</Card>
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
On raw cost per glance, Chrome DevTools MCP is cheaper: 758 tokens against 815. It catches fewer bugs, which is why the efficiency column favours Reticle.
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
## What the fix-rate test measured
|
|
72
72
|
|
|
73
|
-
-
|
|
74
|
-
- **Pixels.** Reticle reads the program, not the screen. If your bug is "the button is three pixels too far left", Reticle is the wrong instrument.
|
|
75
|
-
- **Chrome DevTools MCP is cheaper per look.** 758 tokens against our 815. It catches fewer bugs, so the efficiency works out in our favour, but on raw cost per glance it wins.
|
|
73
|
+
We ran a fix-loop ablation: agents fixed 8 bugs injected into a small fixture app, with Reticle and without it, on a strong model and on a weaker one. **It did not show a fix-rate improvement at either tier.** The strong model fixed 8 of 8 in both conditions and the weaker one 7 of 8 in both, and the Reticle arm made roughly five to six times the tool calls, because driving an app costs more than reading a few short files.
|
|
76
74
|
|
|
77
|
-
|
|
75
|
+
The test cannot settle the question in either direction, and the reasons are specific: the fixture is small enough to read whole, several injected bugs were labelled by a comment on the changed line, and "fixed" was checked by a string disappearing rather than by the app behaving. One case pointed each way. The weaker model without Reticle claimed a fix it never applied, and the live re-check caught that with Reticle; with Reticle, the same model over-edited a stylesheet the string check scored as a pass. The full log is in [`bench/fix-loop/results.md`](https://github.com/reticlehq/reticle/blob/main/bench/fix-loop/results.md).
|
|
78
76
|
|
|
79
|
-
|
|
77
|
+
A separate, smaller measurement of the source pointer alone found the same fix rate with and without it (6 of 6) and fewer tool calls with it (12 against 22). The pointer removed the search; it did not make the agent more capable.
|
|
80
78
|
|
|
81
|
-
|
|
79
|
+
That is what Reticle is designed to improve: not the agent, but the verdict it reports. A broken build reads as broken, a failure arrives with the evidence and the `file:line`, and "I couldn't tell" is reported as that. In the 88-bug head-to-head against a Playwright script, Reticle reported one false green where the script reported 29.
|
|
82
80
|
|
|
83
|
-
|
|
81
|
+
## When to use it
|
|
84
82
|
|
|
85
|
-
|
|
83
|
+
You own the app, an agent edits it, and you want the agent to prove its work rather than assure you of it. It needs a dev build it can instrument, and React (and any framework whose build plugin stamps source) adds source pointers on top. [Use cases](/use-cases) covers what people check with it beyond change verification, from access control to accessibility.
|
|
86
84
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
<Card title="A bad fit" icon="circle-xmark">
|
|
93
|
-
You're testing a site you don't control, you need pixel-level visual regression, or your app has
|
|
94
|
-
no dev build to instrument.
|
|
95
|
-
</Card>
|
|
96
|
-
</CardGroup>
|
|
85
|
+
## Pairs well with
|
|
86
|
+
|
|
87
|
+
- **Playwright** for driving sites you don't own and a cross-browser matrix. Reticle needs its dev-only SDK inside the app.
|
|
88
|
+
- **A visual testing tool** for pixel-level regression. Reticle reads the program, not the screen, so "the button is three pixels too far left" is a job for pixels.
|
|
89
|
+
- **axe** for full WCAG audits, and **a security scanner** for vulnerability discovery.
|
|
97
90
|
|
|
98
91
|
## The one-sentence version
|
|
99
92
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@reticlehq/server",
|
|
3
|
-
"version": "3.
|
|
4
|
-
"description": "Reticle bridge
|
|
3
|
+
"version": "3.4.0",
|
|
4
|
+
"description": "Reticle CLI, bridge and MCP server: a coding agent drives your running web app from the inside and gets a verdict with evidence, for change verification, access control, accessibility, performance and SEO checks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -19,24 +19,24 @@
|
|
|
19
19
|
}
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@modelcontextprotocol/sdk": "^1.30.
|
|
22
|
+
"@modelcontextprotocol/sdk": "^1.30.1",
|
|
23
23
|
"ws": "^8.21.3",
|
|
24
24
|
"zod": "^3.24.1",
|
|
25
25
|
"zod-to-json-schema": "^3.24.0",
|
|
26
|
-
"@reticlehq/
|
|
27
|
-
"@reticlehq/
|
|
28
|
-
"@reticlehq/
|
|
26
|
+
"@reticlehq/browser": "3.4.0",
|
|
27
|
+
"@reticlehq/init": "3.4.0",
|
|
28
|
+
"@reticlehq/engine": "3.4.0",
|
|
29
29
|
"open-verification": "1.0.0",
|
|
30
|
-
"@reticlehq/core": "3.
|
|
30
|
+
"@reticlehq/core": "3.4.0"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/pngjs": "^6.0.5",
|
|
34
34
|
"@types/ws": "^8.5.13",
|
|
35
|
-
"yaml": "^2.9.
|
|
35
|
+
"yaml": "^2.9.1"
|
|
36
36
|
},
|
|
37
37
|
"optionalDependencies": {
|
|
38
38
|
"pixelmatch": "^7.2.0",
|
|
39
|
-
"playwright": "^1.
|
|
39
|
+
"playwright": "^1.63.0",
|
|
40
40
|
"pngjs": "^7.0.0"
|
|
41
41
|
},
|
|
42
42
|
"license": "FSL-1.1-ALv2",
|
|
@@ -60,6 +60,7 @@
|
|
|
60
60
|
"mcp",
|
|
61
61
|
"ai-agents",
|
|
62
62
|
"testing",
|
|
63
|
+
"verification",
|
|
63
64
|
"cli"
|
|
64
65
|
],
|
|
65
66
|
"reticle": {
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bug-capsule minimization — first cut: prefix-trim. A recorded flow that fails is often mostly setup;
|
|
3
|
-
* the capsule should be the SMALLEST flow that still reproduces the failure, so a regression flow stays
|
|
4
|
-
* fast and legible. Prefix-trim drops leading steps while the failure persists — the cheap, deterministic
|
|
5
|
-
* v1 (delta-debugging over arbitrary subsets is a later refinement). The `stillFails` predicate is
|
|
6
|
-
* injected (a real replay), so this stays pure and unit-testable.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Return the shortest trailing sub-flow that still fails, by removing leading steps one at a time while
|
|
10
|
-
* `stillFails` holds. Never trims below one step. Deterministic given a deterministic predicate.
|
|
11
|
-
*/
|
|
12
|
-
export declare function prefixTrim<T>(steps: readonly T[], stillFails: (candidate: readonly T[]) => Promise<boolean>): Promise<T[]>;
|