@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/best-practices.mdx
CHANGED
|
@@ -196,7 +196,7 @@ Sessions accumulate. Four stale ones pointing at dev servers you restarted an ho
|
|
|
196
196
|
|
|
197
197
|
## Confirm a navigation landed
|
|
198
198
|
|
|
199
|
-
`reticle_navigate` returns `confirmed: false` by design. A navigation destroys the document the SDK lives in, so it can only report dispatch. Check [`
|
|
199
|
+
`reticle_navigate` returns `confirmed: false` by design. A navigation destroys the document the SDK lives in, so it can only report dispatch. Check [`reticle_session { action: "list" }`](/tools/sessions) for a session at the new URL before acting, and re-snapshot: refs do not survive a new document.
|
|
200
200
|
|
|
201
201
|
## Start with what the app says about itself
|
|
202
202
|
|
package/docs/capabilities.mdx
CHANGED
|
@@ -55,7 +55,7 @@ Useful at the end of a drive, when the agent is about to report success. "I veri
|
|
|
55
55
|
}
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
Note the token redaction. Credential-shaped values are stripped here exactly as they are in [`
|
|
58
|
+
Note the token redaction. Credential-shaped values are stripped here exactly as they are in [`reticle_observe { action: "network" }`](/tools/network), so reading storage never puts a session token in your context.
|
|
59
59
|
|
|
60
60
|
localStorage, sessionStorage and readable cookies.
|
|
61
61
|
|
|
@@ -87,6 +87,24 @@ Toasts that auto-dismiss, debounced search, polling, session timeouts, retry bac
|
|
|
87
87
|
|
|
88
88
|
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.
|
|
89
89
|
|
|
90
|
+
<Warning>
|
|
91
|
+
Freeze the clock **before** the action that schedules the timer. Reticle replaces the page's
|
|
92
|
+
`setTimeout` and `setInterval` when the clock is frozen, so timers that already exist keep running
|
|
93
|
+
on the browser's real clock and are not fired by `advanceMs`.
|
|
94
|
+
|
|
95
|
+
If a timer is created during page mount, freeze the clock first and then reload the page so the mount-time timer is created under the fake clock.
|
|
96
|
+
|
|
97
|
+
</Warning>
|
|
98
|
+
|
|
99
|
+
The clock virtualizes `Date.now()`, but not every time API. `new Date()` and `performance.now()` continue to use real time. `performance.now()` is intentionally left real because React's scheduler depends on it.
|
|
100
|
+
|
|
101
|
+
The reliable pattern is:
|
|
102
|
+
|
|
103
|
+
1. Freeze the clock.
|
|
104
|
+
2. Perform the action that schedules the timer, or reload the page if the timer is created during mount.
|
|
105
|
+
3. Advance by the required interval.
|
|
106
|
+
4. Assert the consequence.
|
|
107
|
+
|
|
90
108
|
### Crawl: click everything, report anomalies
|
|
91
109
|
|
|
92
110
|
```json
|
|
@@ -123,6 +141,19 @@ This is the tool for an app you did not write and do not understand yet.
|
|
|
123
141
|
25.
|
|
124
142
|
</Warning>
|
|
125
143
|
|
|
144
|
+
Controls Reticle judges destructive are blocked unless you pass `confirmDangerous: true`. That covers the controls on the page the crawl started on. A control one of its clicks revealed, such as the "Yes, delete" behind a "Delete", stays blocked, so one crawl cannot finish a deletion you did not look at.
|
|
145
|
+
|
|
146
|
+
### Covering everything: `exhaustive`
|
|
147
|
+
|
|
148
|
+
`{ "action": "crawl", "exhaustive": true }` goes past one page. It walks every state reachable from where you start, reaching each one by replaying the path that found it from a fresh load, so it never depends on "back" working. It fills text fields before it tries a form's buttons (from `RETICLE_SECRET_<FIELD>` when set, so it gets past a login, and only on the origin the crawl started on), and treats controls that differ only by a number, like table rows, as one. A control with the same name on a different screen is tried again there. Every write it finds is then driven again with the request failing. A write counts as **branched** only when the request was actually sent and broken. With the write failing, the app must not end up where it goes when the write succeeds; if it does, you get `failure-unhandled`. That part needs a browser Reticle drives (`reticle drive`).
|
|
149
|
+
|
|
150
|
+
The run folds into the app-wide coverage ledger, which `reticle_verify { action: "coverage", app: true }` also reports. It has six levels, each with what is missing: routes **reached**, controls **touched**, controls **proved** (an `act_and_wait` came back `yes`), journeys **completed**, writes **branched** (failure path driven), and app functions **executed** (V8 coverage, driven browser only, collected from the first coverage request or exhaustive crawl onward, so an ordinary drive pays nothing for it). `frontier` is the number of states found and not yet explored. Zero means every state the explorer could tell apart was explored, not that every reachable state was: a state is its route plus the names of its controls, so two screens that differ only in field values, in how many of a control they show, or in what the same controls do count as one, and the second is never visited. `reticle gate` blocks when a level falls below the best it has reached, and when a changed file never ran. A changed file whose coverage was taken before the edit is reported as `coverageStale` instead, because its counts describe the old code. When a drop was intended, `reticle gate --accept-coverage` records today's levels as the new best.
|
|
151
|
+
|
|
152
|
+
<Warning>
|
|
153
|
+
Exhaustive really does click everything, repeatedly, and submits forms. `maxSteps` bounds it,
|
|
154
|
+
defaulting to 400 actions.
|
|
155
|
+
</Warning>
|
|
156
|
+
|
|
126
157
|
### Reconcile: what the API said versus what rendered
|
|
127
158
|
|
|
128
159
|
```json
|
package/docs/cli/cloud.mdx
CHANGED
|
@@ -20,7 +20,13 @@ These are thin clients over the `/v1` API. The logic is server-side; these verbs
|
|
|
20
20
|
| `~/.reticle/credentials.json` | Project-scoped API keys from `reticle link`, keyed by `projectId` | Yes |
|
|
21
21
|
| `<repo>/.reticle/cloud.json` | `{ projectId, projectName, url, sync, verify }`. The non-secret binding | No, commit it |
|
|
22
22
|
|
|
23
|
-
Auth for any command is `RETICLE_API_KEY` from the environment (the agent path) if set, otherwise the login token. `RETICLE_CLOUD_URL` overrides the endpoint;
|
|
23
|
+
Auth for any command is `RETICLE_API_KEY` from the environment (the agent path) if set, otherwise the login token. `RETICLE_CLOUD_URL` (or its short form `RETICLE_URL`) overrides the endpoint; without it, a command uses the saved session's host, and otherwise the hosted service, `https://app.reticle.sh`.
|
|
24
|
+
|
|
25
|
+
## In CI
|
|
26
|
+
|
|
27
|
+
CI needs `RETICLE_API_KEY` and nothing else: no `login`, no `link`. Commit `.reticle/cloud.json`, store the key as a secret, and the daemon and `reticle push` sync to the project the binding names. A key stored in `credentials.json` wins over the environment when both exist.
|
|
28
|
+
|
|
29
|
+
The environment key is only sent to the host it belongs to: `RETICLE_CLOUD_URL` when set, otherwise the hosted service. A repo linked to a self-hosted install therefore also needs `RETICLE_CLOUD_URL` set to that install in CI. A repo with no `cloud.json` and a key in the environment syncs to the hosted service, or to `RETICLE_CLOUD_URL`.
|
|
24
30
|
|
|
25
31
|
## The commands
|
|
26
32
|
|
|
@@ -101,9 +107,13 @@ reticle: no .reticle/cloud.json here ... run `reticle link` first
|
|
|
101
107
|
|
|
102
108
|
### `reticle push`
|
|
103
109
|
|
|
104
|
-
Sends local run artifacts from `.reticle` to the linked project, honoring the sync policy. With `sync.runs` off it does nothing and says so. Prints `{ ok, project, sent, pulled }`, where `sent` carries the accepted counts and, when the server refused anything, a `rejected` array naming each
|
|
110
|
+
Sends local run artifacts from `.reticle` to the linked project, honoring the sync policy. With `sync.runs` off it does nothing and says so. Prints `{ ok, project, sent, pulled }`, where `sent` carries the accepted counts and, when the server refused anything, a `rejected` array naming each run's index and reason and a `refused` array for flows, capsules and derived records. `sent.records` lists only the records the server accepted.
|
|
111
|
+
|
|
112
|
+
Runs go up in batches, so a large backlog is never one oversized request.
|
|
113
|
+
|
|
114
|
+
What the platform cannot read is not sent at all, and a `notSent` array says why: a record kind an older platform does not know yet (this one alone leaves `ok` true), or a flow or run in a file version it does not read. Sending those would only be refused again on every cycle.
|
|
105
115
|
|
|
106
|
-
**A rejection is a failed push.** If the server refuses any artifact, `ok` is `false` and the command exits `1`, even when other artifacts in the same bundle landed. A refused artifact never reaches the dashboard and is re-offered on every cycle, so partial loss is still loss. `ok: true` and exit `0` mean everything offered was accepted, which includes the common case of a repo that was already up to date. The accepted counts still report what did land, so a partial push is visible as one.
|
|
116
|
+
**A rejection is a failed push.** If the server refuses any artifact, `ok` is `false` and the command exits `1`, even when other artifacts in the same bundle landed. The reason is kept as `sync.lastError` in `reticle whoami`, and the background daemon logs it once, until a cycle refuses nothing. A refused run is not offered again until its file changes or the platform reports that it reads more: until then it is listed under `notRetried`, and the summary reads `refused, not retried: N run(s) (reason)`. A refused artifact never reaches the dashboard and is re-offered on every cycle, so partial loss is still loss. `ok: true` and exit `0` mean everything offered was accepted, which includes the common case of a repo that was already up to date. The accepted counts still report what did land, so a partial push is visible as one.
|
|
107
117
|
|
|
108
118
|
### `reticle runs`
|
|
109
119
|
|
|
@@ -130,7 +140,7 @@ reticle: usage: reticle share <runId>
|
|
|
130
140
|
`push`, `runs` and `regression` all need a project to talk to. Without one they exit `1` with the same line on stderr, measured:
|
|
131
141
|
|
|
132
142
|
```
|
|
133
|
-
reticle: cloud not attached here ... run `reticle link` (or set
|
|
143
|
+
reticle: cloud not attached here ... run `reticle link` (or set RETICLE_API_KEY)
|
|
134
144
|
```
|
|
135
145
|
|
|
136
146
|
## Exit codes
|
package/docs/cli/doctor.mdx
CHANGED
|
@@ -72,6 +72,10 @@ All three captures below are real, taken by pointing `PLAYWRIGHT_BROWSERS_PATH`
|
|
|
72
72
|
chromium ✓ installed (chromium-1234)
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
**`✓ using the installed Google Chrome`** (or Microsoft Edge) means the pinned build is absent and Reticle drives the browser you already have instead, through Playwright's channel. Nothing to do: the line also names the command that adds Playwright's own build, if you want it.
|
|
76
|
+
|
|
77
|
+
When neither is there, Reticle does not refuse. The first command that needs a browser (a lease, `verify`, a drive) runs the bundled Playwright's own pinned install for you, announced on stderr so `reticle mcp`'s stdout stays clean. The two `✗` lines below are what you see when that has not happened yet, or failed.
|
|
78
|
+
|
|
75
79
|
**`✗ wrong revision`** means builds are installed and none of them is the wanted one. One pinned download away. The line names the revision Playwright wants, then every revision the root actually holds, then the exact command:
|
|
76
80
|
|
|
77
81
|
```
|
package/docs/cli/feedback.mdx
CHANGED
|
@@ -11,7 +11,7 @@ npx @reticlehq/server feedback [--rating 1-5] [--bug] "what worked, what didn't"
|
|
|
11
11
|
npx @reticlehq/server feedback --agent --kind <bug|gap|ambiguity|feature_request|improvement> "what happened"
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
The `--agent` form is for an agent that cannot reach the `
|
|
14
|
+
The `--agent` form is for an agent that cannot reach the `reticle_session { action: "feedback" }` tool: during `init`, while instrumentation is half wired, or when the daemon will not start. Those are the reports that are hardest to hear and most needed, because every other path requires the tool surface to already work.
|
|
15
15
|
|
|
16
16
|
## Flags
|
|
17
17
|
|
|
@@ -63,5 +63,5 @@ npx @reticlehq/server feedback --agent --kind gap \
|
|
|
63
63
|
icon="comments"
|
|
64
64
|
href="/tools/session-and-feedback"
|
|
65
65
|
>
|
|
66
|
-
`
|
|
66
|
+
`reticle_session { action: "feedback" }` when the tools are reachable.
|
|
67
67
|
</Card>
|
package/docs/cli/gate.mdx
CHANGED
|
@@ -7,7 +7,7 @@ icon: shield-halved
|
|
|
7
7
|
`reticle gate` is what makes verification unavoidable. It computes the [affected](/cli/affected) flows, looks for a passing artifact for each, and fails the command if any is missing. An agent that edits a covered file cannot call itself finished without re-verifying.
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx @reticlehq/server gate [--since <ref>] [file...]
|
|
10
|
+
npx @reticlehq/server gate [--since <ref>] [--accept-coverage] [file...]
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
## Arguments and flags
|
|
@@ -16,6 +16,7 @@ npx @reticlehq/server gate [--since <ref>] [file...]
|
|
|
16
16
|
| --- | --- | --- | --- |
|
|
17
17
|
| `file...` | strings, positional | none | Explicit changed files |
|
|
18
18
|
| `--since <ref>` | string | `HEAD` when no files are given | Also include files git reports as changed since this ref |
|
|
19
|
+
| `--accept-coverage` | boolean | off | Accept today's coverage levels as the new best before judging. Use it when a drop was intended, such as a control you removed on purpose. The run reports what it accepted as `coverageAccepted` |
|
|
19
20
|
|
|
20
21
|
## What blocks and what does not
|
|
21
22
|
|
|
@@ -24,6 +25,10 @@ npx @reticlehq/server gate [--since <ref>] [file...]
|
|
|
24
25
|
| `uncovered` | Yes | An affected flow with no passing artifact |
|
|
25
26
|
| `downgraded` | Yes | A flow whose assertions were weakened since its last passing run. A green bought by weakening the test is the gaming move this exists to stop |
|
|
26
27
|
| `deletedCoverage` | Yes | A flow that covered a changed file and has since vanished. Coverage deleted, not satisfied |
|
|
28
|
+
| `unflowed` | Yes | A changed interactive component that no saved flow drives. Only once the project has saved flows, so a first day never blocks |
|
|
29
|
+
| `coverageRegressed` | Yes | A [coverage](/capabilities) level fell below the best it has reached: something new appeared that nothing covers. Cover it, or accept the drop with `--accept-coverage` |
|
|
30
|
+
| `unexecuted` | Yes | A changed file the browser loaded during a drive and never ran a function of |
|
|
31
|
+
| `coverageStale` | No | A changed file whose code coverage was taken before its last edit. Its counts describe the old code, so `unexecuted` cannot judge it either way. Take coverage again after driving the change to measure it |
|
|
27
32
|
| `quarantined` | No | Flows the flake ledger has quarantined. Surfaced, never blocking, because one unexplained flake that blocks a merge destroys trust in the red |
|
|
28
33
|
|
|
29
34
|
## What it prints
|
|
@@ -41,14 +46,14 @@ One `reticle_gate` line. Real capture from this repository, with the flow lists
|
|
|
41
46
|
}
|
|
42
47
|
```
|
|
43
48
|
|
|
44
|
-
`downgraded` and `
|
|
49
|
+
`downgraded`, `deletedCoverage`, `unflowed`, `coverageRegressed`, `unexecuted`, `coverageStale` and `coverageAccepted` appear only when they are non-empty, and none was present in that run. The coverage categories need a coverage ledger, which a project gets from `reticle_verify { action: "crawl", exhaustive: true }` or `reticle_verify { action: "coverage", app: true }`; without one they never fire. The CLI prints this as a single line of JSON; it is pretty-printed here to be readable.
|
|
45
50
|
|
|
46
51
|
## Exit codes
|
|
47
52
|
|
|
48
53
|
| Code | Meaning |
|
|
49
54
|
| --- | --- |
|
|
50
|
-
| `0` | Every affected, non-flaky flow has a passing artifact
|
|
51
|
-
| `1` | Something is uncovered, downgraded or
|
|
55
|
+
| `0` | Every affected, non-flaky flow has a passing artifact, nothing was weakened or deleted, and coverage held |
|
|
56
|
+
| `1` | Something is uncovered, downgraded, deleted, unflowed, unexecuted, or coverage fell. Also `1` on any internal fault: the gate fails closed |
|
|
52
57
|
|
|
53
58
|
Measured on this repository, `npx @reticlehq/server gate --since HEAD~1` exited `1` with the output above: 0 of 47 flows covered, 39 uncovered and 8 quarantined.
|
|
54
59
|
|
package/docs/cli/update.mdx
CHANGED
|
@@ -31,6 +31,16 @@ No flags.
|
|
|
31
31
|
|
|
32
32
|
The SDK sync is best effort and non-fatal on purpose. This command gets run from wherever the human happens to be standing, which is often not an app at all.
|
|
33
33
|
|
|
34
|
+
## Stuck on an older Windows release
|
|
35
|
+
|
|
36
|
+
Reticle 3.1.0 and older cannot apply this update on Windows and may fail with `spawn EINVAL`. Those releases run their own outdated updater, so retrying the command will not help. Run the installer directly from PowerShell instead:
|
|
37
|
+
|
|
38
|
+
```powershell
|
|
39
|
+
irm https://raw.githubusercontent.com/reticlehq/reticle/main/install/install.ps1 | iex
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This installs the current server without going through the old updater.
|
|
43
|
+
|
|
34
44
|
## Exit codes
|
|
35
45
|
|
|
36
46
|
| Code | Meaning |
|
package/docs/cli.mdx
CHANGED
|
@@ -112,6 +112,15 @@ policy https://github.com/reticlehq/reticle/blob/main/docs/telemetry.md
|
|
|
112
112
|
|
|
113
113
|
A bare `reticle` with no arguments is not help. It is `reticle serve`.
|
|
114
114
|
|
|
115
|
+
<Note>
|
|
116
|
+
When the Reticle SDK installed in the project is a different **major** version from the CLI you ran,
|
|
117
|
+
the CLI hands the same command to `npx @reticlehq/server@<that version>`, so an unpinned
|
|
118
|
+
`npx @reticlehq/server` never pairs a daemon with an SDK it cannot talk to. `init`, `update`,
|
|
119
|
+
`rollback`, `setup install`, `version` and `help` always run as typed, and so does a command whose
|
|
120
|
+
version you pinned yourself (`npx @reticlehq/server@<version> …`). Set `RETICLE_NO_VERSION_MATCH=1` to
|
|
121
|
+
turn it off.
|
|
122
|
+
</Note>
|
|
123
|
+
|
|
115
124
|
<Warning>
|
|
116
125
|
`reticle verify` binds the bridge port itself, so it fails if a daemon is already listening, which
|
|
117
126
|
is the normal state once your agent has started one. Stop the daemon first, or point it elsewhere
|
package/docs/desktop.mdx
CHANGED
|
@@ -88,7 +88,7 @@ The rows in **bold** are re-proven by a committed battery on every change, `pnpm
|
|
|
88
88
|
| Capability | Electron | Tauri | Note |
|
|
89
89
|
| --- | --- | --- | --- |
|
|
90
90
|
| sessions, snapshot, query, inspect | yes | yes | `inspect` returns `src/App.tsx:104` in a dev build; a packaged production renderer has no source map, so it reports `n/a` |
|
|
91
|
-
| capabilities, state (live store) | yes | yes | `
|
|
91
|
+
| capabilities, state (live store) | yes | yes | `reticle_look { action: "state" }` reads the real store |
|
|
92
92
|
| act (click/fill/type/select) | yes | yes | |
|
|
93
93
|
| **act_and_wait, wait_for, assert** | yes | yes | signal / state / route / net / console predicates |
|
|
94
94
|
| console errors | yes | yes | catches what the UI never shows |
|
|
@@ -133,7 +133,7 @@ export default defineConfig({
|
|
|
133
133
|
});
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
-
`desktop: true` does
|
|
136
|
+
`desktop: true` does two things a desktop shell needs: `connect()` is injected into the renderer's entry module, so a renderer loaded with no dev server still resolves it, and it is called with `allowInProduction`, because a packaged renderer reports `NODE_ENV=production` and the SDK's production backstop would otherwise refuse to start. It instruments the dev server, and a `vite build` **only when that build runs in a non-production mode**: `vite build --mode development`, for a packaged renderer you want to drive with no dev server. A production-mode build, which is what `vite build` and `electron-vite build` do by default, is stubbed exactly like a web bundle: it carries no SDK and never dials `ws://localhost`, so a release binary built the normal way is clean.
|
|
137
137
|
|
|
138
138
|
Nothing to add in your app code. You can still call `reticle.connect()` by hand and pass `inject: false` if you want control.
|
|
139
139
|
|
|
@@ -157,10 +157,12 @@ That line is what makes your main-process calls visible. It has to live in the p
|
|
|
157
157
|
|
|
158
158
|
**Preload sandboxing.** A sandboxed preload cannot resolve `node_modules`, so the bare `require` above fails with `module not found: @reticlehq/electron/preload`. Either bundle your preload (electron-vite and Electron Forge do this by default; the require is inlined at build time and sandboxing stays on), or set `sandbox: false` in `webPreferences`.
|
|
159
159
|
|
|
160
|
-
**Packaged renderers.** An app that loads its renderer with `loadFile` runs on `file
|
|
160
|
+
**Packaged renderers.** An app that loads its renderer with `loadFile` runs on `file://` with no dev server. To drive one, build its renderer with `vite build --mode development` (the plugin then instruments it, `allowInProduction` included). The default production-mode build ships no Reticle code at all.
|
|
161
161
|
|
|
162
162
|
Working example: [`apps/electron-smoke`](https://github.com/reticlehq/reticle/tree/main/apps/electron-smoke).
|
|
163
163
|
|
|
164
|
+
**Electron Forge.** `reticle init` recognises Forge's Vite template (`vite.renderer.config.*` and no `vite.config.*`) and wires it the same three ways: `reticle()` in the renderer config, the preload shim, and `installReticleCapture` in main. The plugin goes in **without** `desktop: true`, because `electron-forge start` serves the renderer through a real Vite dev server, so the ordinary serve-time injection reaches the window and `electron-forge package` ships a renderer with no Reticle code. `init` starts the app with the script that runs `electron-forge start`, not the renderer's dev script. A vanilla renderer gets `@reticlehq/browser` rather than the React kit.
|
|
165
|
+
|
|
164
166
|
## Tauri setup
|
|
165
167
|
|
|
166
168
|
Frontend side, nothing desktop-specific:
|
|
@@ -214,7 +216,7 @@ Alternatively, since an Electron renderer _is_ Chromium, `--remote-debugging-por
|
|
|
214
216
|
|
|
215
217
|
```toml
|
|
216
218
|
[dependencies]
|
|
217
|
-
reticle-tauri = "3.
|
|
219
|
+
reticle-tauri = "3.4"
|
|
218
220
|
```
|
|
219
221
|
|
|
220
222
|
```rust
|
|
@@ -283,12 +285,12 @@ A packaged renderer runs on `file://`, where `pushState('/settings')` rewrites t
|
|
|
283
285
|
|
|
284
286
|
## What IPC looks like to an agent
|
|
285
287
|
|
|
286
|
-
A desktop app reaches its backend over IPC, not HTTP. `fetch`/`XHR` patching cannot see that, so without the IPC observer every backend call in your app is a blind spot: `
|
|
288
|
+
A desktop app reaches its backend over IPC, not HTTP. `fetch`/`XHR` patching cannot see that, so without the IPC observer every backend call in your app is a blind spot: `reticle_observe { action: "network" }` returns nothing, `act_and_wait` has no in-flight request to settle on, and `assert { net }` is vacuously true. That is a false green by construction.
|
|
287
289
|
|
|
288
290
|
Reticle records each IPC call as an ordinary request, so the tools you already use work unchanged:
|
|
289
291
|
|
|
290
292
|
```jsonc
|
|
291
|
-
//
|
|
293
|
+
// reticle_observe { action: "network", urlContains: "ipc://" }
|
|
292
294
|
{
|
|
293
295
|
"calls": [
|
|
294
296
|
{ "method": "ipc", "url": "ipc://todos:load", "status": 200, "ms": 134 },
|
|
@@ -297,7 +299,7 @@ Reticle records each IPC call as an ordinary request, so the tools you already u
|
|
|
297
299
|
}
|
|
298
300
|
```
|
|
299
301
|
|
|
300
|
-
IPC has no status code. `200`/`500` are synthetic, mapped from whether the call succeeded or failed, precisely so that `
|
|
302
|
+
IPC has no status code. `200`/`500` are synthetic, mapped from whether the call succeeded or failed, precisely so that `reticle_observe { action: "network", status: 500 }` and `assert { kind: "net", status: 500 }` keep working. On Tauri you will see `status: 500` next to `statusText: "OK"`. That is not a bug: the transport really did answer 200, and the 500 is the command's own verdict. `ok` is authoritative, and on Electron `error` carries the message your main process returned:
|
|
301
303
|
|
|
302
304
|
```jsonc
|
|
303
305
|
// reticle_assert { predicate: { kind: "net", urlContains: "ipc://todos:archive", status: 500 } }
|
|
@@ -363,9 +365,11 @@ Playwright MCP is faster. It is also structurally unable to see an IPC failure,
|
|
|
363
365
|
Tauri, no: WKWebView exposes no CDP endpoint, so Playwright cannot attach at all.
|
|
364
366
|
</Accordion>
|
|
365
367
|
<Accordion title="Does the SDK end up in my shipped binary?">
|
|
366
|
-
|
|
367
|
-
`
|
|
368
|
-
|
|
368
|
+
No, not from a normal build. With `desktop: true` a production-mode `vite build` or
|
|
369
|
+
`electron-vite build` is stubbed like a web bundle: no SDK, no `ws://localhost` dial. Only a
|
|
370
|
+
build you run in another mode (`vite build --mode development`) is instrumented, which is how
|
|
371
|
+
you drive a packaged renderer with no dev server. A `connect()` you wrote by hand is yours to
|
|
372
|
+
gate on `import.meta.env.DEV`.
|
|
369
373
|
</Accordion>
|
|
370
374
|
<Accordion title="Why does a Tauri response show status 500 with statusText OK?">
|
|
371
375
|
The IPC transport really did answer HTTP 200. The 500 is Reticle translating the Rust command's
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Environment variables
|
|
3
|
+
description: Every environment variable Reticle reads, what it changes, and which process reads it.
|
|
4
|
+
icon: sliders
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Reticle works with none of these set. Each one changes a single behaviour, and most are read once, by the process named in the table: the daemon at startup, the CLI command you run, or a build plugin when your dev server starts. A daemon that is already running keeps the values it started with, so after changing a daemon setting run `npx @reticlehq/server restart`.
|
|
8
|
+
|
|
9
|
+
## Connection and ports
|
|
10
|
+
|
|
11
|
+
| Variable | Read by | What it does |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| `RETICLE_PORT` | daemon, CLI, build plugins | The bridge and daemon port. `.reticle.json`'s `port` sets it per project; this overrides it. |
|
|
14
|
+
| `RETICLE_HOST` | daemon | The bridge bind host. Loopback by default. Anything else exposes the bridge beyond this machine, so it is opt-in. |
|
|
15
|
+
| `RETICLE_TOKEN` | daemon | A shared secret the page must present when it connects. The pairing token covers this automatically; set it only for a hand-wired setup. |
|
|
16
|
+
| `RETICLE_PAIRING_TOKEN_DIR` | daemon, `init`, build plugins | Where the auto-provisioned pairing token lives. Defaults to `~/.reticle`. Relocate it for CI or a read-only home directory. |
|
|
17
|
+
| `RETICLE_ALLOWED_ORIGINS` | daemon | Comma-separated WebSocket origins the bridge accepts. |
|
|
18
|
+
| `RETICLE_STATE_DIR` | daemon, CLI | Daemon state: pid files, the discovery registry and logs. Defaults to `~/.reticle`. |
|
|
19
|
+
| `RETICLE_DAEMON_READY_TIMEOUT_MS` | MCP proxy | How long the MCP proxy waits for a daemon to come up before reporting it unreachable. |
|
|
20
|
+
| `RETICLE_DEV` | `@reticlehq/next` | Instrument even when `NODE_ENV` says production, for `NODE_ENV=production next dev`. |
|
|
21
|
+
|
|
22
|
+
## Daemon lifetime
|
|
23
|
+
|
|
24
|
+
| Variable | Read by | What it does |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| `RETICLE_IDLE_SHUTDOWN_MS` | daemon | How long the daemon waits with no agent, no page and no lease before it exits. `0` keeps it running. |
|
|
27
|
+
| `RETICLE_IDLE_ATTACHED_MS` | daemon | The same wait while an agent is attached, which is longer so a slow install or a thinking human is not cut off. Derived from the base when unset. |
|
|
28
|
+
| `RETICLE_MCP_PROXY_IDLE_MS` | MCP proxy | How long an abandoned MCP stdio proxy waits before it exits. `0` disables the watcher. |
|
|
29
|
+
| `RETICLE_JOURNAL` | daemon | Turns the causal journal off (`0`, `false`, `off`) or on. On by default. |
|
|
30
|
+
|
|
31
|
+
## Browser
|
|
32
|
+
|
|
33
|
+
| Variable | Read by | What it does |
|
|
34
|
+
| --- | --- | --- |
|
|
35
|
+
| `RETICLE_CDP_URL` | daemon | Attach to a browser that is already running, over CDP, instead of launching one. |
|
|
36
|
+
| `RETICLE_MAX_CONTEXTS` | daemon | The most leased headless browser contexts the pool runs at once. |
|
|
37
|
+
| `RETICLE_MAX_MESSAGES_PER_SECOND` | daemon | Events per second a page may send before the bridge starts sampling them. It never disconnects. Raise it for a legitimately busy app, such as a streaming dashboard. |
|
|
38
|
+
|
|
39
|
+
## Tools and output
|
|
40
|
+
|
|
41
|
+
| Variable | Read by | What it does |
|
|
42
|
+
| --- | --- | --- |
|
|
43
|
+
| `RETICLE_ADVERTISE_ALL_TOOLS` | daemon | Advertise every tool directly instead of the default surface. Everything is reachable either way, through `reticle_run`. |
|
|
44
|
+
| `RETICLE_VERIFY_SURFACE` | daemon | Advertise the smallest surface that can still produce a verdict. |
|
|
45
|
+
| `RETICLE_TOOL_PROFILE` | daemon | Retired. Any value it used to accept still resolves to a sensible surface, and the daemon says which one it used instead. |
|
|
46
|
+
| `RETICLE_ENCODING` | daemon | How tool results are written for the agent. Compact JSON by default; `pretty` indents it, and `toon` is a denser tabular form. The typed result is the same in every encoding. |
|
|
47
|
+
| `RETICLE_NO_UPSELL` | daemon | Silences every upgrade hint. |
|
|
48
|
+
|
|
49
|
+
## Gate and CI
|
|
50
|
+
|
|
51
|
+
| Variable | Read by | What it does |
|
|
52
|
+
| --- | --- | --- |
|
|
53
|
+
| `RETICLE_SKIP_GATE` | `reticle gate --hook` | Lets an agent's stop hook proceed past a failing gate. The skip is printed and recorded, never silent. It does not affect `reticle gate` without `--hook`, which is what CI runs. |
|
|
54
|
+
| `RETICLE_VERIFY_TOKEN` | `reticle serve --http` | The bearer token the optional HTTP verify endpoint requires. |
|
|
55
|
+
| `RETICLE_SECRET_<FIELD>` | replay, verify, crawl | The value typed into a password or secret field at replay. A recorded flow never stores it. See [what is recorded](/what-is-recorded). |
|
|
56
|
+
|
|
57
|
+
## Cloud and the autonomous drive
|
|
58
|
+
|
|
59
|
+
| Variable | Read by | What it does |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| `RETICLE_API_KEY` | CLI, daemon | The API key minted on the platform. |
|
|
62
|
+
| `RETICLE_CLOUD_KEY` | CLI, daemon | The key's earlier name. Still honoured. |
|
|
63
|
+
| `RETICLE_CLOUD_URL`, `RETICLE_URL` | CLI, daemon | The platform host. `RETICLE_CLOUD_URL` wins when both are set. |
|
|
64
|
+
| `RETICLE_SYNC_INTERVAL_MS` | `reticle sync --watch` | How often the watching sync runs. Every 60 seconds by default. |
|
|
65
|
+
| `ANTHROPIC_API_KEY` | autonomous drive | The key the drive's model uses when no coding agent is in the loop. Without it, the drive is unavailable and everything else is unaffected. |
|
|
66
|
+
| `RETICLE_HARNESS_MODEL` | autonomous drive | The model the drive uses. A small one by default. |
|
|
67
|
+
| `RETICLE_HARNESS_BASE_URL` | autonomous drive | A proxy or gateway in front of the model API. |
|
|
68
|
+
| `RETICLE_HARNESS_MAX_STEPS` | autonomous drive | A hard ceiling on model turns in one drive. It bounds cost. |
|
|
69
|
+
| `RETICLE_HARNESS_DRIVER` | autonomous drive | Which model drives: `anthropic` (the default) or `jev`. |
|
|
70
|
+
| `JEV_API_KEY`, `RETICLE_HARNESS_JEV_URL` | autonomous drive | A direct key and base URL for the `jev` driver. The usual path is `RETICLE_API_KEY` through the platform. |
|
|
71
|
+
| `OPENAI_API_KEY`, `RETICLE_HARNESS_OPENAI_MODEL` | autonomous drive | A direct key and model for the OpenAI driver. |
|
|
72
|
+
|
|
73
|
+
## Licensing
|
|
74
|
+
|
|
75
|
+
| Variable | Read by | What it does |
|
|
76
|
+
| --- | --- | --- |
|
|
77
|
+
| `RETICLE_LICENSE_KEY` | daemon | The Enterprise licence key. See [licence activation](/license-activation). |
|
|
78
|
+
|
|
79
|
+
## Telemetry and feedback
|
|
80
|
+
|
|
81
|
+
| Variable | Read by | What it does |
|
|
82
|
+
| --- | --- | --- |
|
|
83
|
+
| `RETICLE_TELEMETRY` | CLI, daemon | `0`, `false` or `off` turns anonymous usage telemetry off. `DO_NOT_TRACK` is honoured too. See [telemetry](/telemetry). |
|
|
84
|
+
| `RETICLE_TELEMETRY_FILE` | CLI, daemon | Write telemetry to a local JSONL file and send nothing, so you can read exactly what would be sent. |
|
|
85
|
+
| `RETICLE_TELEMETRY_URL`, `RETICLE_TELEMETRY_KEY` | CLI, daemon | Send telemetry to a different host or project, such as an EU region or your own instance. |
|
|
86
|
+
| `RETICLE_FEEDBACK` | daemon | Turns off the feedback channel only. Usage telemetry follows `RETICLE_TELEMETRY`. |
|
|
87
|
+
| `RETICLE_TRACE` | daemon, CLI | Verbose internal tracing for people working on Reticle itself. Off by default. |
|
package/docs/faq.mdx
CHANGED
|
@@ -23,22 +23,16 @@ You get considerably better results by adding `data-testid` attributes and by [e
|
|
|
23
23
|
</Accordion>
|
|
24
24
|
|
|
25
25
|
<Accordion title="Does it work without React?">
|
|
26
|
-
The core is framework-agnostic: DOM, network, routing, console, animations, snapshots and actions are gated against a vanilla TypeScript app.
|
|
26
|
+
Yes. The core is framework-agnostic: DOM, network, routing, console, animations, snapshots and actions are gated against a vanilla TypeScript app. What varies by framework is how `connect()` gets in and whether you get a source pointer on top.
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
| Framework | Status |
|
|
31
|
-
| --- | --- |
|
|
32
|
-
| React, Next.js, Remix, Astro | Supported, each with an app and a CI gate |
|
|
33
|
-
| SvelteKit | Wired end to end. `init` writes the client hook, the plugin stamps `.svelte` source. But **no CI gate**, so unverified rather than supported |
|
|
34
|
-
| Vue | A Pinia store adapter and nothing else. No detection, no `.vue` stamping, no gate |
|
|
28
|
+
[Frameworks](/frameworks) is the one list of what is proven for each, from "driven to a verdict in CI" to "install gated" to "wired, unverified".
|
|
35
29
|
|
|
36
30
|
</Accordion>
|
|
37
31
|
|
|
38
32
|
<Accordion title="Can it tell me whether my UI looks good?">
|
|
39
|
-
|
|
33
|
+
Reticle verifies behaviour, not aesthetics. Visual correctness and "does this feel right" remain a human job, or a visual-diff tool's, and Reticle pairs well with one.
|
|
40
34
|
|
|
41
|
-
It does read design tokens. [`
|
|
35
|
+
It does read design tokens. [`reticle_look { action: "element" }`](/tools/inspect) reports whether a colour came from your theme or from someone's clipboard. But that is a consistency check, not taste.
|
|
42
36
|
|
|
43
37
|
</Accordion>
|
|
44
38
|
|
|
@@ -58,7 +52,7 @@ Measured on the same app: Reticle caught 10 of 10 injected bugs, Playwright MCP
|
|
|
58
52
|
</Accordion>
|
|
59
53
|
|
|
60
54
|
<Accordion title="Can I run several apps or tabs at once?">
|
|
61
|
-
Yes. Each is a session. Pass `sessionId` to any tool when more than one is connected, and [`
|
|
55
|
+
Yes. Each is a session. Pass `sessionId` to any tool when more than one is connected, and [`reticle_session { action: "list" }`](/tools/sessions) lists them.
|
|
62
56
|
|
|
63
57
|
Reticle scopes to your project and prefers the active tab, and it **refuses rather than guesses** when the choice is ambiguous. A refusal you can act on beats a silent pick of the wrong tab.
|
|
64
58
|
|
|
@@ -74,9 +68,9 @@ If you believe an `unknown` is wrong, report it. Reticle's own response says as
|
|
|
74
68
|
</Accordion>
|
|
75
69
|
|
|
76
70
|
<Accordion title="Does my data leave the machine?">
|
|
77
|
-
Your app's data, no. Reticle is dev-only
|
|
71
|
+
Your app's data, no. Reticle is dev-only and localhost-only, and nothing from the app under test (DOM, network bodies, console, state, source) is sent. Credential-shaped values are redacted before they leave the page. You will see `[REDACTED]` in request bodies without configuring anything.
|
|
78
72
|
|
|
79
|
-
Anonymous usage
|
|
73
|
+
Anonymous usage counts are sent by default, separately, and carry nothing from your app. `reticle telemetry disable`, `RETICLE_TELEMETRY=0` or `DO_NOT_TRACK=1` turns them off.
|
|
80
74
|
|
|
81
75
|
<Card title="Exactly what is collected" icon="chart-line" href="/telemetry">
|
|
82
76
|
The complete list. If it is not on that page, it is not sent.
|
|
@@ -85,7 +79,7 @@ Anonymous usage telemetry is sent separately and can be turned off with `reticle
|
|
|
85
79
|
|
|
86
80
|
<Accordion title="Does it work with WebGL / react-three-fiber?">
|
|
87
81
|
Partially. Reticle's model of an app is DOM + store + network. A WebGL or react-three-fiber
|
|
88
|
-
subtree is a single `<canvas>` to `
|
|
82
|
+
subtree is a single `<canvas>` to `reticle_look { action: "find" }` / `reticle_look { action: "page" }`: Reticle cannot pick faces
|
|
89
83
|
or drive the camera inside the scene.
|
|
90
84
|
|
|
91
85
|
DOM, registered store state, and network **around** the canvas still work, and that is often where the consequential bugs live (import counts, mesh stats, solver results that contradict the UI). `init` prints this limit when it detects react-three-fiber so an adopting team does not discover it only after trying to verify the feature they care about.
|
|
@@ -93,9 +87,9 @@ DOM, registered store state, and network **around** the canvas still work, and t
|
|
|
93
87
|
</Accordion>
|
|
94
88
|
|
|
95
89
|
<Accordion title="Is Reticle proven to make agents fix more bugs?">
|
|
96
|
-
No
|
|
90
|
+
No. A fix-loop test on a small fixture found the same fix rate with and without Reticle, at two model tiers, and the Reticle arm made more tool calls. The fixture was small enough to read whole and the pass check looked for a string rather than behaviour, so the question is open. [Why Reticle](/why-reticle#what-the-fix-rate-test-measured) has the details.
|
|
97
91
|
|
|
98
|
-
What is
|
|
92
|
+
What Reticle is built to improve is the verdict: in the 88-bug head-to-head against a Playwright script it reported one false green to the script's 29, and on a known-good control it raised no false alarms.
|
|
99
93
|
|
|
100
94
|
</Accordion>
|
|
101
95
|
|
|
@@ -108,4 +102,12 @@ What is measured is detection: 10 of 10 injected regressions caught, with zero f
|
|
|
108
102
|
Which tools are advertised directly, and why each earned its slot.
|
|
109
103
|
</Card>
|
|
110
104
|
</Accordion>
|
|
105
|
+
|
|
106
|
+
<Accordion title="Can I use it for security, accessibility, performance or SEO checks?">
|
|
107
|
+
Yes, for how your own running app behaves: access control by role, calls that must never fire, CSP violations, roles and focus, request counts and long tasks, titles, headings, links and redirects. It pairs with a vulnerability scanner, an accessibility audit tool such as axe and an SEO crawler, which cover what an in-app check does not.
|
|
108
|
+
|
|
109
|
+
<Card title="Use cases" icon="list-check" href="/use-cases">
|
|
110
|
+
What each one checks, with a call you can run.
|
|
111
|
+
</Card>
|
|
112
|
+
</Accordion>
|
|
111
113
|
</AccordionGroup>
|
package/docs/first-drive.md
CHANGED
|
@@ -46,18 +46,10 @@ If `~/.reticle/pairing-token` does not exist yet, run any `reticle` command once
|
|
|
46
46
|
|
|
47
47
|
This is the shortest path to seeing Reticle work, and it needs no MCP client at all.
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Ask for a verdict, naming the app's url. With no tab open on that origin, Reticle opens one in a browser it drives (Playwright's Chromium, or an installed Chrome or Edge when that is missing) and closes it afterwards; a tab you already have open is used instead:
|
|
50
50
|
|
|
51
51
|
```bash
|
|
52
|
-
node
|
|
53
|
-
.then(b=>b.newPage().then(p=>p.goto('http://localhost:4310/')
|
|
54
|
-
.then(()=>new Promise(r=>setTimeout(r,60000)))))" &
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Then ask for a verdict:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
node server/dist/command/cli.js verify "" --port 4400 \
|
|
52
|
+
node server/dist/command/cli.js verify http://localhost:4310/ --port 4400 \
|
|
61
53
|
--expect '{"kind":"text","contains":"Reticle"}'
|
|
62
54
|
```
|
|
63
55
|
|
|
@@ -72,7 +64,7 @@ That is the whole product in one line: a claim, checked against a running page,
|
|
|
72
64
|
Try making it fail, because a tool that only ever says yes is not telling you anything:
|
|
73
65
|
|
|
74
66
|
```bash
|
|
75
|
-
node server/dist/command/cli.js verify
|
|
67
|
+
node server/dist/command/cli.js verify http://localhost:4310/ --port 4400 \
|
|
76
68
|
--expect '{"kind":"text","contains":"definitely not on this page"}'
|
|
77
69
|
```
|
|
78
70
|
|
|
@@ -80,8 +72,8 @@ node server/dist/command/cli.js verify "" --port 4400 \
|
|
|
80
72
|
|
|
81
73
|
If your editor has the Reticle MCP server, the same app is now drivable. The four calls worth knowing, in the order you actually use them:
|
|
82
74
|
|
|
83
|
-
- `
|
|
84
|
-
- `
|
|
75
|
+
- `reticle_look { action: "page" }`: what is on the page
|
|
76
|
+
- `reticle_look { action: "find", by: "testid", value: "..." }`: find one thing, cheaply
|
|
85
77
|
- `reticle_act_and_wait { ref, action, until }` (**the one that produces a verdict**)
|
|
86
78
|
- `reticle_observe`: everything the page did, when you need the evidence
|
|
87
79
|
|
package/docs/flows.md
CHANGED
|
@@ -87,6 +87,25 @@ reticle_flow {action:"load"}({ flowName: "create-task" }) // → the flow JSON
|
|
|
87
87
|
reticle_flow_replay({ flowName: "create-task" }) // re-resolve each anchor against the LIVE DOM, run it
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
+
### Resume from a step
|
|
91
|
+
|
|
92
|
+
```jsonc
|
|
93
|
+
reticle_flow_replay({ flowName: "create-task", from: 3 }) // by 0-based index
|
|
94
|
+
reticle_flow_replay({ flowName: "create-task", from: "submit" }) // or by a step's `id`
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
There is no state to restore, so the steps before `from` run again quickly as setup: their actions run, their `expect`s are not checked, and they are not reported. Replay is then checked and reported from `from` on. If a setup step fails, it is reported, because the resume never reached the step you asked for. A setup step declared `"effect": "commits"` refuses the resume and the whole flow replays, so resuming never re-sends a payment or a message silently. A `from` that names no step is an error, not a full replay.
|
|
98
|
+
|
|
99
|
+
## Flows saved from a drive
|
|
100
|
+
|
|
101
|
+
Every session's driving is saved as a flow at teardown when it declared a consequence. These flows:
|
|
102
|
+
|
|
103
|
+
- are named from the `intent` you pass to `reticle_act_and_wait` (`drive-close-an-issue`), and carry it as the flow's `intent`;
|
|
104
|
+
- merge: another drive that starts on the same page and takes the same steps updates the existing file instead of adding a copy. The existing flow keeps its name and everything it already says; the new drive only fills gaps. Flows you named yourself are never merged;
|
|
105
|
+
- record, on every step, the `page` it ran on and the `endPage` it led to;
|
|
106
|
+
- declare `requires` (the start page) and `ensures` (the end page) as route claims, so `canFollow` can tell which flows chain. Replay treats a required start page as met by navigating there;
|
|
107
|
+
- carry `author: { agent, person }`: the MCP client that drove it and the email of whoever ran `reticle login` on that machine. Either is left out when it is not known.
|
|
108
|
+
|
|
90
109
|
## Delete a flow
|
|
91
110
|
|
|
92
111
|
```jsonc
|
|
@@ -105,7 +124,7 @@ A renamed or obsolete flow otherwise lingers in `reticle_flow {action:"list"}` a
|
|
|
105
124
|
- `drift`: an anchor missed (a testid was renamed, or a signal never fired). The result is **legible**, never a blind failure: `{ step, anchor, drift: { reasonKind: "testid_not_found", nearest: "send-message" } }`. (This is the "whose fault is it" principle.)
|
|
106
125
|
- `error`: the flow file is missing/invalid, or a resolved action failed. Runtime failures include the failed step and a top-level error envelope.
|
|
107
126
|
|
|
108
|
-
A testid-_preserving_ refactor (you moved markup but kept the testids) still replays green. A step whose element has **no testid** is anchored on its component + source location (`{ kind: "component", component, source: { file, line } }`), an auto-derived stable anchor, so a flow records cleanly with zero hand-added testids and replay re-resolves it via `
|
|
127
|
+
A testid-_preserving_ refactor (you moved markup but kept the testids) still replays green. A step whose element has **no testid** is anchored on its component + source location (`{ kind: "component", component, source: { file, line } }`), an auto-derived stable anchor, so a flow records cleanly with zero hand-added testids and replay re-resolves it via `reticle_look { action: "find" } by:'component'`.
|
|
109
128
|
|
|
110
129
|
### The decision envelope: what to do next, not just pass/fail
|
|
111
130
|
|
|
@@ -175,7 +194,7 @@ With `apply: false` the flow file is **never modified**; you get the proposed di
|
|
|
175
194
|
| `reticle_flow {action:"list"}` | `{}` | flows on disk |
|
|
176
195
|
| `reticle_flow {action:"load"}` | `{ flowName }` | the flow JSON |
|
|
177
196
|
| `reticle_flow {action:"delete"}` | `{ flowName }` | `{ deleted: true }`, or `{ error, code }` (`not_found` when no such flow) |
|
|
178
|
-
| `reticle_flow_replay` | `{ flowName }` | `{ status, steps, decision? }` (decision on drift/fail) |
|
|
197
|
+
| `reticle_flow_replay` | `{ flowName, from?, sweep? }` | `{ status, steps, decision? }` (decision on drift/fail); `from` resumes at a step |
|
|
179
198
|
| `reticle_verify {action:"flows"}` | `{ names?, sessionId? }` | suite verdict `{ status, passed, failed, failures[] }` |
|
|
180
199
|
| `reticle_verify { action: "heal" }` | `{ flowName, apply? }` | propose / apply nearest-match rebind |
|
|
181
200
|
| `reticle_annotate` | `{ kind, … }` | compile a structured annotation into the flow |
|