@reticlehq/server 3.2.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.
Files changed (437) hide show
  1. package/LICENSE-ENTERPRISE +1 -1
  2. package/README.md +3 -3
  3. package/SKILL.md +23 -22
  4. package/dist/chromium-launch-options.d.ts +4 -3
  5. package/dist/chromium-launch-options.js +6 -2
  6. package/dist/command/cli/adhoc-suite.d.ts +41 -0
  7. package/dist/command/cli/adhoc-suite.js +159 -0
  8. package/dist/command/cli/adhoc-verdict.d.ts +58 -2
  9. package/dist/command/cli/adhoc-verdict.js +108 -13
  10. package/dist/command/cli/answers/gate-hook-message.d.ts +6 -0
  11. package/dist/command/cli/answers/gate-hook-message.js +6 -0
  12. package/dist/command/cli/auth/cloud-keystore.d.ts +0 -2
  13. package/dist/command/cli/auth/cloud-keystore.js +0 -3
  14. package/dist/command/cli/auth/cloud-session.d.ts +4 -0
  15. package/dist/command/cli/auth/cloud-session.js +2 -0
  16. package/dist/command/cli/cli-doctor.js +30 -8
  17. package/dist/command/cli/cli-flow-commands.d.ts +3 -6
  18. package/dist/command/cli/cli-flow-commands.js +67 -4
  19. package/dist/command/cli/cli-parse-grammar.d.ts +7 -0
  20. package/dist/command/cli/cli-parse-grammar.js +7 -0
  21. package/dist/command/cli/cli-parse-verify.d.ts +2 -5
  22. package/dist/command/cli/cli-parse-verify.js +86 -13
  23. package/dist/command/cli/cli-parse.d.ts +14 -1
  24. package/dist/command/cli/cli-parse.js +54 -8
  25. package/dist/command/cli/cli-update-commands.js +8 -1
  26. package/dist/command/cli/cli-verify.d.ts +80 -0
  27. package/dist/command/cli/cli-verify.js +181 -26
  28. package/dist/command/cli/cloud-cli.js +5 -2
  29. package/dist/command/cli/cloud-kit.d.ts +0 -2
  30. package/dist/command/cli/cloud-kit.js +3 -5
  31. package/dist/command/cli/cloud-login.js +21 -3
  32. package/dist/command/cli/demo/demo-page.js +6 -3
  33. package/dist/command/cli/doctor/browser/chromium-hint.d.ts +5 -0
  34. package/dist/command/cli/doctor/browser/chromium-hint.js +5 -0
  35. package/dist/command/cli/doctor/doctor-sessions-line.d.ts +2 -1
  36. package/dist/command/cli/launch/cli-launch.d.ts +9 -29
  37. package/dist/command/cli/launch/cli-launch.js +27 -49
  38. package/dist/command/cli/launch/sdk-version-match.d.ts +84 -0
  39. package/dist/command/cli/launch/sdk-version-match.js +206 -0
  40. package/dist/command/cli/lifecycle/daemon-lifecycle.js +2 -16
  41. package/dist/command/cli/ports/resolve/cli-port.d.ts +38 -0
  42. package/dist/command/cli/ports/resolve/cli-port.js +169 -15
  43. package/dist/command/cli/report-command.d.ts +16 -0
  44. package/dist/command/cli/report-command.js +97 -0
  45. package/dist/command/cli/setup-mcp-cli.js +13 -13
  46. package/dist/command/cli/tutorial.d.ts +2 -2
  47. package/dist/command/cli/tutorial.js +21 -7
  48. package/dist/command/cli.js +67 -10
  49. package/dist/command/daemon/binding/daemon-status-probe.d.ts +44 -2
  50. package/dist/command/daemon/binding/daemon-status-probe.js +79 -6
  51. package/dist/command/daemon/binding/port-presence.d.ts +1 -1
  52. package/dist/command/daemon/daemon-resolve.d.ts +9 -0
  53. package/dist/command/daemon/daemon-resolve.js +1 -1
  54. package/dist/command/daemon/idle-shutdown.d.ts +2 -1
  55. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +7 -1
  56. package/dist/command/daemon/lifetime/daemon-usefulness.js +30 -7
  57. package/dist/command/dev/stale-issue-guard.d.ts +3 -4
  58. package/dist/command/dev/stale-issue-guard.js +8 -8
  59. package/dist/command/setup/bringup/connect-lease.d.ts +17 -0
  60. package/dist/command/setup/bringup/connect-lease.js +38 -0
  61. package/dist/command/setup/bringup/dev-server-files.d.ts +68 -0
  62. package/dist/command/setup/bringup/dev-server-files.js +131 -0
  63. package/dist/command/setup/bringup/dev-server-log-cap.d.ts +35 -0
  64. package/dist/command/setup/bringup/dev-server-log-cap.js +121 -0
  65. package/dist/command/setup/bringup/ensure-daemon.d.ts +65 -4
  66. package/dist/command/setup/bringup/ensure-daemon.js +135 -16
  67. package/dist/command/setup/bringup/static-page-server.d.ts +35 -0
  68. package/dist/command/setup/bringup/static-page-server.js +151 -0
  69. package/dist/command/setup/desktop-shape.d.ts +4 -0
  70. package/dist/command/setup/desktop-shape.js +18 -2
  71. package/dist/command/setup/init/init-host.js +8 -0
  72. package/dist/command/setup/init/init-port.d.ts +15 -0
  73. package/dist/command/setup/init/init-port.js +44 -0
  74. package/dist/command/setup/init/init-runtime.d.ts +1 -1
  75. package/dist/command/setup/init/init-runtime.js +39 -2
  76. package/dist/command/setup/node-effects.d.ts +27 -14
  77. package/dist/command/setup/node-effects.js +80 -44
  78. package/dist/command/setup/probe/loopback-probe-urls.d.ts +7 -0
  79. package/dist/command/setup/probe/loopback-probe-urls.js +40 -0
  80. package/dist/command/setup/probe/page-probe.d.ts +13 -2
  81. package/dist/command/setup/probe/page-probe.js +18 -3
  82. package/dist/command/setup/run-setup.d.ts +26 -1
  83. package/dist/command/setup/run-setup.js +96 -13
  84. package/dist/command/setup/session-pick.d.ts +13 -0
  85. package/dist/command/setup/session-pick.js +20 -0
  86. package/dist/command/setup/setup-command.d.ts +2 -14
  87. package/dist/command/setup/setup-command.js +105 -31
  88. package/dist/command/setup/setup-mcp.js +3 -3
  89. package/dist/command/setup/terminal/wait-progress.d.ts +8 -0
  90. package/dist/command/setup/terminal/wait-progress.js +17 -0
  91. package/dist/features/crawl/crawl-empty.js +1 -1
  92. package/dist/features/crawl/crawl-tools.d.ts +6 -0
  93. package/dist/features/crawl/crawl-tools.js +57 -0
  94. package/dist/features/crawl/crawl.d.ts +2 -0
  95. package/dist/features/crawl/crawl.js +171 -156
  96. package/dist/features/exhaust/app-coverage.d.ts +33 -0
  97. package/dist/features/exhaust/app-coverage.js +31 -0
  98. package/dist/features/exhaust/code-coverage.d.ts +47 -0
  99. package/dist/features/exhaust/code-coverage.js +77 -0
  100. package/dist/features/exhaust/exhaust-run.d.ts +33 -0
  101. package/dist/features/exhaust/exhaust-run.js +82 -0
  102. package/dist/features/exhaust/explorer.d.ts +103 -0
  103. package/dist/features/exhaust/explorer.js +195 -0
  104. package/dist/features/exhaust/failure-branches.d.ts +33 -0
  105. package/dist/features/exhaust/failure-branches.js +92 -0
  106. package/dist/features/exhaust/ledger.d.ts +202 -0
  107. package/dist/features/exhaust/ledger.js +252 -0
  108. package/dist/features/exhaust/session-fold.d.ts +31 -0
  109. package/dist/features/exhaust/session-fold.js +79 -0
  110. package/dist/features/exhaust/session-port.d.ts +36 -0
  111. package/dist/features/exhaust/session-port.js +102 -0
  112. package/dist/features/harness/drive-report.d.ts +0 -9
  113. package/dist/features/harness/drive-report.js +18 -0
  114. package/dist/features/harness/driver.js +4 -7
  115. package/dist/features/harness/fill-values.d.ts +6 -0
  116. package/dist/features/harness/fill-values.js +3 -0
  117. package/dist/features/harness/jev-driver.js +36 -22
  118. package/dist/features/harness/openai-driver.js +4 -7
  119. package/dist/features/harness/platform-config.d.ts +10 -0
  120. package/dist/features/harness/platform-config.js +13 -6
  121. package/dist/index.d.ts +10 -1
  122. package/dist/index.js +78 -104
  123. package/dist/judgement/capsule/capsule-store.d.ts +31 -2
  124. package/dist/judgement/capsule/capsule-store.js +58 -6
  125. package/dist/judgement/capsule/capsule.js +5 -0
  126. package/dist/judgement/capsule/causal-summary.d.ts +13 -1
  127. package/dist/judgement/capsule/causal-summary.js +7 -0
  128. package/dist/judgement/domain/domain-model.js +40 -9
  129. package/dist/judgement/oracles/self-instrument.js +4 -2
  130. package/dist/judgement/outcome/assertion-integrity.d.ts +3 -3
  131. package/dist/judgement/runs/artifact/gap-report.d.ts +17 -0
  132. package/dist/judgement/runs/artifact/gap-report.js +46 -0
  133. package/dist/judgement/runs/artifact/gap-summary.d.ts +58 -0
  134. package/dist/judgement/runs/artifact/gap-summary.js +85 -0
  135. package/dist/judgement/runs/artifact/render-report.js +4 -1
  136. package/dist/judgement/runs/artifact/replay-mapping.d.ts +2 -2
  137. package/dist/judgement/runs/artifact/replay-mapping.js +44 -9
  138. package/dist/judgement/runs/artifact/to-artifact.d.ts +7 -2
  139. package/dist/judgement/runs/artifact/to-artifact.js +1 -1
  140. package/dist/judgement/runs/context-tools.js +21 -3
  141. package/dist/judgement/runs/drive-run.js +7 -2
  142. package/dist/judgement/runs/verification-sync.d.ts +3 -1
  143. package/dist/judgement/runs/verification-sync.js +1 -1
  144. package/dist/language/flows/annotate-notes/annotate.d.ts +0 -15
  145. package/dist/language/flows/annotate-notes/annotate.js +66 -18
  146. package/dist/language/flows/change/affected.d.ts +9 -0
  147. package/dist/language/flows/change/affected.js +35 -0
  148. package/dist/language/flows/change/gate.d.ts +20 -0
  149. package/dist/language/flows/change/gate.js +12 -1
  150. package/dist/language/flows/flow-anchor.d.ts +12 -0
  151. package/dist/language/flows/flow-anchor.js +20 -0
  152. package/dist/language/flows/flow-author.d.ts +7 -0
  153. package/dist/language/flows/flow-author.js +19 -0
  154. package/dist/language/flows/flow-expect-grammar.d.ts +2 -2
  155. package/dist/language/flows/flow-expect-grammar.js +92 -11
  156. package/dist/language/flows/flow-intent.js +1 -1
  157. package/dist/language/flows/flow-journey.d.ts +54 -0
  158. package/dist/language/flows/flow-journey.js +119 -0
  159. package/dist/language/flows/flow-learning.d.ts +3 -0
  160. package/dist/language/flows/flow-learning.js +39 -8
  161. package/dist/language/flows/flow-replay-run.d.ts +33 -12
  162. package/dist/language/flows/flow-replay-run.js +131 -52
  163. package/dist/language/flows/flow-replay-types.d.ts +9 -0
  164. package/dist/language/flows/flow-replay.d.ts +27 -12
  165. package/dist/language/flows/flow-replay.js +127 -111
  166. package/dist/language/flows/flow-result.d.ts +2 -0
  167. package/dist/language/flows/flow-result.js +25 -0
  168. package/dist/language/flows/flow-step-runners.d.ts +26 -10
  169. package/dist/language/flows/flow-step-runners.js +20 -4
  170. package/dist/language/flows/flow-success.d.ts +21 -6
  171. package/dist/language/flows/flow-success.js +50 -138
  172. package/dist/language/flows/flow-tools.js +17 -5
  173. package/dist/language/flows/flows.d.ts +18 -5
  174. package/dist/language/flows/flows.js +101 -16
  175. package/dist/language/flows/heal.d.ts +9 -1
  176. package/dist/language/flows/heal.js +24 -2
  177. package/dist/language/flows/learned-sources.d.ts +21 -0
  178. package/dist/language/flows/learned-sources.js +84 -0
  179. package/dist/language/flows/recording/recording-backtrack.d.ts +0 -7
  180. package/dist/language/flows/recording/recording-backtrack.js +1 -1
  181. package/dist/language/flows/recording/replay-halt.d.ts +2 -1
  182. package/dist/language/flows/recording/replay-halt.js +3 -1
  183. package/dist/language/flows/recording/tape/recordings.d.ts +31 -2
  184. package/dist/language/flows/recording/tape/recordings.js +55 -1
  185. package/dist/language/flows/replay.d.ts +19 -0
  186. package/dist/language/flows/replay.js +53 -13
  187. package/dist/language/flows/stores/annotation-store.d.ts +5 -5
  188. package/dist/language/flows/stores/assertion-tiers-store.js +2 -3
  189. package/dist/language/flows/stores/flake-store.js +2 -3
  190. package/dist/language/flows/suite/coverage.d.ts +1 -1
  191. package/dist/language/flows/suite/parallel-suite.d.ts +2 -1
  192. package/dist/language/flows/verify-change-tools.js +19 -2
  193. package/dist/launch-chromium.d.ts +80 -0
  194. package/dist/launch-chromium.js +218 -0
  195. package/dist/memory/cloud/cloud-config.d.ts +11 -2
  196. package/dist/memory/cloud/cloud-config.js +47 -7
  197. package/dist/memory/cloud/cloud-sync.d.ts +4 -3
  198. package/dist/memory/cloud/cloud-sync.js +7 -10
  199. package/dist/memory/cloud/harness-config.d.ts +2 -0
  200. package/dist/memory/cloud/harness-offer.js +5 -6
  201. package/dist/memory/cloud/harness-switch.js +5 -6
  202. package/dist/memory/cloud/sync-cycle.d.ts +78 -1
  203. package/dist/memory/cloud/sync-cycle.js +321 -53
  204. package/dist/memory/cloud/sync-daemon.d.ts +13 -0
  205. package/dist/memory/cloud/sync-daemon.js +45 -20
  206. package/dist/memory/cloud/sync-disk.js +27 -8
  207. package/dist/memory/impact/impact-store.js +6 -0
  208. package/dist/memory/intent/inline-intent.js +8 -3
  209. package/dist/memory/intent/intent-shard-store.d.ts +33 -47
  210. package/dist/memory/intent/intent-shard-store.js +252 -140
  211. package/dist/memory/intent/intent-shard.d.ts +0 -23
  212. package/dist/memory/intent/intent-shard.js +1 -11
  213. package/dist/memory/intent/intent-store.d.ts +13 -8
  214. package/dist/memory/intent/intent-store.js +46 -90
  215. package/dist/memory/intent/intent-tools.js +34 -23
  216. package/dist/memory/journal/ambient-store.js +2 -3
  217. package/dist/memory/journal/deviation-report.js +4 -1
  218. package/dist/memory/journal/deviation-service.js +10 -2
  219. package/dist/memory/journal/drive-flow.d.ts +19 -14
  220. package/dist/memory/journal/drive-flow.js +65 -48
  221. package/dist/memory/journal/envelope-store.js +2 -3
  222. package/dist/memory/journal/journal-recorder.d.ts +21 -0
  223. package/dist/memory/journal/on-disk/retain-policy.d.ts +34 -0
  224. package/dist/memory/journal/on-disk/retain-policy.js +44 -0
  225. package/dist/memory/journal/on-disk/retention.d.ts +14 -10
  226. package/dist/memory/journal/on-disk/retention.js +13 -12
  227. package/dist/memory/journal/on-disk/startup-maintenance.d.ts +42 -0
  228. package/dist/memory/journal/on-disk/startup-maintenance.js +14 -0
  229. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +0 -11
  230. package/dist/memory/journal/on-disk/workspace-gitignore.js +6 -45
  231. package/dist/memory/journal/on-disk/workspace-tiers.d.ts +52 -0
  232. package/dist/memory/journal/on-disk/workspace-tiers.js +90 -0
  233. package/dist/memory/journal/route-template.d.ts +22 -0
  234. package/dist/memory/journal/route-template.js +44 -0
  235. package/dist/memory/journal/session-end.d.ts +13 -2
  236. package/dist/memory/journal/session-end.js +88 -18
  237. package/dist/memory/journal/session-journal.d.ts +8 -1
  238. package/dist/memory/journal/session-journal.js +10 -0
  239. package/dist/memory/project/baselines.d.ts +1 -1
  240. package/dist/memory/project/dir/reticle-dir.d.ts +3 -1
  241. package/dist/memory/project/dir/reticle-dir.js +1 -0
  242. package/dist/memory/project/fs/fs-port.js +44 -5
  243. package/dist/memory/project/fs/write-atomic.d.ts +26 -0
  244. package/dist/memory/project/fs/write-atomic.js +48 -0
  245. package/dist/memory/project/project-tools.js +3 -1
  246. package/dist/memory/recall/prior/connection-memory.d.ts +6 -0
  247. package/dist/memory/recall/prior/connection-memory.js +8 -0
  248. package/dist/memory/recall/registered-projects.d.ts +2 -1
  249. package/dist/portal/bridge/auth-failure-reason.d.ts +1 -1
  250. package/dist/portal/bridge/auth-failure-reason.js +9 -4
  251. package/dist/portal/bridge/bridge.d.ts +8 -0
  252. package/dist/portal/bridge/bridge.js +43 -2
  253. package/dist/portal/input/js-coverage.d.ts +25 -0
  254. package/dist/portal/input/js-coverage.js +30 -0
  255. package/dist/portal/input/real-input.d.ts +11 -0
  256. package/dist/portal/input/real-input.js +31 -5
  257. package/dist/portal/pool/browser-pool.d.ts +10 -0
  258. package/dist/portal/pool/browser-pool.js +10 -0
  259. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  260. package/dist/portal/pool/playwright-launcher.js +21 -13
  261. package/dist/portal/pool/pool-contract.d.ts +2 -0
  262. package/dist/portal/pool/storage-seed.d.ts +2 -1
  263. package/dist/portal/pool/zero-install.d.ts +27 -0
  264. package/dist/portal/pool/zero-install.js +54 -0
  265. package/dist/portal/realm/web-realm.js +6 -0
  266. package/dist/portal/session/dev-server/dev-command.d.ts +2 -2
  267. package/dist/portal/session/dev-server/dev-command.js +30 -12
  268. package/dist/portal/session/dev-server/dev-server-probe.d.ts +2 -1
  269. package/dist/portal/session/dev-server/dev-server-probe.js +17 -1
  270. package/dist/portal/session/dev-server/route-status-probe.d.ts +24 -0
  271. package/dist/portal/session/dev-server/route-status-probe.js +57 -0
  272. package/dist/portal/session/dev-server/served-document.d.ts +21 -0
  273. package/dist/portal/session/dev-server/served-document.js +57 -0
  274. package/dist/portal/session/facts/background-traffic.d.ts +9 -0
  275. package/dist/portal/session/facts/background-traffic.js +25 -0
  276. package/dist/portal/session/facts/observed-state.d.ts +11 -0
  277. package/dist/portal/session/facts/observed-state.js +34 -0
  278. package/dist/portal/session/live-control-tools.js +48 -3
  279. package/dist/portal/session/no-session-diagnosis.d.ts +29 -0
  280. package/dist/portal/session/no-session-diagnosis.js +62 -5
  281. package/dist/portal/session/no-session-next-action.d.ts +13 -0
  282. package/dist/portal/session/no-session-next-action.js +48 -9
  283. package/dist/portal/session/no-session-watch.d.ts +18 -0
  284. package/dist/portal/session/no-session-watch.js +88 -2
  285. package/dist/portal/session/presence/attachment-history.d.ts +13 -2
  286. package/dist/portal/session/session-health.d.ts +61 -0
  287. package/dist/portal/session/session-health.js +43 -3
  288. package/dist/portal/session/session-info.d.ts +6 -0
  289. package/dist/portal/session/session-manager.d.ts +29 -6
  290. package/dist/portal/session/session-manager.js +42 -5
  291. package/dist/portal/session/session-reaper.d.ts +28 -0
  292. package/dist/portal/session/session-reaper.js +49 -1
  293. package/dist/portal/session/session-successor.d.ts +11 -0
  294. package/dist/portal/session/session-successor.js +14 -1
  295. package/dist/portal/session/session-verdict-facts.d.ts +28 -0
  296. package/dist/portal/session/session-verdict-facts.js +15 -0
  297. package/dist/portal/session/session.d.ts +10 -0
  298. package/dist/portal/session/session.js +34 -26
  299. package/dist/surface/http-server.d.ts +2 -1
  300. package/dist/surface/http-server.js +4 -2
  301. package/dist/surface/mcp/mcp-proxy.d.ts +2 -2
  302. package/dist/surface/mcp/mcp-proxy.js +5 -5
  303. package/dist/surface/mcp/mcp.js +4 -2
  304. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +13 -1
  305. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +27 -2
  306. package/dist/surface/mcp/proxy-idle-exit.d.ts +2 -1
  307. package/dist/surface/mcp/server-instructions.js +21 -8
  308. package/dist/surface/tools/act/after-match.d.ts +17 -0
  309. package/dist/surface/tools/act/after-match.js +30 -0
  310. package/dist/surface/tools/act/already-true.d.ts +40 -0
  311. package/dist/surface/tools/act/already-true.js +36 -0
  312. package/dist/surface/tools/act/durable.d.ts +69 -0
  313. package/dist/surface/tools/act/durable.js +139 -0
  314. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +19 -6
  315. package/dist/surface/tools/act/navigation/navigate-arrival.js +60 -10
  316. package/dist/surface/tools/act/navigation/navigate-result.d.ts +1 -12
  317. package/dist/surface/tools/act/navigation/navigate-result.js +21 -3
  318. package/dist/surface/tools/act/proved-controls.d.ts +9 -0
  319. package/dist/surface/tools/act/proved-controls.js +11 -0
  320. package/dist/surface/tools/act/sequence-grade.d.ts +5 -0
  321. package/dist/surface/tools/act/sequence-grade.js +32 -1
  322. package/dist/surface/tools/act/settle-in-flight.d.ts +6 -2
  323. package/dist/surface/tools/act/settle-in-flight.js +29 -6
  324. package/dist/surface/tools/act-capsule.d.ts +7 -0
  325. package/dist/surface/tools/act-capsule.js +68 -8
  326. package/dist/surface/tools/act-sequence-tool.js +25 -8
  327. package/dist/surface/tools/act-tools.js +51 -74
  328. package/dist/surface/tools/args/numeric-bounds.d.ts +15 -2
  329. package/dist/surface/tools/args/numeric-bounds.js +30 -3
  330. package/dist/surface/tools/assert/assert-grade.js +26 -3
  331. package/dist/surface/tools/assert/assert-verdict.js +32 -6
  332. package/dist/surface/tools/browser-tools.js +17 -4
  333. package/dist/surface/tools/coverage-tools.js +27 -1
  334. package/dist/surface/tools/dynamic-tools.js +6 -0
  335. package/dist/surface/tools/error-recovery.js +4 -4
  336. package/dist/surface/tools/feedback-invite.js +6 -4
  337. package/dist/surface/tools/feedback-tools.d.ts +2 -1
  338. package/dist/surface/tools/feedback-tools.js +1 -1
  339. package/dist/surface/tools/harness-explore.d.ts +3 -2
  340. package/dist/surface/tools/harness-explore.js +7 -6
  341. package/dist/surface/tools/invoke-tool.js +17 -4
  342. package/dist/surface/tools/lease-hint.d.ts +8 -0
  343. package/dist/surface/tools/lease-hint.js +10 -0
  344. package/dist/surface/tools/lease-tools.d.ts +16 -28
  345. package/dist/surface/tools/lease-tools.js +68 -11
  346. package/dist/surface/tools/lineage-tools.js +1 -1
  347. package/dist/surface/tools/live-call-text.js +4 -1
  348. package/dist/surface/tools/observe-tools.js +23 -7
  349. package/dist/surface/tools/real-input-attempt.d.ts +0 -5
  350. package/dist/surface/tools/real-input-attempt.js +1 -1
  351. package/dist/surface/tools/tool-kit.d.ts +5 -0
  352. package/dist/surface/tools/tool-kit.js +6 -1
  353. package/dist/surface/tools/tool-surface.js +17 -5
  354. package/dist/surface/tools/tools.js +68 -29
  355. package/dist/telemetry/argument-shape.d.ts +0 -2
  356. package/dist/telemetry/argument-shape.js +0 -4
  357. package/dist/telemetry/error-class.d.ts +2 -3
  358. package/dist/telemetry/error-class.js +2 -3
  359. package/dist/telemetry/feedback-local.d.ts +1 -0
  360. package/dist/telemetry/feedback-local.js +1 -3
  361. package/dist/telemetry/feedback.d.ts +1 -1
  362. package/dist/telemetry/harness-drive.d.ts +0 -2
  363. package/dist/telemetry/harness-drive.js +0 -4
  364. package/dist/telemetry/hud-metrics.d.ts +32 -0
  365. package/dist/telemetry/hud-metrics.js +95 -0
  366. package/dist/telemetry/session-metrics.d.ts +5 -0
  367. package/dist/telemetry/session-metrics.js +15 -1
  368. package/dist/wire-journal.d.ts +34 -0
  369. package/dist/wire-journal.js +104 -0
  370. package/dist/workspace-packages.d.ts +0 -2
  371. package/dist/workspace-packages.js +1 -9
  372. package/docs/README.md +5 -2
  373. package/docs/actions.mdx +3 -3
  374. package/docs/agent-cheatsheet.md +4 -4
  375. package/docs/architecture.md +6 -6
  376. package/docs/best-practices.mdx +1 -1
  377. package/docs/capabilities.mdx +32 -1
  378. package/docs/cli/cloud.mdx +21 -9
  379. package/docs/cli/doctor.mdx +4 -0
  380. package/docs/cli/feedback.mdx +2 -2
  381. package/docs/cli/gate.mdx +9 -4
  382. package/docs/cli/init.mdx +1 -0
  383. package/docs/cli/report.mdx +44 -0
  384. package/docs/cli/update.mdx +10 -0
  385. package/docs/cli.mdx +9 -0
  386. package/docs/desktop.mdx +14 -10
  387. package/docs/environment.mdx +87 -0
  388. package/docs/faq.mdx +18 -16
  389. package/docs/first-drive.md +5 -13
  390. package/docs/flows.md +32 -2
  391. package/docs/frameworks.mdx +140 -9
  392. package/docs/getting-started.md +3 -3
  393. package/docs/http-transport.md +6 -3
  394. package/docs/human-control.md +2 -2
  395. package/docs/index.mdx +16 -6
  396. package/docs/install-agentic.mdx +37 -1
  397. package/docs/install-manual.mdx +1 -1
  398. package/docs/integration-patterns.md +3 -3
  399. package/docs/multi-agent-testing.md +1 -1
  400. package/docs/packages/babel-plugin.mdx +1 -1
  401. package/docs/packages/browser.mdx +2 -2
  402. package/docs/packages/react.mdx +2 -2
  403. package/docs/packages/tauri.mdx +1 -1
  404. package/docs/packages/vite-plugin.mdx +2 -2
  405. package/docs/packages.mdx +9 -9
  406. package/docs/predicates.mdx +176 -7
  407. package/docs/quickstart.mdx +2 -2
  408. package/docs/recipes.mdx +2 -2
  409. package/docs/state-management.mdx +2 -2
  410. package/docs/system-map.md +1 -1
  411. package/docs/telemetry.md +1 -1
  412. package/docs/token-efficiency.md +3 -3
  413. package/docs/tools/act-and-wait.mdx +1 -0
  414. package/docs/tools/act-sequence.mdx +1 -1
  415. package/docs/tools/console.mdx +1 -1
  416. package/docs/tools/inspect.mdx +1 -1
  417. package/docs/tools/network.mdx +1 -1
  418. package/docs/tools/query.mdx +11 -11
  419. package/docs/tools/sessions.mdx +1 -1
  420. package/docs/tools/snapshot.mdx +1 -1
  421. package/docs/tools/state.mdx +1 -1
  422. package/docs/tools/wait-for.mdx +1 -1
  423. package/docs/usage.md +8 -7
  424. package/docs/use-cases.mdx +157 -0
  425. package/docs/vs-screenshots.mdx +3 -3
  426. package/docs/what-is-recorded.md +62 -0
  427. package/docs/what-is-reticle.mdx +17 -20
  428. package/docs/why-reticle.mdx +14 -21
  429. package/package.json +11 -10
  430. package/dist/judgement/capsule/minimize.d.ts +0 -12
  431. package/dist/judgement/capsule/minimize.js +0 -22
  432. package/dist/judgement/outcome/predicate-to-expect.d.ts +0 -44
  433. package/dist/judgement/outcome/predicate-to-expect.js +0 -148
  434. package/dist/judgement/phenomena/phenomena.d.ts +0 -26
  435. package/dist/judgement/phenomena/phenomena.js +0 -101
  436. package/dist/language/flows/flow-report.d.ts +0 -22
  437. package/dist/language/flows/flow-report.js +0 -106
