@reticlehq/server 2.7.0 → 2.9.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.
Files changed (357) hide show
  1. package/README.md +14 -5
  2. package/SKILL.md +130 -778
  3. package/dist/bridge/bridge.d.ts +23 -0
  4. package/dist/bridge/bridge.js +80 -2
  5. package/dist/bridge/bridge.test-harness.d.ts +5 -0
  6. package/dist/bridge/bridge.test-harness.js +6 -4
  7. package/dist/capsule/causal-summary.d.ts +36 -1
  8. package/dist/capsule/causal-summary.js +33 -7
  9. package/dist/capsule/divergence.js +7 -1
  10. package/dist/cli/chromium-hint.d.ts +33 -5
  11. package/dist/cli/chromium-hint.js +82 -12
  12. package/dist/cli/cli-doctor.js +65 -34
  13. package/dist/cli/cli-flow-commands.js +8 -8
  14. package/dist/cli/cli-kill.d.ts +58 -0
  15. package/dist/cli/cli-kill.js +162 -0
  16. package/dist/cli/cli-parse.d.ts +16 -1
  17. package/dist/cli/cli-parse.js +32 -9
  18. package/dist/cli/cli-port.d.ts +32 -0
  19. package/dist/cli/cli-port.js +82 -35
  20. package/dist/cli/cli-verify.d.ts +21 -0
  21. package/dist/cli/cli-verify.js +47 -3
  22. package/dist/cli/config-discovery.d.ts +35 -0
  23. package/dist/cli/config-discovery.js +163 -0
  24. package/dist/cli/doctor-daemon-line.js +4 -1
  25. package/dist/cli/doctor-project-line.d.ts +37 -0
  26. package/dist/cli/doctor-project-line.js +35 -0
  27. package/dist/cli/doctor-rows.d.ts +51 -0
  28. package/dist/cli/doctor-rows.js +54 -0
  29. package/dist/cli/doctor-sessions-line.d.ts +12 -0
  30. package/dist/cli/doctor-sessions-line.js +69 -0
  31. package/dist/cli/drive-attach.d.ts +99 -0
  32. package/dist/cli/drive-attach.js +203 -0
  33. package/dist/cli/drive-command.d.ts +13 -0
  34. package/dist/cli/drive-command.js +103 -0
  35. package/dist/cli/open-note.d.ts +20 -0
  36. package/dist/cli/open-note.js +37 -0
  37. package/dist/cli/port-holder.d.ts +10 -0
  38. package/dist/cli/port-holder.js +26 -2
  39. package/dist/cli/status-next-action.d.ts +37 -0
  40. package/dist/cli/status-next-action.js +61 -0
  41. package/dist/cli.js +119 -39
  42. package/dist/crawl/crawl-tools.js +12 -2
  43. package/dist/crawl/crawl.d.ts +13 -0
  44. package/dist/crawl/crawl.js +50 -2
  45. package/dist/events/contradictions.d.ts +46 -0
  46. package/dist/events/contradictions.js +35 -22
  47. package/dist/events/declared.d.ts +45 -0
  48. package/dist/events/declared.js +73 -0
  49. package/dist/events/echo-mismatch.d.ts +8 -2
  50. package/dist/events/echo-mismatch.js +33 -5
  51. package/dist/events/event-filters.d.ts +1 -1
  52. package/dist/events/event-filters.js +7 -4
  53. package/dist/events/predicate-eval.d.ts +17 -72
  54. package/dist/events/predicate-eval.js +117 -236
  55. package/dist/events/predicate-parse.js +31 -3
  56. package/dist/events/predicate-route.d.ts +32 -0
  57. package/dist/events/predicate-route.js +102 -0
  58. package/dist/events/predicate-schema.d.ts +99 -0
  59. package/dist/events/predicate-schema.js +309 -0
  60. package/dist/events/predicate.d.ts +8 -0
  61. package/dist/events/predicate.js +296 -22
  62. package/dist/flows/annotate-tools.js +3 -0
  63. package/dist/flows/annotate.js +18 -4
  64. package/dist/flows/coverage.d.ts +38 -5
  65. package/dist/flows/coverage.js +30 -4
  66. package/dist/flows/decision.d.ts +15 -0
  67. package/dist/flows/decision.js +1 -1
  68. package/dist/flows/flow-classify.js +1 -1
  69. package/dist/flows/flow-replay-run.js +8 -1
  70. package/dist/flows/flow-tools.js +21 -5
  71. package/dist/flows/heal-run.js +1 -1
  72. package/dist/flows/replay.js +3 -0
  73. package/dist/honesty/accepted-write.d.ts +3 -0
  74. package/dist/honesty/accepted-write.js +8 -3
  75. package/dist/honesty/already-true.js +15 -0
  76. package/dist/honesty/blind-spots.js +10 -2
  77. package/dist/honesty/honesty.d.ts +11 -0
  78. package/dist/honesty/honesty.js +1 -0
  79. package/dist/honesty/uncaptured-bodies.d.ts +4 -2
  80. package/dist/honesty/uncaptured-bodies.js +9 -2
  81. package/dist/honesty/unread-outcome.d.ts +8 -0
  82. package/dist/honesty/unread-outcome.js +36 -9
  83. package/dist/honesty/unsettled.d.ts +49 -0
  84. package/dist/honesty/unsettled.js +82 -0
  85. package/dist/honesty/verified.d.ts +36 -3
  86. package/dist/honesty/verified.js +54 -11
  87. package/dist/http-server.d.ts +19 -0
  88. package/dist/http-server.js +202 -4
  89. package/dist/impact/impact-recorder.d.ts +23 -0
  90. package/dist/impact/impact-recorder.js +76 -0
  91. package/dist/impact/impact-store.d.ts +47 -0
  92. package/dist/impact/impact-store.js +171 -0
  93. package/dist/index.d.ts +7 -0
  94. package/dist/index.js +47 -10
  95. package/dist/init/agent-rules.d.ts +36 -0
  96. package/dist/init/agent-rules.js +132 -22
  97. package/dist/init/astro-patch.d.ts +2 -1
  98. package/dist/init/astro-patch.js +38 -6
  99. package/dist/init/capabilities.d.ts +22 -0
  100. package/dist/init/capabilities.js +76 -0
  101. package/dist/init/confirm.d.ts +114 -0
  102. package/dist/init/confirm.js +165 -0
  103. package/dist/init/connect-steps.d.ts +2 -0
  104. package/dist/init/connect-steps.js +50 -0
  105. package/dist/init/cra.js +3 -2
  106. package/dist/init/csp-check.d.ts +38 -0
  107. package/dist/init/csp-check.js +92 -0
  108. package/dist/init/csp-doctor.d.ts +25 -0
  109. package/dist/init/csp-doctor.js +49 -0
  110. package/dist/init/cursor.js +6 -9
  111. package/dist/init/detect.d.ts +8 -0
  112. package/dist/init/detect.js +33 -3
  113. package/dist/init/mcp-clients.d.ts +1 -0
  114. package/dist/init/mcp-clients.js +51 -7
  115. package/dist/init/mcp.d.ts +15 -0
  116. package/dist/init/mcp.js +19 -0
  117. package/dist/init/non-js-project.js +29 -5
  118. package/dist/init/plan-framework.d.ts +10 -0
  119. package/dist/init/plan-framework.js +78 -16
  120. package/dist/init/plan.d.ts +47 -6
  121. package/dist/init/plan.js +228 -69
  122. package/dist/init/run.d.ts +24 -2
  123. package/dist/init/run.js +157 -45
  124. package/dist/init/slash-command.d.ts +1 -1
  125. package/dist/init/slash-command.js +54 -6
  126. package/dist/init/snippets.d.ts +45 -5
  127. package/dist/init/snippets.js +194 -42
  128. package/dist/init/vite-config.js +53 -5
  129. package/dist/input/network-mock-tools.d.ts +19 -0
  130. package/dist/input/network-mock-tools.js +37 -5
  131. package/dist/input/scroll-find.d.ts +6 -0
  132. package/dist/input/scroll-find.js +17 -2
  133. package/dist/input/scroll-tools.js +4 -0
  134. package/dist/journal/attach-journal.d.ts +9 -1
  135. package/dist/journal/attach-journal.js +13 -2
  136. package/dist/journal/journal-query.d.ts +13 -0
  137. package/dist/journal/journal-query.js +28 -3
  138. package/dist/journal/workspace-gitignore.d.ts +10 -0
  139. package/dist/journal/workspace-gitignore.js +59 -0
  140. package/dist/license/license.js +1 -1
  141. package/dist/mcp/mcp-proxy.d.ts +35 -30
  142. package/dist/mcp/mcp-proxy.js +306 -104
  143. package/dist/mcp/mcp.d.ts +10 -1
  144. package/dist/mcp/mcp.js +70 -34
  145. package/dist/mcp/proxy-handshake.d.ts +82 -1
  146. package/dist/mcp/proxy-handshake.js +109 -2
  147. package/dist/mcp/proxy-lifecycle.d.ts +11 -2
  148. package/dist/mcp/proxy-lifecycle.js +12 -3
  149. package/dist/mcp/proxy-log.d.ts +63 -0
  150. package/dist/mcp/proxy-log.js +132 -0
  151. package/dist/mcp/server-instructions.d.ts +17 -0
  152. package/dist/mcp/server-instructions.js +56 -0
  153. package/dist/mcp/shared-params.d.ts +27 -0
  154. package/dist/mcp/shared-params.js +36 -0
  155. package/dist/pool/browser-pool.d.ts +22 -2
  156. package/dist/pool/browser-pool.js +44 -4
  157. package/dist/project/learned-routes.d.ts +24 -0
  158. package/dist/project/learned-routes.js +63 -0
  159. package/dist/project/project-store.d.ts +6 -0
  160. package/dist/project/project-store.js +25 -1
  161. package/dist/project/reticle-dir.d.ts +2 -0
  162. package/dist/project/reticle-dir.js +1 -0
  163. package/dist/session/connection-memory.d.ts +59 -0
  164. package/dist/session/connection-memory.js +108 -0
  165. package/dist/session/dev-command.d.ts +26 -0
  166. package/dist/session/dev-command.js +89 -0
  167. package/dist/session/dev-server-probe.d.ts +68 -0
  168. package/dist/session/dev-server-probe.js +102 -7
  169. package/dist/session/last-act.d.ts +26 -0
  170. package/dist/session/last-act.js +35 -1
  171. package/dist/session/live-control-tools.js +42 -5
  172. package/dist/session/no-session-diagnosis.d.ts +67 -2
  173. package/dist/session/no-session-diagnosis.js +236 -27
  174. package/dist/session/no-session-next-action.d.ts +46 -0
  175. package/dist/session/no-session-next-action.js +85 -0
  176. package/dist/session/no-session-watch.d.ts +40 -1
  177. package/dist/session/no-session-watch.js +174 -8
  178. package/dist/session/pending-commands.d.ts +12 -0
  179. package/dist/session/pending-commands.js +13 -1
  180. package/dist/session/ref-provenance.d.ts +54 -0
  181. package/dist/session/ref-provenance.js +61 -0
  182. package/dist/session/session-lease.js +1 -1
  183. package/dist/session/session-manager.d.ts +4 -0
  184. package/dist/session/session-manager.js +35 -5
  185. package/dist/session/session.d.ts +10 -1
  186. package/dist/session/session.js +146 -5
  187. package/dist/telemetry/app-instrumented.d.ts +8 -0
  188. package/dist/telemetry/app-instrumented.js +10 -0
  189. package/dist/telemetry/automation-hint.d.ts +17 -0
  190. package/dist/telemetry/automation-hint.js +71 -0
  191. package/dist/telemetry/bug-found.d.ts +15 -17
  192. package/dist/telemetry/bug-found.js +52 -21
  193. package/dist/telemetry/cli-telemetry.js +7 -1
  194. package/dist/telemetry/daemon-telemetry.js +24 -0
  195. package/dist/telemetry/feedback.js +1 -1
  196. package/dist/telemetry/init-telemetry.js +9 -1
  197. package/dist/telemetry/install-source.d.ts +56 -0
  198. package/dist/telemetry/install-source.js +74 -0
  199. package/dist/telemetry/instrumentation-stall.d.ts +50 -0
  200. package/dist/telemetry/instrumentation-stall.js +90 -0
  201. package/dist/telemetry/run-telemetry.js +4 -1
  202. package/dist/telemetry/session-metrics.d.ts +8 -0
  203. package/dist/telemetry/session-metrics.js +15 -0
  204. package/dist/telemetry/telemetry.d.ts +7 -1
  205. package/dist/telemetry/telemetry.js +26 -2
  206. package/dist/telemetry/tool-refused.d.ts +19 -0
  207. package/dist/telemetry/tool-refused.js +55 -0
  208. package/dist/telemetry/verification-of.js +46 -7
  209. package/dist/temp-dir.d.ts +27 -0
  210. package/dist/temp-dir.js +46 -0
  211. package/dist/tools/act-tools.js +209 -28
  212. package/dist/tools/assert-grade.d.ts +1 -1
  213. package/dist/tools/assert-grade.js +27 -5
  214. package/dist/tools/assert-verdict.js +49 -7
  215. package/dist/tools/browser-tools.js +10 -0
  216. package/dist/tools/contract-tools.js +4 -0
  217. package/dist/tools/dynamic-tools.js +16 -7
  218. package/dist/tools/error-recovery.d.ts +10 -0
  219. package/dist/tools/error-recovery.js +73 -9
  220. package/dist/tools/feedback-invite.js +1 -1
  221. package/dist/tools/invoke-tool.js +159 -26
  222. package/dist/tools/lease-hint.d.ts +30 -8
  223. package/dist/tools/lease-hint.js +65 -14
  224. package/dist/tools/lease-tools.d.ts +40 -1
  225. package/dist/tools/lease-tools.js +181 -83
  226. package/dist/tools/navigate-result.js +1 -1
  227. package/dist/tools/observe-tools.js +10 -4
  228. package/dist/tools/observed-nothing.js +1 -1
  229. package/dist/tools/react-grace.d.ts +52 -0
  230. package/dist/tools/react-grace.js +90 -0
  231. package/dist/tools/read-tools.js +67 -5
  232. package/dist/tools/resolve-target.d.ts +33 -0
  233. package/dist/tools/resolve-target.js +53 -0
  234. package/dist/tools/settle-in-flight.d.ts +94 -0
  235. package/dist/tools/settle-in-flight.js +146 -0
  236. package/dist/tools/snapshot-delta.d.ts +10 -0
  237. package/dist/tools/snapshot-delta.js +194 -9
  238. package/dist/tools/tool-kit.d.ts +8 -0
  239. package/dist/tools/tool-surface.d.ts +60 -0
  240. package/dist/tools/tool-surface.js +86 -1
  241. package/dist/tools/tools.js +61 -8
  242. package/dist/tools/unadvertised-help.js +9 -6
  243. package/docs/README.md +55 -11
  244. package/docs/actions.mdx +120 -0
  245. package/docs/agent-cheatsheet.md +95 -29
  246. package/docs/architecture.md +52 -35
  247. package/docs/benchmarks.md +127 -75
  248. package/docs/best-practices.mdx +216 -0
  249. package/docs/capabilities.mdx +534 -0
  250. package/docs/cli/affected.mdx +53 -0
  251. package/docs/cli/capsules.mdx +70 -0
  252. package/docs/cli/cloud.mdx +153 -0
  253. package/docs/cli/doctor.mdx +109 -0
  254. package/docs/cli/drive.mdx +74 -0
  255. package/docs/cli/feedback.mdx +67 -0
  256. package/docs/cli/gate.mdx +64 -0
  257. package/docs/cli/help.mdx +94 -0
  258. package/docs/cli/hunt.mdx +73 -0
  259. package/docs/cli/identify.mdx +76 -0
  260. package/docs/cli/init.mdx +121 -0
  261. package/docs/cli/kill.mdx +91 -0
  262. package/docs/cli/license.mdx +48 -0
  263. package/docs/cli/mcp.mdx +61 -0
  264. package/docs/cli/open.mdx +74 -0
  265. package/docs/cli/restart.mdx +60 -0
  266. package/docs/cli/rollback.mdx +35 -0
  267. package/docs/cli/serve.mdx +69 -0
  268. package/docs/cli/status.mdx +88 -0
  269. package/docs/cli/stop.mdx +64 -0
  270. package/docs/cli/telemetry.mdx +57 -0
  271. package/docs/cli/update.mdx +52 -0
  272. package/docs/cli/verify.mdx +76 -0
  273. package/docs/cli/version.mdx +39 -0
  274. package/docs/cli/watch.mdx +62 -0
  275. package/docs/cli.mdx +241 -0
  276. package/docs/debugging.md +16 -10
  277. package/docs/deploy-checks.md +45 -12
  278. package/docs/desktop.mdx +384 -0
  279. package/docs/docs.json +364 -0
  280. package/docs/enterprise.md +22 -16
  281. package/docs/faq.mdx +102 -0
  282. package/docs/fixtures.md +13 -7
  283. package/docs/flows.md +29 -23
  284. package/docs/for-agents.md +71 -0
  285. package/docs/frameworks.mdx +238 -0
  286. package/docs/gate-plan.md +48 -42
  287. package/docs/gates.md +28 -22
  288. package/docs/getting-started.md +129 -77
  289. package/docs/human-control.md +24 -18
  290. package/docs/index.mdx +143 -0
  291. package/docs/install-agentic.mdx +224 -0
  292. package/docs/install-manual.mdx +196 -0
  293. package/docs/instrumentation.mdx +238 -0
  294. package/docs/integration-patterns.md +41 -35
  295. package/docs/local-registry.md +19 -13
  296. package/docs/multi-agent-testing.md +19 -13
  297. package/docs/packages/babel-plugin.mdx +79 -0
  298. package/docs/packages/browser.mdx +111 -0
  299. package/docs/packages/core.mdx +116 -0
  300. package/docs/packages/electron.mdx +85 -0
  301. package/docs/packages/eslint-plugin.mdx +86 -0
  302. package/docs/packages/next.mdx +89 -0
  303. package/docs/packages/react.mdx +91 -0
  304. package/docs/packages/server.mdx +98 -0
  305. package/docs/packages/tauri.mdx +63 -0
  306. package/docs/packages/test.mdx +119 -0
  307. package/docs/packages/vite-plugin.mdx +94 -0
  308. package/docs/packages.mdx +218 -0
  309. package/docs/platform-integration.md +35 -26
  310. package/docs/predicates.mdx +248 -0
  311. package/docs/quickstart.mdx +257 -0
  312. package/docs/recipes.mdx +282 -0
  313. package/docs/skill-file.mdx +107 -0
  314. package/docs/state-management.mdx +199 -0
  315. package/docs/style.css +14 -0
  316. package/docs/system-map.md +50 -33
  317. package/docs/telemetry-contract.md +106 -52
  318. package/docs/telemetry-events.mdx +475 -0
  319. package/docs/telemetry.md +63 -55
  320. package/docs/testing.md +44 -6
  321. package/docs/token-efficiency.md +37 -27
  322. package/docs/tools-act-and-wait.mdx +173 -0
  323. package/docs/tools-act-sequence.mdx +137 -0
  324. package/docs/tools-act.mdx +95 -0
  325. package/docs/tools-assert.mdx +129 -0
  326. package/docs/tools-console.mdx +63 -0
  327. package/docs/tools-inspect.mdx +88 -0
  328. package/docs/tools-navigate.mdx +99 -0
  329. package/docs/tools-network.mdx +119 -0
  330. package/docs/tools-observe.mdx +145 -0
  331. package/docs/tools-overview.mdx +160 -0
  332. package/docs/tools-query.mdx +126 -0
  333. package/docs/tools-session-and-feedback.mdx +112 -0
  334. package/docs/tools-sessions.mdx +94 -0
  335. package/docs/tools-snapshot.mdx +129 -0
  336. package/docs/tools-state.mdx +104 -0
  337. package/docs/tools-tools-and-run.mdx +156 -0
  338. package/docs/tools-wait-for.mdx +85 -0
  339. package/docs/troubleshooting.mdx +263 -0
  340. package/docs/usage.md +209 -165
  341. package/docs/vs-chrome-devtools-mcp.mdx +123 -0
  342. package/docs/vs-playwright-mcp.mdx +125 -0
  343. package/docs/vs-screenshots.mdx +137 -0
  344. package/docs/what-is-reticle.mdx +63 -0
  345. package/docs/why-reticle.mdx +109 -0
  346. package/package.json +5 -5
  347. package/docs/desktop-apps.md +0 -256
  348. package/docs/matrix/2.5.0/claude-code-machine.json +0 -19
  349. package/docs/matrix/2.5.0/codex-machine.json +0 -20
  350. package/docs/matrix/2.5.0/cursor-machine.json +0 -22
  351. package/docs/matrix/2.5.0/gemini-machine.json +0 -22
  352. package/docs/matrix/2.5.0/opencode-machine.json +0 -22
  353. package/docs/matrix/2.5.0/vscode-machine.json +0 -22
  354. package/docs/matrix/2.5.0/windsurf-machine.json +0 -22
  355. package/docs/matrix/MATRIX.md +0 -26
  356. package/docs/matrix/README.md +0 -59
  357. package/docs/mint.json +0 -61