@@ -20,6 +20,7 @@ import { errorSkeleton, fingerprintError } from './error-fingerprint.js';
20
20
  import { describeToolParams } from './argument-shape.js';
21
21
  import { machineSnapshot } from './machine-snapshot.js';
22
22
  import { classifyError } from './error-class.js';
23
+ import { HudMetrics } from './hud-metrics.js';
23
24
  /** Cap the distinct error shapes held in memory — a pathological loop must not grow unbounded. */
24
25
  const MAX_ERROR_KINDS = 40;
25
26
  /** Distinct tool names whose repeat-runs are tracked. Its own cap: the tool surface, not error shapes. */
@@ -165,10 +166,16 @@ export class SessionMetrics {
165
166
  #surface;
166
167
  #startedAt;
167
168
  #now;
169
+ #hud;
168
170
  /** Clock injected — this file must stay testable without a real one, per the repo's clock rule. */
169
171
  constructor(now) {
170
172
  this.#now = now;
171
173
  this.#startedAt = now();
174
+ this.#hud = new HudMetrics(now);
175
+ }
176
+ /** A person used the HUD. Names only; the wire schema has already narrowed it. */
177
+ recordHudUse(use) {
178
+ this.#hud.record(use);
172
179
  }
173
180
  /**
174
181
  * Record a call starting. Returns a function to call when it finishes — that closure is what makes
@@ -555,6 +562,7 @@ export class SessionMetrics {
555
562
  ...(this.#firstAppAt === undefined
556
563
  ? {}
557
564
  : { msToFirstApp: Math.max(0, this.#firstAppAt - this.#startedAt) }),
565
+ ...this.#hud.summarize(),
558
566
  final,
559
567
  // Only on a real exit. A periodic flush carrying `exit: "unknown"` would read as a daemon that
560
568
  // died without a shutdown path, which is the one thing this field exists to make visible.
@@ -613,7 +621,8 @@ export class SessionMetrics {
613
621
  0 === this.#bugsFound &&
614
622
  0 === this.#sdkFailures &&
615
623
  0 === this.#postSocketFailures &&
616
- 0 === this.#postRetriesSaved);
624
+ 0 === this.#postRetriesSaved &&
625
+ this.#hud.empty);
617
626
  }
618
627
  /** Zero the counters after a non-final flush so the next flush reports the NEXT window, not a total. */
619
628
  reset() {
@@ -641,6 +650,7 @@ export class SessionMetrics {
641
650
  this.#unknownToolCalls = 0;
642
651
  this.#bugsFound = 0;
643
652
  this.#bugKinds.clear();
653
+ this.#hud.reset();
644
654
  // #seenBugKinds is deliberately NOT cleared. It is not a window counter — it is the
645
655
  // session-lifetime memory behind `repeat` on bug_found, and zeroing it made the same defect,
646
656
  // found again after a flush, report as a newly distinct one. Sessions run to 11.5 hours in the
@@ -665,6 +675,10 @@ export const recordBrowserLatency = (ms) => {
665
675
  export const recordSdkFailure = (failure) => {
666
676
  getSessionMetrics().recordSdkFailure(failure.site, failure.message);
667
677
  };
678
+ /** Narrow-and-record one HUD use. Keeps the session hot path to a single call. */
679
+ export const recordHudUse = (use) => {
680
+ getSessionMetrics().recordHudUse(use);
681
+ };
668
682
  /** Tests only — drop the singleton so each case starts from zero. */
669
683
  export const resetSessionMetrics = () => {
670
684
  current = undefined;
@@ -0,0 +1,34 @@
1
+ import { Bridge } from './portal/bridge/bridge.js';
2
+ import { FlowStore } from './language/flows/flows.js';
3
+ import type { FlowFile } from '@reticlehq/core';
4
+ import type { FileSystemPort } from './memory/project/fs/fs-port.js';
5
+ import type { TapeStep } from './memory/journal/drive-flow.js';
6
+ import type { OnboardingStep } from '@reticlehq/core/telemetry';
7
+ import { type PruneWorkspaceOptions } from './memory/journal/on-disk/startup-maintenance.js';
8
+ /**
9
+ * Wire journal capture, ambient seeding and the journal-tail flush onto a bridge.
10
+ *
11
+ * Both entry points need all three, and both used to hand-roll them. `startDaemon` only ever wired the
12
+ * first, so on the path every user actually takes (`reticle serve` / `reticle mcp`) the journal tail was
13
+ * dropped at session end and the learned ambient map was never persisted OR seeded — meaning ambient
14
+ * learning could not converge across sessions and the last events of every session were lost. The two
15
+ * call sites had already drifted once before, which is why this is one function rather than a
16
+ * copy-paste both are asked to keep in step.
17
+ */
18
+ export declare function attachJournal(bridge: Bridge, deps: {
19
+ fs: FileSystemPort;
20
+ reticleRoot: string;
21
+ enabled: boolean;
22
+ takeAmbientTape?: () => {
23
+ steps: readonly TapeStep[];
24
+ startPath?: string;
25
+ } | undefined;
26
+ reportStep?: (step: OnboardingStep) => Promise<boolean>;
27
+ /** Tell cloud sync a run landed, so it cycles instead of waiting for its timer. */
28
+ onRunPersisted?: () => void;
29
+ flows?: FlowStore;
30
+ /** Who is driving, stamped on each flow teardown saves. */
31
+ author?: () => FlowFile['author'];
32
+ /** What this project is willing to keep — the `retain` block of its `.reticle.json`. */
33
+ retain?: PruneWorkspaceOptions;
34
+ }): void;
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Journal wiring for the composition root.
3
+ *
4
+ * A sibling of `index.ts` rather than a move into `memory/journal/`: this is COMPOSITION, not
5
+ * journalling. It reaches the bridge, the flow store, the telemetry funnel and the recording tape to
6
+ * join them together, and putting those reaches inside the journal domain would make that domain
7
+ * depend on four areas it has no business knowing. `index.ts` already holds every one of them, and
8
+ * the 1000-line backstop is what asked for the split.
9
+ */
10
+ import { artifactRootResolver } from './memory/project/artifact-root-resolver.js';
11
+ import { originOf } from './portal/session/session-manager.js';
12
+ import { Bridge } from './portal/bridge/bridge.js';
13
+ import { FlowStore } from './language/flows/flows.js';
14
+ import { makeJournalAttach } from './memory/journal/attach-journal.js';
15
+ import { makeSessionEnd, recordDriveRun } from './memory/journal/session-end.js';
16
+ import { attachDriveRunFlush } from './memory/journal/drive-run-flush.js';
17
+ import { AmbientStore } from './memory/journal/ambient-store.js';
18
+ import { ensureWorkspaceGitignore } from './memory/journal/on-disk/workspace-gitignore.js';
19
+ import { pruneWorkspace, } from './memory/journal/on-disk/startup-maintenance.js';
20
+ import { dirname } from 'node:path';
21
+ import { findProjectConfig } from './command/cli/ports/resolve/cli-port.js';
22
+ import { readBackgroundTraffic } from './portal/session/facts/background-traffic.js';
23
+ /**
24
+ * Wire journal capture, ambient seeding and the journal-tail flush onto a bridge.
25
+ *
26
+ * Both entry points need all three, and both used to hand-roll them. `startDaemon` only ever wired the
27
+ * first, so on the path every user actually takes (`reticle serve` / `reticle mcp`) the journal tail was
28
+ * dropped at session end and the learned ambient map was never persisted OR seeded — meaning ambient
29
+ * learning could not converge across sessions and the last events of every session were lost. The two
30
+ * call sites had already drifted once before, which is why this is one function rather than a
31
+ * copy-paste both are asked to keep in step.
32
+ */
33
+ export function attachJournal(bridge, deps) {
34
+ const journalAttach = makeJournalAttach(deps);
35
+ const ambientStore = new AmbientStore(deps.fs, deps.reticleRoot);
36
+ // Built once, not per session: the resolver walks config discovery and the user-level registry,
37
+ // and neither changes between two tabs connecting a second apart.
38
+ const resolveArtifactRoot = artifactRootResolver(deps.reticleRoot);
39
+ bridge.attachSessionCreate((session) => {
40
+ // Stamp the project's own `.reticle` before ANY counter fires for this session. Without it every
41
+ // verdict is recorded against wherever the daemon was started, which is how one app's evidence
42
+ // reached a different account's production dashboard.
43
+ // The origin is passed for the case where the page never stamped a project id: it is the only
44
+ // distinguishing fact left, and without it every such app shares one bucket.
45
+ session.artifactRoot = resolveArtifactRoot(session.projectId, originOf(session.url)).root;
46
+ // The project's config sits beside its `.reticle/`, so the declaration is read from the tab's
47
+ // own project rather than from wherever the daemon was started.
48
+ session.background = readBackgroundTraffic(findProjectConfig(dirname(session.artifactRoot)));
49
+ // Here rather than on the start path, which was neither the moment we were about to write into a
50
+ // repository nor the root we were about to write into: it created `.reticle/` — holding nothing
51
+ // but the ignore file — wherever the daemon was launched, coming back every boot after the user
52
+ // deleted it, while the journals this ignore protects landed in another tree, uncovered.
53
+ if (deps.enabled)
54
+ void ensureWorkspaceGitignore(deps.fs, session.artifactRoot);
55
+ journalAttach(session);
56
+ // Seed the learned ambient map so a fresh session starts knowing which regions churn, instead of
57
+ // re-learning from zero. Best-effort + async: a late seed still helps, a failure is silent.
58
+ if (deps.enabled) {
59
+ void ambientStore
60
+ .load()
61
+ .then((counts) => session.seedAmbient(counts))
62
+ .catch(() => undefined);
63
+ }
64
+ });
65
+ // Teardown: flush the journal tail to disk + persist what this session learned.
66
+ bridge.attachSessionEnd(makeSessionEnd({
67
+ ...deps,
68
+ // A drive is saved in the session's own project, where replay will look for it.
69
+ ...(deps.flows === undefined
70
+ ? {}
71
+ : { flowsAt: (root) => new FlowStore(deps.fs, root, { now: Date.now }) }),
72
+ ...(deps.retain === undefined ? {} : { retain: deps.retain }),
73
+ // Retention runs from teardown, and it must not delete the journal of a session that is still
74
+ // being written. The registry is the only thing that knows which those are.
75
+ liveSessionIds: () => new Set(bridge.sessions.all().map((s) => s.id)),
76
+ }));
77
+ /*
78
+ * And the same write, DURING the session rather than only at the end of it.
79
+ *
80
+ * Teardown was the only writer of a run artifact, so every verdict produced while a tab stayed
81
+ * open was invisible to cloud sync — which can only push artifacts that exist. Reported as "sync
82
+ * is not happening" and diagnosed as the agent forgetting to sync; there is no sync command to
83
+ * forget. The evidence simply was not on disk yet.
84
+ *
85
+ * Safe to call repeatedly because the run id is derived from the session, so this rewrites one
86
+ * artifact rather than accumulating them — a property `recordDriveRun` already had, for the
87
+ * unrelated reason that a reconnecting tab must not publish two overlapping rows.
88
+ */
89
+ if (deps.enabled) {
90
+ attachDriveRunFlush({
91
+ resolve: (sessionId) => bridge.sessions.get(sessionId),
92
+ write: (session) => recordDriveRun(deps, session),
93
+ });
94
+ }
95
+ // One call, because "what maintenance runs at startup" needs one answer. Inlined here, the byte
96
+ // budget was simply missing — written, tested, and called by nothing, while the three count
97
+ // bounds beside it ran every time. See startup-maintenance.ts.
98
+ //
99
+ // Deliberately NOT behind `deps.enabled`. Switching journalling off is what somebody does BECAUSE
100
+ // the directory got too big, and both sweep sites were gated on it, so that setting was the one
101
+ // under which nothing ever deleted what was already there. Visual diffs, feedback copies and run
102
+ // artifacts do not need the journal to be written at all and kept accumulating regardless.
103
+ void pruneWorkspace(deps.fs, deps.reticleRoot, new Set(bridge.sessions.all().map((s) => s.id)), deps.retain ?? {});
104
+ }
@@ -18,5 +18,3 @@
18
18
  * allowed to depend on anything, which is what makes them useful as fixtures.
19
19
  */
20
20
  export declare function publishedPackageDirs(): string[];
21
- /** The same list, as the last part of each path: `core`, `server`, `dom`, and so on. */
22
- export declare function publishedPackageNames(): string[];
@@ -1,5 +1,5 @@
1
1
  import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
- import { basename, join } from 'node:path';
2
+ import { join } from 'node:path';
3
3
  import { workspaceGlobs } from '../../scripts/check-boundaries.mjs';
4
4
  import { REPO_ROOT } from './machine/repo-root.js';
5
5
  /**
@@ -47,11 +47,3 @@ function collect(dir, levels, into) {
47
47
  collect(join(dir, entry.name), levels - 1, into);
48
48
  }
49
49
  }
50
- /** The same list, as the last part of each path: `core`, `server`, `dom`, and so on. */
51
- export function publishedPackageNames() {
52
- // `basename`, not `split('/')`: these directories are built with `join`, so on Windows they hold
53
- // backslashes and contain no forward slash at all — the split then returns the WHOLE ABSOLUTE
54
- // PATH as the package name. Every caller comparing a name against a real one silently stops
55
- // matching, which is the same defect that reported fourteen packages as uncovered.
56
- return publishedPackageDirs().map((dir) => basename(dir));
57
- }
package/docs/README.md CHANGED
@@ -13,8 +13,9 @@ Everything here is published to [docs.reticle.sh](https://docs.reticle.sh) by `d
13
13
  | Page | What it answers |
14
14
  | --- | --- |
15
15
  | [quickstart.mdx](quickstart.mdx) | five minutes to a real verdict; every response on it was captured live |
16
- | [what-is-reticle.mdx](what-is-reticle.mdx) | the definition, what Reticle is NOT, and what it needs to run |
17
- | [why-reticle.mdx](why-reticle.mdx) | the false-green problem, the measured case, and where we lose |
16
+ | [what-is-reticle.mdx](what-is-reticle.mdx) | the definition, where it fits beside other tools, and what it needs to run |
17
+ | [why-reticle.mdx](why-reticle.mdx) | the false-green problem, the measured case, and what pairs well with it |
18
+ | [use-cases.mdx](use-cases.mdx) | what people verify with it: agent-built changes, security behaviour, accessibility, performance, SEO basics, personas |
18
19
  | [install-agentic.mdx](install-agentic.mdx) | what `npx @reticlehq/server init` writes, and how to read its marks |
19
20
  | [install-manual.mdx](install-manual.mdx) | wiring the MCP server and SDK by hand, per agent and framework |
20
21
  | [skill-setup.md](skill-setup.md) | the setup half of SKILL.md: what to pass `init`, reading its report, and what to do when it cannot finish |
@@ -24,6 +25,7 @@ Everything here is published to [docs.reticle.sh](https://docs.reticle.sh) by `d
24
25
  | [capabilities.mdx](capabilities.mdx) | coverage, storage, fake clocks, crawl, visual diff, network mocking |
25
26
  | [recipes.mdx](recipes.mdx) | worked examples for real situations, with the response each returned |
26
27
  | [actions.mdx](actions.mdx) | every action and its arguments, including `press` and its history |
28
+ | [environment.mdx](environment.mdx) | every environment variable Reticle reads, what it changes, and which process reads it |
27
29
  | [faq.mdx](faq.mdx) | production, frameworks, comparisons, and the honest limits |
28
30
  | [tools/overview.mdx](tools/overview.mdx) | the 18 advertised tools, the 30 in the cold tail, and why |
29
31
  | [tools/snapshot.mdx](tools/snapshot.mdx) | `reticle_look { action: "page" }`: three modes, from full tree to a 25-token route check |
@@ -72,6 +74,7 @@ Everything here is published to [docs.reticle.sh](https://docs.reticle.sh) by `d
72
74
  | [vs-playwright-mcp.mdx](vs-playwright-mcp.mdx) | outside-in vs inside-out, and when Playwright is right |
73
75
  | [vs-chrome-devtools-mcp.mdx](vs-chrome-devtools-mcp.mdx) | cheaper per look, catches less: the trade, measured |
74
76
  | [vs-screenshots.mdx](vs-screenshots.mdx) | why a better vision model does not fix a non-visual bug |
77
+ | [what-is-recorded.md](what-is-recorded.md) | what Reticle keeps, what is redacted, and what it takes for any of it to leave your machine |
75
78
  | [telemetry.md](telemetry.md) | what is collected, and how to turn it off |
76
79
  | [local-registry.md](local-registry.md) | installing an unpublished build |
77
80
  | [license-activation.mdx](license-activation.mdx) | you have a key: where to set it, how to confirm it, what to do when it fails |
package/docs/actions.mdx CHANGED
@@ -5,7 +5,7 @@ description: Every action reticle_act and reticle_act_and_wait can perform, with
5
5
  icon: hand-pointer
6
6
  ---
7
7
 
8
- Every action Reticle can perform takes the same shape: a `ref` from [`reticle_snapshot`](/tools/snapshot) or [`reticle_query`](/tools/query), an `action` name, and an optional `args` object. The same seventeen actions are available on [`reticle_act`](/tools/act), which proves nothing, and on [`reticle_act_and_wait`](/tools/act-and-wait), which returns a verdict.
8
+ Every action Reticle can perform takes the same shape: a `ref` from [`reticle_look { action: "page" }`](/tools/snapshot) or [`reticle_look { action: "find" }`](/tools/query), an `action` name, and an optional `args` object. The same seventeen actions are available on [`reticle_act`](/tools/act), which proves nothing, and on [`reticle_act_and_wait`](/tools/act-and-wait), which returns a verdict.
9
9
 
10
10
  ```json
11
11
  { "ref": "e104", "action": "fill", "args": { "value": "reticle" } }
@@ -20,7 +20,7 @@ Every action Reticle can perform takes the same shape: a `ref` from [`reticle_sn
20
20
  | `type` | `{ text }` | **Appends** to the current value |
21
21
  | `clear` | none | Empties an input |
22
22
  | `select` | `{ value }` | For `<select>` |
23
- | `check` / `uncheck` | none | Checkbox and radio |
23
+ | `check` / `uncheck` | none | Checkbox and radio, or a `role="checkbox"`/`role="switch"` element (fails if `aria-checked` does not change) |
24
24
  | `submit` | none | Submits the element's `<form>` |
25
25
  | `press` | `{ text }` | The key **name**: `Escape`, `Tab`, `Enter` |
26
26
  | `scrollIntoView` | none | |
@@ -93,7 +93,7 @@ Several actions in one round trip:
93
93
  ```
94
94
 
95
95
  <Warning>
96
- [`reticle_act_sequence`](/tools/act-sequence) returns `ok: true` when the steps were
96
+ [`reticle_act { steps: [...] }`](/tools/act-sequence) returns `ok: true` when the steps were
97
97
  **dispatched**, not when they worked. Batch the setup, then prove the outcome with
98
98
  [`reticle_act_and_wait`](/tools/act-and-wait) on the final step.
99
99
  </Warning>
@@ -4,7 +4,7 @@ description: 'One screen to get fluent: the look → act → observe → assert
4
4
  icon: bolt
5
5
  ---
6
6
 
7
- The loop is **look → act → observe → assert**, and only `reticle_act_and_wait` and `reticle_assert` produce a verdict. Reach for `reticle_act_and_wait({ ref, action, until })` first: it names the expected consequence before the action, which is the difference between a check and a rationalisation. `verified: "unknown"` is not a pass.
7
+ The loop is **look → act → observe → assert**, and verdicts come from `reticle_act_and_wait`, `reticle_assert`, and `reticle_act { steps }` when a step declares `expect`. Reach for `reticle_act_and_wait({ ref, action, until })` first: it names the expected consequence before the action, which is the difference between a check and a rationalisation. `verified: "unknown"` is not a pass.
8
8
 
9
9
  One screen to get fluent. Reticle is the **proof layer for AI agents**: no screenshots, no vision model, evidence not prose. Everything below returns structured data. Full guide: [usage.md](usage.md).
10
10
 
@@ -17,7 +17,7 @@ One screen to get fluent. Reticle is the **proof layer for AI agents**: no scree
17
17
  | **observe** | `reticle_observe` / `reticle_assert { action: "wait" }` | Everything the app did after `since` / block until true. |
18
18
  | **assert** | `reticle_assert` | Evaluate a predicate → `{ pass, evidence, failureReason? }`. The end of every loop. |
19
19
 
20
- > **Only `reticle_act_and_wait` and `reticle_assert` produce a verdict.** Everything else moves or reads the app and proves nothing, so a drive ending without one of those two has no result however many tools it used. `reticle_act` is the tool agents reach for by habit and it catches nothing; `act_and_wait` is where defects actually surface. And `verified: "unknown"` is not a pass: it means Reticle drove the app and could not tell what happened. Report it as unknown.
20
+ > **Verdicts come from `reticle_act_and_wait`, `reticle_assert`, and `reticle_act { steps }` when a step declares `expect`.** Everything else moves or reads the app and proves nothing, so a drive ending without a verdict has no result however many tools it used. `reticle_act` is the tool agents reach for by habit and it catches nothing; `act_and_wait` is where defects actually surface. And `verified: "unknown"` is not a pass: it means Reticle drove the app and could not tell what happened. Report it as unknown.
21
21
 
22
22
  `reticle_act` returns a `since` cursor; pass it to `reticle_observe({ since })` to scope the window. Elements are addressed by stable refs (`e7`) from `snapshot`/`query`; they re-resolve across re-renders.
23
23
 
@@ -125,9 +125,9 @@ Call an old name and you are told the new one. `reticle_tools` prints the live s
125
125
 
126
126
  - `reticle_verify`: **the only core tool that CONCLUDES.** `{ action:"crawl" }` drives every reachable control itself and reports the whole fault set in one call (destructive: it really clicks). `{ action:"flows" }` replays every saved flow with no model in the loop. Reach for it when you think you are done: every other tool here answers "here is more to look at".
127
127
 
128
- Not on this surface at all, and NOT reachable by any call from it: `reticle_capabilities` (the app's whole testable surface in one call), `reticle_domain` (learn the app + gaps), `reticle_baseline {action:"diff"}`, `reticle_project` (run history), `reticle_screenshot`, `reticle_visual_diff`, `reticle_storage`, `reticle_network_mock`, `reticle_clock`. They need a daemon started with `RETICLE_ADVERTISE_ALL_TOOLS=1`, which advertises the full table.
128
+ Not on this surface at all, but one hop away: `reticle_run { tool, args }` calls any registered tool by name, advertised or not, and `reticle_tools { names: [...] }` loads its arguments. That reaches `reticle_capabilities` (the app's whole testable surface in one call), `reticle_domain` (learn the app + gaps), `reticle_baseline {action:"diff"}`, `reticle_project` (run history), `reticle_screenshot`, `reticle_visual_diff`, `reticle_storage`, `reticle_network_mock` and `reticle_clock`. A daemon started with `RETICLE_ADVERTISE_ALL_TOOLS=1` advertises them directly instead.
129
129
 
130
- **What the wider surface adds, if you start the daemon with `RETICLE_ADVERTISE_ALL_TOOLS=1`:** record/replay a journey (`reticle_record {action:"start"}/stop`, `reticle_replay`), persist a self-healing golden flow (`reticle_flow_save*` / `reticle_flow_replay` / `reticle_verify { action: "heal" }`), compile annotations (`reticle_annotate`), explore autonomously (`reticle_explore` lists controls; `reticle_verify {action:"crawl"}` is now advertised directly, clicks them all and reports anomalies, and is **destructive**), reveal a virtualized off-screen row (`reticle_scroll_to`, for when `reticle_look { action: "find" }` finds nothing because a windowed list hasn't rendered it yet), visual-check (`reticle_screenshot` / `reticle_visual_diff`, pinned with `reticle_viewport` for reproducible baselines), test error/edge states by stubbing the network (`reticle_network_mock`: 500 / offline / delay, driven or leased), control time for toasts/debounces/auto-dismiss (`reticle_clock { freeze | advanceMs | reset }`), or work with a human (`reticle_session {action:"end"}` / `reticle_session {action:"resume"}` / `reticle_session {action:"messages"}`, and **`reticle_session {action:"review"}`** to drain + fix the bugs the human flagged from the panel).
130
+ **What the wider surface adds, through `reticle_run` or advertised directly with `RETICLE_ADVERTISE_ALL_TOOLS=1`:** record/replay a journey (`reticle_record {action:"start"}/stop`, `reticle_replay`), persist a self-healing golden flow (`reticle_flow_save*` / `reticle_flow_replay` / `reticle_verify { action: "heal" }`), compile annotations (`reticle_annotate`), explore autonomously (`reticle_explore` lists controls; `reticle_verify {action:"crawl"}` is now advertised directly, clicks them all and reports anomalies, and is **destructive**), reveal a virtualized off-screen row (`reticle_scroll_to`, for when `reticle_look { action: "find" }` finds nothing because a windowed list hasn't rendered it yet), visual-check (`reticle_screenshot` / `reticle_visual_diff`, pinned with `reticle_viewport` for reproducible baselines), test error/edge states by stubbing the network (`reticle_network_mock`: 500 / offline / delay, driven or leased), control time for toasts/debounces/auto-dismiss (`reticle_clock { freeze | advanceMs | reset }`), or work with a human (`reticle_session {action:"end"}` / `reticle_session {action:"resume"}` / `reticle_session {action:"messages"}`, and **`reticle_session {action:"review"}`** to drain + fix the bugs the human flagged from the panel).
131
131
 
132
132
  ## flows vs baselines vs project.json (the persistence layers)
133
133
 
@@ -14,7 +14,7 @@ Reticle has three moving parts: a dev-only **SDK** inside your page that instrum
14
14
 
15
15
  Your app, in dev, embeds a tiny **SDK** that instruments the page (DOM, network, console, routing, framework state) and opens a WebSocket to a local **bridge**. The bridge runs inside the Reticle **server**, which also exposes an **MCP server**, the standard protocol AI agents speak.
16
16
 
17
- Your coding agent calls MCP tools (`reticle_query`, `reticle_act`, `reticle_assert`, …); the server turns them into commands over the WebSocket; the SDK executes them in the page and streams back structured events. The agent thus **looks, acts, observes, and asserts** on the real running app, never on a screenshot.
17
+ Your coding agent calls MCP tools (`reticle_look { action: "find" }`, `reticle_act`, `reticle_assert`, …); the server turns them into commands over the WebSocket; the SDK executes them in the page and streams back structured events. The agent thus **looks, acts, observes, and asserts** on the real running app, never on a screenshot.
18
18
 
19
19
  ```mermaid
20
20
  flowchart LR
@@ -23,7 +23,7 @@ flowchart LR
23
23
  B["@reticlehq/browser<br/>SDK in your app<br/>(the DOM)"]
24
24
  D[(".reticle/<br/>flows · baselines<br/>runs · contract")]
25
25
 
26
- A -- "MCP (stdio/SSE)<br/>reticle_query / act / assert" --> S
26
+ A -- "MCP (stdio/SSE)<br/>reticle_look / act / assert" --> S
27
27
  S -- "tool results" --> A
28
28
  S <-- "WebSocket<br/>commands / events" --> B
29
29
  S <--> D
@@ -37,7 +37,7 @@ Reticle is a pnpm + Turborepo monorepo. The split is not cosmetic: each boundary
37
37
 
38
38
  | Package | Runs in | Responsibility | Hard rule |
39
39
  | --- | --- | --- | --- |
40
- | `@reticlehq/core` | both | The **wire contract**: every constant + zod schema crossing any boundary | Depends only on `zod` |
40
+ | `@reticlehq/core` | both | The **wire contract**: every constant + zod schema crossing any boundary | Depends only on `zod` and `open-verification` |
41
41
  | `@reticlehq/browser` | the browser | Instrument the page; execute commands; emit events | Never imports Node APIs |
42
42
  | `@reticlehq/server` | Node | The bridge, the MCP server, the `reticle` CLI, flow/run storage | Never imports DOM APIs |
43
43
  | `@reticlehq/react` | the browser | The SDK **kit** you install in a browser app: re-exports the browser sensor (so one install gives both `reticle` and `install`) and maps a DOM node → React component → source `file:line` | Core works without the source-mapping half |
@@ -59,8 +59,8 @@ The browser and server both import it; neither can invent a message the other do
59
59
 
60
60
  1. **Connect.** In dev, your app calls `reticle.connect({ session })`. The SDK opens a WebSocket to the bridge (`ws://localhost:4400/reticle` by default) and sends a `HELLO` carrying the session id, protocol version, and (if configured) a pairing token. Each browser tab uses `SESSION_AUTO` (a unique id), so multiple apps/tabs never collide.
61
61
  2. **Capture.** The SDK installs observers: a `MutationObserver` for DOM changes, wrappers around `fetch`/`XHR` for network, a console hook, a history hook for routing, and registries the app opts into (`registerStore`, `registerCapabilities`, `reticle.signal`). Events flow into a bounded **ring buffer**, so recent history is always available and memory is capped.
62
- 3. **Look / act.** The agent calls an MCP tool. `reticle_query` finds an element by role/text/testid/ component and returns a stable **ref**. `reticle_act` dispatches an action against that ref and returns an **effect** report (did it land, did the DOM mutate, did focus move…). The server sends the command over the WebSocket; the SDK runs it and replies.
63
- 4. **Observe.** After an action, the agent reads what happened with `reticle_network`, `reticle_console`, `reticle_state`, or the reaction digest from `reticle_act_and_wait`. The server pulls the relevant slice of the ring buffer (scoped to a cursor so stale events can't leak in) and returns a compact summary.
62
+ 3. **Look / act.** The agent calls an MCP tool. `reticle_look { action: "find" }` finds an element by role/text/testid/ component and returns a stable **ref**. `reticle_act` dispatches an action against that ref and returns an **effect** report (did it land, did the DOM mutate, did focus move…). The server sends the command over the WebSocket; the SDK runs it and replies.
63
+ 4. **Observe.** After an action, the agent reads what happened with `reticle_observe { action: "network" }`, `reticle_observe { action: "console" }`, `reticle_look { action: "state" }`, or the reaction digest from `reticle_act_and_wait`. The server pulls the relevant slice of the ring buffer (scoped to a cursor so stale events can't leak in) and returns a compact summary.
64
64
  5. **Assert.** `reticle_assert` (and a flow's declared `success`) evaluates a **predicate** over program truth (a network call that returned 200, a store value, a `signal` the app emitted), not just "an element exists." This is the difference between "looks done" and "is done."
65
65
 
66
66
  ---
@@ -87,7 +87,7 @@ The same verification runs over and over, every commit, every CI run. Reticle re
87
87
 
88
88
  ### 4. Dev-only, localhost-only, your app data stays local
89
89
 
90
- The SDK is tree-shaken out of production builds and connects only to a local bridge. The bridge binds to loopback by default; exposing it beyond localhost _requires_ a pairing token (the server refuses to bind a non-loopback host without one). Every environment variable that gates a security control is a single named constant, so a typo can't silently disable auth. Nothing from the app under test ever leaves your machine: no DOM, network, console, state, or source. The CLI reports anonymous, opt-out usage metrics only (a random id + event names like `invoke`/`session_start`; no code, no PII; see [telemetry](telemetry.md)); opt out with `reticle telemetry disable`, `RETICLE_TELEMETRY=0`, or `DO_NOT_TRACK=1`. The one thing that carries free text is feedback you or your agent deliberately send (`reticle feedback` / `reticle_feedback`). It is never collected passively, it is redacted before sending, and it is disabled separately with `RETICLE_FEEDBACK=0`.
90
+ The SDK is tree-shaken out of production builds and connects only to a local bridge. The bridge binds to loopback by default; exposing it beyond localhost _requires_ a pairing token (the server refuses to bind a non-loopback host without one). Every environment variable that gates a security control is a single named constant, so a typo can't silently disable auth. Nothing from the app under test ever leaves your machine: no DOM, network, console, state, or source. The CLI reports anonymous, opt-out usage metrics only (a random id + event names like `invoke`/`session_start`; no code, no PII; see [telemetry](telemetry.md)); opt out with `reticle telemetry disable`, `RETICLE_TELEMETRY=0`, or `DO_NOT_TRACK=1`. The one thing that carries free text is feedback you or your agent deliberately send (`reticle feedback` / `reticle_session { action: "feedback" }`). It is never collected passively, it is redacted before sending, and it is disabled separately with `RETICLE_FEEDBACK=0`.
91
91
 
92
92
  ---
93
93
 
@@ -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 [`reticle_sessions`](/tools/sessions) for a session at the new URL before acting, and re-snapshot: refs do not survive a new document.
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
 
@@ -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 [`reticle_network`](/tools/network), so reading storage never puts a session token in your context.
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
@@ -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; the default is `http://localhost:8890`. When a command falls back to that default without `RETICLE_CLOUD_URL` (or a saved session URL), it prints a one-line notice on stderr; stdout stays pure JSON for agents.
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,7 +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 `{ pushed, failed, total, project }`.
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.
115
+
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.
105
117
 
106
118
  ### `reticle runs`
107
119
 
@@ -128,17 +140,17 @@ reticle: usage: reticle share <runId>
128
140
  `push`, `runs` and `regression` all need a project to talk to. Without one they exit `1` with the same line on stderr, measured:
129
141
 
130
142
  ```
131
- reticle: cloud not attached here ... run `reticle link` (or set RETICLE_CLOUD_URL/KEY)
143
+ reticle: cloud not attached here ... run `reticle link` (or set RETICLE_API_KEY)
132
144
  ```
133
145
 
134
146
  ## Exit codes
135
147
 
136
- | Code | Meaning |
137
- | ---- | ----------------------------------------------------------------------------------- |
138
- | `0` | Success |
139
- | `1` | The API call failed, or the repository is not attached where attachment is required |
140
- | `2` | Usage error, or not signed in and no `RETICLE_API_KEY` |
141
- | `3` | `regression` only: at least one flow broke |
148
+ | Code | Meaning |
149
+ | --- | --- |
150
+ | `0` | Success |
151
+ | `1` | The API call failed, the repository is not attached where attachment is required, or `push` had an artifact refused |
152
+ | `2` | Usage error, or not signed in and no `RETICLE_API_KEY` |
153
+ | `3` | `regression` only: at least one flow broke |
142
154
 
143
155
  Output is pretty-printed JSON on stdout. Errors and next-step nudges go to stderr, so an agent parsing stdout is unaffected.
144
156
 
@@ -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
  ```
@@ -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 `reticle_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.
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
- `reticle_feedback` when the tools are reachable.
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 `deletedCoverage` appear only when they are non-empty, and neither was present in that run. The CLI prints this as a single line of JSON; it is pretty-printed here to be readable.
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 and nothing was weakened or deleted |
51
- | `1` | Something is uncovered, downgraded or deleted. Also `1` on any internal fault: the gate fails closed |
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/init.mdx CHANGED
@@ -19,6 +19,7 @@ npx @reticlehq/server init [--dry-run] [--port N] [--no-mcp] [--no-install] [--a
19
19
  | `--no-mcp` | boolean | `false` (MCP is registered) | Skip the MCP registration **and** the agent rule files (`CLAUDE.md`, `AGENTS.md`, `.cursor`) and the `/reticle` command |
20
20
  | `--no-install` | boolean | `false` (deps are installed) | Do not run the install. The step becomes `[⚠]` and prints the `add -D` command for you to run by hand, rather than vanishing from the plan |
21
21
  | `--app <dir>` | string | unset | Pick which app to wire in a monorepo, without changing directory |
22
+ | `--hooks` | boolean | `false` | Also add a print-only Stop hook to `.claude/settings.json`, merged into what is there. When the agent stops without a claim that held, it prints one line; it never blocks. See [`reticle report`](/cli/report) |
22
23
  | `--yes` | boolean | `false` | Accepted for scripting. `init` has no interactive prompts today, so it is a no-op |
23
24
 
24
25
  <Warning>