@@ -0,0 +1,282 @@
1
+ ---
2
+ title: 'Recipes: copy, paste, verify'
3
+ sidebarTitle: Recipes
4
+ description: Worked examples for the situations you are actually in, with the real response each one returned.
5
+ icon: book-open
6
+ ---
7
+
8
+ Each recipe is a situation, the call that verifies it, and what came back. Every response on this page was captured from a running app on 2026-08-16. Refs like `e605` are session-specific: take your own from [`reticle_query`](/tools-query) before copying a call.
9
+
10
+ ## "Did the login actually work?"
11
+
12
+ One call, three conditions. The signal fired, exactly one request went out, and nothing was logged.
13
+
14
+ ```json
15
+ {
16
+ "ref": "e605",
17
+ "action": "click",
18
+ "until": {
19
+ "kind": "allOf",
20
+ "predicates": [
21
+ { "kind": "signal", "name": "auth:granted" },
22
+ { "kind": "net", "method": "POST", "urlContains": "/api/login", "count": 1 },
23
+ { "kind": "console", "level": "error", "absent": true }
24
+ ]
25
+ }
26
+ }
27
+ ```
28
+
29
+ ```json
30
+ {
31
+ "verified": "yes",
32
+ "because": "assertion held at signal grade over a clean capture with no channel disagreeing",
33
+ "verdict": {
34
+ "pass": true,
35
+ "evidence": [
36
+ { "name": "auth:granted", "data": { "email": "admin@reticle.dev" } },
37
+ { "matched": 1 },
38
+ { "absent": true }
39
+ ]
40
+ },
41
+ "summary": {
42
+ "stateDiffs": [{ "path": "auth", "from": null, "to": "{…}" }],
43
+ "storageKeysChanged": ["reticle.bench.authToken", "reticle.bench.sessionId"]
44
+ },
45
+ "honesty": { "grade": "signal", "coverage": { "pct": 100, "partial": false } }
46
+ }
47
+ ```
48
+
49
+ Each child predicate reports its own evidence, in order. `count: 1` is the part that catches double-submit, and it costs nothing to ask for.
50
+
51
+ ## "Did navigating actually change the view?"
52
+
53
+ ```json
54
+ { "ref": "e618", "action": "click", "until": { "kind": "signal", "name": "nav:changed" } }
55
+ ```
56
+
57
+ ```json
58
+ {
59
+ "verified": "yes",
60
+ "verdict": {
61
+ "pass": true,
62
+ "evidence": { "name": "nav:changed", "data": { "view": "deployments" } }
63
+ },
64
+ "summary": {
65
+ "statePathsChanged": ["app"],
66
+ "stateDiffs": [{ "path": "view", "from": "overview", "to": "deployments", "atMs": 49084 }],
67
+ "signals": ["nav:changed"]
68
+ },
69
+ "honesty": { "grade": "signal", "coverage": { "pct": 100, "partial": false } }
70
+ }
71
+ ```
72
+
73
+ The signal carries the destination in its payload, so one predicate proves both that navigation happened and that it went to the right place.
74
+
75
+ ## "Did the modal open?" and the lesson in getting it wrong
76
+
77
+ Here is a real failure, kept because it teaches more than another pass.
78
+
79
+ ```json
80
+ {
81
+ "ref": "e623",
82
+ "action": "click",
83
+ "args": { "confirmDangerous": true },
84
+ "until": {
85
+ "kind": "allOf",
86
+ "predicates": [
87
+ { "kind": "element", "query": { "role": "dialog" }, "state": "visible" },
88
+ { "kind": "console", "level": "error", "absent": true }
89
+ ]
90
+ }
91
+ }
92
+ ```
93
+
94
+ ```json
95
+ {
96
+ "verified": "no",
97
+ "verdict": {
98
+ "pass": false,
99
+ "evidence": [
100
+ {
101
+ "pass": false,
102
+ "expected": "an element matching {\"role\":\"dialog\"} in state 'visible'",
103
+ "observed": "no matching element on the page",
104
+ "assertion": "element.present",
105
+ "evidence": {
106
+ "presentTestids": ["deploy-table", "filter-search", "env-filter", "sign-out", "…"]
107
+ }
108
+ },
109
+ { "pass": true, "evidence": { "absent": true } }
110
+ ]
111
+ },
112
+ "summary": {
113
+ "stateDiffs": [{ "path": "newDeployOpen", "from": false, "to": true, "atMs": 60862 }],
114
+ "signals": ["modal:opened"]
115
+ },
116
+ "capsule": { "blastRadius": ["state app", "signal modal:opened"], "firstDivergence": null }
117
+ }
118
+ ```
119
+
120
+ Read the `summary`. The modal **did** open. `newDeployOpen` went `false` to `true` and the app fired `modal:opened`. `capsule.blastRadius` says the same thing as a list: the click moved the `app` store and fired `modal:opened`, and nothing else.
121
+
122
+ The assertion was wrong, not the app. That modal is a `div` with no `role="dialog"`, so a role query could never match it. (Which is also an accessibility bug worth fixing, found for free.)
123
+
124
+ The right predicate was sitting in the response the whole time:
125
+
126
+ ```json
127
+ { "until": { "kind": "signal", "name": "modal:opened" } }
128
+ ```
129
+
130
+ <Tip>
131
+ When an assertion fails, read `summary.signals` and `summary.stateDiffs` before you assume the
132
+ feature is broken. They tell you what actually happened, and usually hand you the predicate you
133
+ should have written.
134
+ </Tip>
135
+
136
+ ## "Nothing matched, and I do not know why"
137
+
138
+ An empty `reticle_query` result tells you what _is_ there:
139
+
140
+ ```json
141
+ {
142
+ "count": 0,
143
+ "elements": [],
144
+ "hint": {
145
+ "route": "/hostile",
146
+ "knownEmptyState": true,
147
+ "presentTestids": ["nav-overview", "nav-deployments", "hostile-view", "hostile-ticker", "…"],
148
+ "presentRegions": [{ "role": "list", "childCount": 0, "name": "hostile-feed", "sample": [] }]
149
+ },
150
+ "cost": { "bytes": 402, "tokens": 101 }
151
+ }
152
+ ```
153
+
154
+ The testid existed, on another route. `hint.route` says where you actually are and `presentTestids` says what is here instead, for 101 tokens and no snapshot. `presentRegions` is the other half: a list with `childCount: 0` is an empty state, which is a different bug from a list that failed to render at all.
155
+
156
+ ## "Is this button destructive?"
157
+
158
+ Reticle refuses controls that look destructive, before acting:
159
+
160
+ ```json
161
+ {
162
+ "error": "potentially destructive action blocked; retry with args.confirmDangerous=true",
163
+ "recovery": "Reticle blocked a potentially destructive control (delete, remove, revoke…) on purpose. If you mean it, retry the same action with args.confirmDangerous set to true. This is a deliberate refusal, not a defect: there is nothing to report."
164
+ }
165
+ ```
166
+
167
+ Confirm it explicitly when you mean it:
168
+
169
+ ```json
170
+ { "ref": "e623", "action": "click", "args": { "confirmDangerous": true }, "until": { … } }
171
+ ```
172
+
173
+ <Note>
174
+ The matcher is conservative and will occasionally stop something harmless. A button labelled "New
175
+ deploy" trips it. That is the trade: a false stop costs you one argument, and a false start costs
176
+ you a deleted record.
177
+ </Note>
178
+
179
+ ## "Did my change break anything else?"
180
+
181
+ ```json
182
+ { "tool": "reticle_verify_change", "args": { "since": "HEAD~1" } }
183
+ ```
184
+
185
+ Give it the files you edited, or a git ref. It works out which saved flows cover them and replays only those.
186
+
187
+ ## "What is even testable in this app?"
188
+
189
+ The best first call on an unfamiliar codebase:
190
+
191
+ ```json
192
+ { "tool": "reticle_capabilities" }
193
+ ```
194
+
195
+ ```json
196
+ {
197
+ "testids": ["login-email", "login-submit", "new-deploy", "deploy-submit", "…"],
198
+ "signals": ["auth:granted", "auth:denied", "deploy:created", "modal:opened", "…"],
199
+ "stores": ["app"],
200
+ "flows": [
201
+ {
202
+ "name": "ship-a-deploy",
203
+ "steps": ["nav-deployments", "new-deploy", "deploy-name", "deploy-submit"]
204
+ }
205
+ ],
206
+ "source": "live"
207
+ }
208
+ ```
209
+
210
+ That is the app stating what it considers testable, which beats snapshotting the DOM and inferring it from element names.
211
+
212
+ ## "The error state has never been tested"
213
+
214
+ Most error states have never run. Force one:
215
+
216
+ ```json
217
+ {
218
+ "tool": "reticle_network_mock",
219
+ "args": { "mocks": [{ "urlContains": "/api/deploys", "status": 500 }] }
220
+ }
221
+ ```
222
+
223
+ Then drive the flow and assert the error UI appears. Pass `clear: true` to turn mocking off.
224
+
225
+ <Warning>
226
+ This one needs a **Reticle-driven browser**, because mocks are applied through CDP and the always-on
227
+ SDK cannot do that. A pooled lease is **not** enough. Re-verified on 2026-08-16: calling it against a
228
+ tab from `reticle_lease` returns
229
+
230
+ ```json
231
+ {
232
+ "applied": false,
233
+ "count": 0,
234
+ "ok": false,
235
+ "reason": "no-cdp-provider",
236
+ "recommendation": "this needs a Reticle-driven browser (it is applied through CDP, which the always-on SDK cannot do), start with `reticle drive <url>` or set RETICLE_CDP_URL"
237
+ }
238
+ ```
239
+
240
+ Under a driven browser the same call answers `{ "applied": true, "count": 1 }`. The same rule applies to `reticle_screenshot`, `reticle_visual_diff` and `reticle_viewport`, which report `no-visual-provider` instead.
241
+
242
+ </Warning>
243
+
244
+ ## "I want this to run on every PR"
245
+
246
+ Record it once, replay it forever:
247
+
248
+ ```json
249
+ { "tool": "reticle_flow_verify", "args": { "names": ["docs-check"] } }
250
+ ```
251
+
252
+ Omit `names` to replay every saved flow. Either way you get one consolidated verdict, and only the failures carry detail:
253
+
254
+ ```json
255
+ {
256
+ "status": "fail",
257
+ "total": 1,
258
+ "passed": 0,
259
+ "failed": 1,
260
+ "summary": "0/1 flows pass, 1 need attention: docs-check",
261
+ "failures": [
262
+ {
263
+ "flow": "docs-check",
264
+ "verdict": "drift",
265
+ "whatChanged": "testid \"login-submit\" not found",
266
+ "whereInSource": "src/components/Login.tsx:81",
267
+ "nextAction": "rebind the anchor to \"sign-out\" (closest survivor), or update the flow if the change was intended."
268
+ }
269
+ ]
270
+ }
271
+ ```
272
+
273
+ It also returns `flaky`, the flows it has seen both pass and fail on unchanged code. Treat that list as a bug in the flow, not in the app.
274
+
275
+ <CardGroup cols={2}>
276
+ <Card title="The predicate grammar" icon="filter" href="/predicates">
277
+ Every kind, every field, and which ones actually prove something.
278
+ </Card>
279
+ <Card title="Best practices" icon="star" href="/best-practices">
280
+ The habits behind these recipes, and the mistakes that produce a confident wrong pass.
281
+ </Card>
282
+ </CardGroup>
@@ -0,0 +1,107 @@
1
+ ---
2
+ title: 'The SKILL file: paste and go'
3
+ sidebarTitle: SKILL file
4
+ description: One URL you paste into any coding agent to teach it Reticle. How it works, what it contains, and when you need it at all.
5
+ icon: graduation-cap
6
+ ---
7
+
8
+ Paste `https://raw.githubusercontent.com/reticlehq/reticle/main/SKILL.md` into any coding agent and say "read this and set up Reticle". The document installs Reticle, wires it into your app, and then drives a proper verification loop, choosing setup mode or test mode itself based on whether `.reticle.json` already exists. You often do not need it: `npx @reticlehq/server init` configures Claude Code and Cursor directly.
9
+
10
+ `SKILL.md` is a single document you hand to a coding agent. It teaches the agent to install Reticle, wire it into your app, and then drive a verification loop properly. Without you explaining any of it.
11
+
12
+ ```
13
+ https://raw.githubusercontent.com/reticlehq/reticle/main/SKILL.md
14
+ ```
15
+
16
+ That URL is live and returns the current version. Paste it into your agent and say "read this and set up Reticle".
17
+
18
+ <Note>
19
+ You often do not need it. `npx @reticlehq/server init` writes a `/reticle` slash command for
20
+ Claude Code automatically, and installs agent rule files for Claude and Cursor. The SKILL file is
21
+ for agents that `init` cannot configure, for a from-scratch install, or when you want the agent to
22
+ have the full protocol in context rather than a summary.
23
+ </Note>
24
+
25
+ ## It has two modes, and it picks one itself
26
+
27
+ The first thing the document tells an agent to do is check which situation it is in:
28
+
29
+ ```bash
30
+ cat .reticle.json 2>/dev/null || echo "NOT_FOUND"
31
+ ```
32
+
33
+ - **Not found** → run **Setup mode**: register the MCP server, install the SDK, wire the entry point, validate the connection, and prove it on one flow while the user watches.
34
+ - **Found** → run **Test mode**: connect, orient, decide what to test, drive it, report.
35
+
36
+ One document, two jobs, no flag for you to remember. The second time you invoke it, it skips straight to the useful part.
37
+
38
+ ## What Setup mode actually does
39
+
40
+ | Phase | What the agent does |
41
+ | --- | --- |
42
+ | Save the skill | Store it as `/reticle` so the loop is one word away from then on |
43
+ | Run `init` | Without asking you questions it can answer itself |
44
+ | Manual fallbacks | Per-agent MCP config, per-framework SDK wiring, for anything `init` marked `⚠` |
45
+ | Validate | Confirm a session actually connected. Not that a checklist went green |
46
+ | Prove it | Drive one real flow while you watch, so the install ends in evidence |
47
+
48
+ That last row is the one that matters. Plenty of installs "succeed" and then nothing works. The skill does not consider itself finished until a real flow has produced a real verdict.
49
+
50
+ ## What Test mode actually does
51
+
52
+ Five phases: connect, orient, decide what to test, run the tests, report. The reporting format is specified, which matters more than it sounds. An agent left to summarise freely will summarise optimistically.
53
+
54
+ The rules it operates under are the same ones these docs keep repeating:
55
+
56
+ - Only `reticle_act_and_wait` and `reticle_assert` produce a verdict.
57
+ - `verified: "unknown"` is not a pass.
58
+ - Never weaken a check to make it pass.
59
+
60
+ ## Feedback is the first section, on purpose
61
+
62
+ Before setup, before anything, the document tells the agent that reporting problems is part of the job. And that this applies **during** setup, which is where Reticle is most likely to break and least likely to hear about it.
63
+
64
+ It even covers the case where nothing is installed yet:
65
+
66
+ ```bash
67
+ npx @reticlehq/server feedback --agent --kind gap "init finished but no session ever connected"
68
+ ```
69
+
70
+ That works with no daemon running, which is the entire point. The install that failed halfway is the one worth hearing about, and in that state the MCP tools do not exist.
71
+
72
+ <Tip>
73
+ It also draws a line that saves everyone time: report defects in **Reticle**. A bug found in the
74
+ app under test is Reticle working correctly, and belongs in the answer to the user.
75
+ </Tip>
76
+
77
+ ## It ships inside the package too
78
+
79
+ `SKILL.md` is bundled into `@reticlehq/server` at publish time, alongside a copy of this entire documentation site. So an agent that has already installed Reticle can read it from disk without a network round trip:
80
+
81
+ ```
82
+ node_modules/@reticlehq/server/SKILL.md
83
+ node_modules/@reticlehq/server/docs/
84
+ ```
85
+
86
+ Handy in a sandbox with no outbound network, which is an increasingly common place for an agent to live.
87
+
88
+ ## Should you read it?
89
+
90
+ Probably not, unless you are curious. It is roughly 60 KB and written for an agent, which means it is exhaustive in the way a runbook is exhaustive. Every fallback, every framework, every failure mode spelled out rather than summarised.
91
+
92
+ If you want the human version of the same material, you are already in it:
93
+
94
+ <CardGroup cols={2}>
95
+ <Card title="Agentic install" icon="wand-magic-sparkles" href="/install-agentic">
96
+ What `reticle init` does, with real output.
97
+ </Card>
98
+ <Card title="Manual install" icon="screwdriver-wrench" href="/install-manual">
99
+ Every step `init` cannot automate.
100
+ </Card>
101
+ <Card title="Agent cheat sheet" icon="bolt" href="/agent-cheatsheet">
102
+ The one-screen version of the drive loop.
103
+ </Card>
104
+ <Card title="Best practices" icon="star" href="/best-practices">
105
+ The habits that make verdicts worth trusting.
106
+ </Card>
107
+ </CardGroup>
@@ -0,0 +1,199 @@
1
+ ---
2
+ title: State management
3
+ description: Register any store so Reticle can read what your app believes. Zustand and Redux work natively, and eight more have adapters.
4
+ icon: database
5
+ ---
6
+
7
+ **Reticle reads any store that has `getState()` and `subscribe()`, which covers Zustand and Redux with no adapter at all. TanStack Query, Pinia, Svelte stores, Jotai, Valtio, MobX, XState and Recoil each have a one-line adapter, and `pushStore` covers anything else.** Register one with `registerStore('app', myStore)` in your dev-only `src/reticle-dev.ts`.
8
+
9
+ Reading application state is what separates a verdict from a screenshot. A `200` proves the server was reachable. A rendered row proves React ran. Only state proves your app accepted the change.
10
+
11
+ Reticle needs one thing from your store: a way to read it, and a way to know when it changed.
12
+
13
+ ## The contract
14
+
15
+ ```ts
16
+ interface StoreLike {
17
+ getState(): unknown;
18
+ subscribe(listener: () => void): () => void;
19
+ }
20
+ ```
21
+
22
+ Anything with that shape registers directly, with no adapter.
23
+
24
+ ```ts
25
+ import { registerStore } from '@reticlehq/browser';
26
+
27
+ registerStore('app', myStore);
28
+ ```
29
+
30
+ <Warning>
31
+ Pass the **store**, not `() => store.getState()`. The store form wires `subscribe`, so every mutation
32
+ emits a state diff. The getter form still works for compatibility but leaves the store on pull-only
33
+ reads: no change events, and an empty `stateDiffs` in every verdict.
34
+
35
+ That reads as "nothing changed" and actually means "I was never watching". It is the most common instrumentation mistake there is.
36
+
37
+ </Warning>
38
+
39
+ ## Works natively
40
+
41
+ <CardGroup cols={2}>
42
+ <Card title="Zustand" icon="bolt">
43
+ A zustand hook already has `getState` and `subscribe`. Pass it straight in.
44
+ </Card>
45
+ <Card title="Redux" icon="boxes-stacked">
46
+ A Redux store is `StoreLike` by definition. Same one-liner.
47
+ </Card>
48
+ </CardGroup>
49
+
50
+ ```ts
51
+ registerStore('app', useApp); // zustand
52
+ registerStore('app', store); // redux
53
+ ```
54
+
55
+ This is what the Reticle fixture app does, and it is why its verdicts carry `stateDiffs: [{ "path": "auth", "from": null, "to": "…" }]`.
56
+
57
+ ## Adapters
58
+
59
+ Eight libraries do not fit `StoreLike` for a reason specific to each. Every adapter returns a `StoreLike` you hand straight to `registerStore`.
60
+
61
+ Each example below is the one documented in the adapter's own source.
62
+
63
+ ### TanStack Query
64
+
65
+ ```ts
66
+ import { tanstackQueryStore } from '@reticlehq/browser';
67
+
68
+ registerStore('queries', tanstackQueryStore(queryClient));
69
+ ```
70
+
71
+ <Tip>
72
+ Register your server cache even if you already register a client store. "The screen is plausible
73
+ and the network is silent" is the normal failure with query caches: a mutation forgets to
74
+ invalidate, the UI keeps rendering a number that was true a minute ago, and nothing fires for
75
+ anyone to notice. The cache's freshness metadata is the only witness.
76
+ </Tip>
77
+
78
+ ### Pinia
79
+
80
+ ```ts
81
+ import { piniaStore } from '@reticlehq/browser';
82
+
83
+ registerStore('cart', piniaStore(useCartStore()));
84
+ ```
85
+
86
+ ### Svelte stores
87
+
88
+ ```ts
89
+ import { svelteStore } from '@reticlehq/browser';
90
+
91
+ registerStore('cart', svelteStore(cartStore));
92
+ ```
93
+
94
+ ### Jotai
95
+
96
+ Atoms are not a store, so you name the ones you care about.
97
+
98
+ ```ts
99
+ import { jotaiStore } from '@reticlehq/browser';
100
+ import { getDefaultStore } from 'jotai';
101
+
102
+ registerStore('app', jotaiStore(getDefaultStore(), { cart: cartAtom, user: userAtom }));
103
+ ```
104
+
105
+ ### Valtio
106
+
107
+ ```ts
108
+ import { valtioStore } from '@reticlehq/browser';
109
+ import { snapshot, subscribe } from 'valtio/vanilla';
110
+
111
+ registerStore('app', valtioStore(state, snapshot, subscribe));
112
+ ```
113
+
114
+ ### MobX
115
+
116
+ ```ts
117
+ import { mobxStore } from '@reticlehq/browser';
118
+ import { reaction, toJS } from 'mobx';
119
+
120
+ registerStore('app', mobxStore(store, toJS, reaction));
121
+ ```
122
+
123
+ You pass `toJS` and `reaction` in rather than Reticle importing MobX. The SDK stays free of your state library, and your bundle stays free of a copy it did not ask for.
124
+
125
+ ### XState
126
+
127
+ ```ts
128
+ import { xstateStore } from '@reticlehq/browser';
129
+
130
+ registerStore('machine', xstateStore(actor));
131
+ ```
132
+
133
+ An XState actor's `subscribe` returns a subscription object rather than an unsubscribe function, which is the single reason it does not satisfy `StoreLike` already.
134
+
135
+ ### Recoil
136
+
137
+ The most involved, because Recoil has no store object to hand over.
138
+
139
+ ```ts
140
+ import { recoilStore } from '@reticlehq/browser';
141
+
142
+ const latest = useRef(snapshot_UNSTABLE());
143
+ const listeners = useRef(new Set<() => void>()).current;
144
+
145
+ useRecoilTransactionObserver_UNSTABLE(({ snapshot }) => {
146
+ latest.current = snapshot;
147
+ for (const l of listeners) l();
148
+ });
149
+
150
+ registerStore(
151
+ 'recoil',
152
+ recoilStore(
153
+ { cart: cartAtom },
154
+ () => latest.current,
155
+ (l) => {
156
+ listeners.add(l);
157
+ return () => listeners.delete(l);
158
+ },
159
+ ),
160
+ );
161
+ ```
162
+
163
+ ### Anything else
164
+
165
+ `pushStore` gives you a store plus the `push` that updates it, so you own the write side. Useful for state that lives somewhere Reticle cannot reach: a web worker, a websocket, a third-party SDK.
166
+
167
+ ```ts
168
+ import { pushStore } from '@reticlehq/browser';
169
+
170
+ const { store, push } = pushStore({ status: 'idle' });
171
+ registerStore('worker', store);
172
+
173
+ worker.onmessage = (e) => push(e.data);
174
+ ```
175
+
176
+ ## Reading it back
177
+
178
+ ```json
179
+ { "store": "app", "path": "cart.items.0.qty" }
180
+ ```
181
+
182
+ `reticle_state` walks a dot-path with numeric array indices. `depth` collapses anything deeper to a size marker, which is the difference between a cheap look and a very expensive one on a large store.
183
+
184
+ You can also assert on it directly, which is stronger than reading it afterwards:
185
+
186
+ ```json
187
+ { "kind": "state", "store": "app", "path": "deployments.0.status", "equals": "live" }
188
+ ```
189
+
190
+ That catches a UI-versus-store desync, a deploy that only looks shipped, deterministically and with no model involved.
191
+
192
+ <CardGroup cols={2}>
193
+ <Card title="reticle_state" icon="database" href="/tools-state">
194
+ Arguments, depth control, and reading a component's hook state.
195
+ </Card>
196
+ <Card title="Instrument your app" icon="wrench" href="/instrumentation">
197
+ Stores are one of three things worth registering. The other two are signals and testids.
198
+ </Card>
199
+ </CardGroup>
package/docs/style.css ADDED
@@ -0,0 +1,14 @@
1
+ /* Any .css file at the docs root is auto-loaded by Mintlify; docs.json has no field for it.
2
+ Tagline under the footer logo: the footer schema is {socials, links} and takes no text. */
3
+ #footer a.select-none::after {
4
+ content: 'Your agent says it works. Reticle checks.';
5
+ display: block;
6
+ margin-top: 0.75rem;
7
+ font-size: 0.875rem;
8
+ line-height: 1.25rem;
9
+ color: rgb(var(--gray-500));
10
+ }
11
+
12
+ .dark #footer a.select-none::after {
13
+ color: rgb(var(--gray-400));
14
+ }