@reticlehq/server 3.7.0 → 3.8.1

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 (578) hide show
  1. package/SKILL.md +59 -68
  2. package/bin/reticle.js +9 -2
  3. package/dist/command/cli/adhoc-suite.js +1 -1
  4. package/dist/command/cli/adhoc-verdict.d.ts +12 -0
  5. package/dist/command/cli/adhoc-verdict.js +62 -4
  6. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  7. package/dist/command/cli/answers/gate-hook-message.js +5 -1
  8. package/dist/command/cli/auth/cloud-session.d.ts +11 -19
  9. package/dist/command/cli/auth/cloud-session.js +23 -0
  10. package/dist/command/cli/auth/device-flow.d.ts +3 -37
  11. package/dist/command/cli/cli-doctor.js +66 -21
  12. package/dist/command/cli/cli-flow-commands.js +53 -11
  13. package/dist/command/cli/cli-kill.d.ts +8 -0
  14. package/dist/command/cli/cli-kill.js +43 -3
  15. package/dist/command/cli/cli-parse-feedback.d.ts +4 -0
  16. package/dist/command/cli/cli-parse-feedback.js +13 -1
  17. package/dist/command/cli/cli-parse-grammar.d.ts +1 -2
  18. package/dist/command/cli/cli-parse-grammar.js +1 -6
  19. package/dist/command/cli/cli-parse-serve.d.ts +24 -0
  20. package/dist/command/cli/cli-parse-serve.js +124 -0
  21. package/dist/command/cli/cli-parse.d.ts +12 -11
  22. package/dist/command/cli/cli-parse.js +100 -123
  23. package/dist/command/cli/cli-usage.d.ts +0 -11
  24. package/dist/command/cli/cli-usage.js +43 -16
  25. package/dist/command/cli/cli-verify.d.ts +1 -1
  26. package/dist/command/cli/cli-verify.js +29 -14
  27. package/dist/command/cli/cloud-cli.js +27 -9
  28. package/dist/command/cli/cloud-kit.js +3 -3
  29. package/dist/command/cli/cloud-link.d.ts +1 -20
  30. package/dist/command/cli/cloud-link.js +2 -0
  31. package/dist/command/cli/cloud-login.d.ts +6 -2
  32. package/dist/command/cli/cloud-login.js +13 -41
  33. package/dist/command/cli/config/checkout.d.ts +10 -0
  34. package/dist/command/cli/config/checkout.js +78 -0
  35. package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
  36. package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
  37. package/dist/command/cli/doctor/doctor-coverage-line.js +1 -7
  38. package/dist/command/cli/doctor/doctor-rows.d.ts +4 -0
  39. package/dist/command/cli/doctor/doctor-rows.js +4 -0
  40. package/dist/command/cli/drive/drive-attach.d.ts +5 -0
  41. package/dist/command/cli/drive/drive-attach.js +21 -1
  42. package/dist/command/cli/hook/codex-transcript.d.ts +20 -0
  43. package/dist/command/cli/hook/codex-transcript.js +224 -0
  44. package/dist/command/cli/hook/episode-structure.d.ts +24 -0
  45. package/dist/command/cli/hook/episode-structure.js +138 -0
  46. package/dist/command/cli/hook/hook-command.d.ts +9 -0
  47. package/dist/command/cli/hook/hook-command.js +211 -0
  48. package/dist/command/cli/hook/hook-fast.d.ts +31 -0
  49. package/dist/command/cli/hook/hook-fast.js +136 -0
  50. package/dist/command/cli/hook/prompt-hook.d.ts +30 -0
  51. package/dist/command/cli/hook/prompt-hook.js +199 -0
  52. package/dist/command/cli/hook/tool-hook.d.ts +21 -0
  53. package/dist/command/cli/hook/tool-hook.js +259 -0
  54. package/dist/command/cli/launch/cli-launch.d.ts +2 -0
  55. package/dist/command/cli/launch/cli-launch.js +22 -2
  56. package/dist/command/cli/lifecycle/daemon-lifecycle.js +28 -2
  57. package/dist/command/cli/mcp-command.d.ts +9 -0
  58. package/dist/command/cli/mcp-command.js +127 -41
  59. package/dist/command/cli/open-navigate.d.ts +43 -0
  60. package/dist/command/cli/open-navigate.js +85 -0
  61. package/dist/command/cli/ports/port-holder.d.ts +16 -4
  62. package/dist/command/cli/ports/port-holder.js +58 -12
  63. package/dist/command/cli/ports/resolve/cli-port.js +18 -2
  64. package/dist/command/cli/project-name.d.ts +1 -7
  65. package/dist/command/cli/project-name.js +1 -0
  66. package/dist/command/cli/report-command.d.ts +8 -2
  67. package/dist/command/cli/report-command.js +95 -18
  68. package/dist/command/cli/status-fields.d.ts +9 -2
  69. package/dist/command/cli/status-fields.js +148 -4
  70. package/dist/command/cli/try-command.d.ts +3 -4
  71. package/dist/command/cli/try-command.js +6 -11
  72. package/dist/command/cli/verify-results.d.ts +4 -1
  73. package/dist/command/cli/verify-results.js +3 -1
  74. package/dist/command/cli.d.ts +1 -7
  75. package/dist/command/cli.js +79 -160
  76. package/dist/command/daemon/daemon-resilience.d.ts +6 -1
  77. package/dist/command/daemon/daemon-resilience.js +31 -18
  78. package/dist/command/daemon/daemon.d.ts +11 -0
  79. package/dist/command/daemon/daemon.js +70 -2
  80. package/dist/command/daemon/lifetime/daemon-usefulness.d.ts +2 -0
  81. package/dist/command/daemon/lifetime/daemon-usefulness.js +13 -2
  82. package/dist/command/daemon/wake-decision.js +4 -2
  83. package/dist/command/daemon/win32-escape.d.ts +32 -0
  84. package/dist/command/daemon/win32-escape.js +119 -0
  85. package/dist/command/setup/agent-configs.d.ts +9 -0
  86. package/dist/command/setup/agent-configs.js +9 -0
  87. package/dist/command/setup/auto-approve.d.ts +10 -3
  88. package/dist/command/setup/auto-approve.js +51 -3
  89. package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
  90. package/dist/command/setup/bringup/dev-server-wait.js +5 -1
  91. package/dist/command/setup/bringup/ensure-daemon.js +4 -7
  92. package/dist/command/setup/init/init-host.js +6 -0
  93. package/dist/command/setup/init/init-port.js +5 -4
  94. package/dist/command/setup/init/init-runtime.js +7 -1
  95. package/dist/command/setup/node-effects.d.ts +8 -0
  96. package/dist/command/setup/node-effects.js +36 -4
  97. package/dist/command/setup/probe/dev-port.d.ts +26 -0
  98. package/dist/command/setup/probe/dev-port.js +117 -0
  99. package/dist/command/setup/probe/page-probe.d.ts +1 -1
  100. package/dist/command/setup/probe/page-probe.js +11 -3
  101. package/dist/command/setup/remaining-steps.d.ts +0 -7
  102. package/dist/command/setup/remaining-steps.js +3 -2
  103. package/dist/command/setup/run-setup.d.ts +11 -0
  104. package/dist/command/setup/run-setup.js +33 -5
  105. package/dist/command/setup/setup-command.d.ts +2 -0
  106. package/dist/command/setup/setup-command.js +22 -4
  107. package/dist/command/update/updater.d.ts +1 -6
  108. package/dist/command/update/updater.js +4 -5
  109. package/dist/command/update/version-seen.d.ts +24 -0
  110. package/dist/command/update/version-seen.js +65 -0
  111. package/dist/command/version/peer-announce.d.ts +9 -1
  112. package/dist/command/version/peer-announce.js +25 -2
  113. package/dist/command/version/sdk-fix.d.ts +5 -6
  114. package/dist/command/version/sdk-fix.js +17 -32
  115. package/dist/command/version/version-skew.d.ts +16 -1
  116. package/dist/command/version/version-skew.js +84 -10
  117. package/dist/features/crawl/crawl-tools.js +2 -2
  118. package/dist/features/crawl/crawl.js +2 -0
  119. package/dist/features/exhaust/ledger.d.ts +15 -96
  120. package/dist/features/exhaust/ledger.js +3 -3
  121. package/dist/features/harness/drive-runs.d.ts +28 -4
  122. package/dist/features/harness/drive-runs.js +99 -7
  123. package/dist/features/harness/drivers.d.ts +1 -1
  124. package/dist/features/harness/drivers.js +1 -1
  125. package/dist/features/harness/harness.d.ts +5 -0
  126. package/dist/features/harness/harness.js +24 -12
  127. package/dist/features/harness/platform/platform-drives.d.ts +7 -1
  128. package/dist/features/harness/platform/platform-drives.js +12 -7
  129. package/dist/features/harness/platform/refusal.d.ts +1 -1
  130. package/dist/features/harness/platform/refusal.js +4 -4
  131. package/dist/features/harness/platform/remote-drive.js +70 -28
  132. package/dist/features/harness/platform/server-driver.js +22 -1
  133. package/dist/features/harness/platform-config.d.ts +1 -10
  134. package/dist/features/harness/platform-config.js +0 -20
  135. package/dist/features/license/license.d.ts +2 -14
  136. package/dist/features/visual/step-shots.d.ts +33 -1
  137. package/dist/features/visual/step-shots.js +155 -1
  138. package/dist/features/visual/visual-tools.js +12 -4
  139. package/dist/hooks/coding-agents.d.ts +6 -0
  140. package/dist/hooks/coding-agents.js +24 -3
  141. package/dist/hooks/episode-stamp.d.ts +32 -0
  142. package/dist/hooks/episode-stamp.js +61 -0
  143. package/dist/hooks/hook-commands.js +19 -9
  144. package/dist/index.d.ts +5 -1
  145. package/dist/index.js +66 -24
  146. package/dist/judgement/app-graph/journal-steps.d.ts +8 -0
  147. package/dist/judgement/app-graph/journal-steps.js +92 -0
  148. package/dist/judgement/capsule/capsule-store.d.ts +2 -39
  149. package/dist/judgement/domain/domain-model.js +1 -10
  150. package/dist/judgement/domain/domain-tools.js +4 -2
  151. package/dist/judgement/runs/artifact/run-store.d.ts +28 -8
  152. package/dist/judgement/runs/artifact/run-store.js +153 -28
  153. package/dist/judgement/runs/default-run-id.d.ts +3 -1
  154. package/dist/judgement/runs/default-run-id.js +15 -3
  155. package/dist/judgement/runs/drive-run.d.ts +3 -3
  156. package/dist/judgement/runs/drive-run.js +11 -7
  157. package/dist/judgement/runs/run-ledger.d.ts +21 -0
  158. package/dist/judgement/runs/run-ledger.js +143 -0
  159. package/dist/judgement/runs/runner-port.d.ts +1 -1
  160. package/dist/judgement/runs/runner-port.js +8 -2
  161. package/dist/judgement/runs/verification-sync.d.ts +4 -3
  162. package/dist/judgement/runs/verification-sync.js +27 -5
  163. package/dist/language/flows/affected-tools.js +2 -1
  164. package/dist/language/flows/annotate-notes/annotate.js +8 -3
  165. package/dist/language/flows/annotate-tools.js +1 -1
  166. package/dist/language/flows/change/affected.d.ts +8 -0
  167. package/dist/language/flows/change/affected.js +20 -7
  168. package/dist/language/flows/decision.js +19 -4
  169. package/dist/language/flows/fields/flow-secret-field.d.ts +9 -0
  170. package/dist/language/flows/fields/flow-secret-field.js +67 -5
  171. package/dist/language/flows/flow-anchor.d.ts +5 -0
  172. package/dist/language/flows/flow-anchor.js +4 -0
  173. package/dist/language/flows/flow-cross-step.d.ts +7 -1
  174. package/dist/language/flows/flow-cross-step.js +9 -0
  175. package/dist/language/flows/flow-expect-grammar.js +15 -10
  176. package/dist/language/flows/flow-intent.js +6 -1
  177. package/dist/language/flows/flow-journey.d.ts +8 -0
  178. package/dist/language/flows/flow-journey.js +13 -0
  179. package/dist/language/flows/flow-lease.d.ts +27 -0
  180. package/dist/language/flows/flow-lease.js +59 -0
  181. package/dist/language/flows/flow-replay-run.d.ts +1 -87
  182. package/dist/language/flows/flow-replay-run.js +111 -310
  183. package/dist/language/flows/flow-replay.js +21 -19
  184. package/dist/language/flows/flow-replayable.d.ts +38 -0
  185. package/dist/language/flows/flow-replayable.js +179 -0
  186. package/dist/language/flows/flow-start-path.d.ts +108 -0
  187. package/dist/language/flows/flow-start-path.js +313 -0
  188. package/dist/language/flows/flow-step-runners.d.ts +23 -2
  189. package/dist/language/flows/flow-step-runners.js +191 -32
  190. package/dist/language/flows/flow-store-for-session.d.ts +8 -1
  191. package/dist/language/flows/flow-store-for-session.js +6 -0
  192. package/dist/language/flows/flow-tools.d.ts +2 -23
  193. package/dist/language/flows/flow-tools.js +63 -113
  194. package/dist/language/flows/flows.d.ts +4 -6
  195. package/dist/language/flows/flows.js +90 -15
  196. package/dist/language/flows/heal-run.d.ts +10 -4
  197. package/dist/language/flows/heal-run.js +26 -9
  198. package/dist/language/flows/recording/flake.d.ts +3 -27
  199. package/dist/language/flows/recording/flake.js +1 -1
  200. package/dist/language/flows/recording/recording-backtrack.js +1 -4
  201. package/dist/language/flows/recording/tape/recordings.d.ts +11 -1
  202. package/dist/language/flows/recording/tape/recordings.js +9 -3
  203. package/dist/language/flows/replay.d.ts +25 -5
  204. package/dist/language/flows/replay.js +83 -16
  205. package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
  206. package/dist/language/flows/suite/coverage.d.ts +9 -0
  207. package/dist/language/flows/suite/coverage.js +12 -1
  208. package/dist/language/flows/suite-selection.d.ts +25 -0
  209. package/dist/language/flows/suite-selection.js +41 -9
  210. package/dist/machine/git-tracks.d.ts +6 -0
  211. package/dist/machine/git-tracks.js +36 -0
  212. package/dist/memory/cloud/background-sync.d.ts +25 -0
  213. package/dist/memory/cloud/background-sync.js +79 -0
  214. package/dist/memory/cloud/cloud-config.d.ts +12 -1
  215. package/dist/memory/cloud/cloud-config.js +39 -13
  216. package/dist/memory/cloud/cloud-sync.d.ts +3 -24
  217. package/dist/memory/cloud/cloud-sync.js +5 -2
  218. package/dist/memory/cloud/harness-config.d.ts +0 -7
  219. package/dist/memory/cloud/memory-scope.d.ts +19 -0
  220. package/dist/memory/cloud/memory-scope.js +48 -0
  221. package/dist/memory/cloud/sync-answer.d.ts +43 -0
  222. package/dist/memory/cloud/sync-answer.js +42 -0
  223. package/dist/memory/cloud/sync-cycle.d.ts +40 -10
  224. package/dist/memory/cloud/sync-cycle.js +97 -144
  225. package/dist/memory/cloud/sync-daemon.d.ts +50 -3
  226. package/dist/memory/cloud/sync-daemon.js +473 -83
  227. package/dist/memory/cloud/sync-describe.d.ts +28 -0
  228. package/dist/memory/cloud/sync-describe.js +92 -0
  229. package/dist/memory/cloud/sync-disk.d.ts +9 -1
  230. package/dist/memory/cloud/sync-disk.js +137 -33
  231. package/dist/memory/cloud/sync-flow-versions.d.ts +26 -0
  232. package/dist/memory/cloud/sync-flow-versions.js +42 -0
  233. package/dist/memory/impact/impact-store.js +32 -15
  234. package/dist/memory/intent/intent-shard.d.ts +41 -266
  235. package/dist/memory/intent/intent-tools.js +20 -61
  236. package/dist/memory/intent/record-request.d.ts +27 -0
  237. package/dist/memory/intent/record-request.js +88 -0
  238. package/dist/memory/intent/settled-words.js +9 -1
  239. package/dist/memory/journal/drive-flow.d.ts +3 -0
  240. package/dist/memory/journal/drive-flow.js +11 -41
  241. package/dist/memory/journal/envelope-store.js +1 -1
  242. package/dist/memory/journal/envelope.d.ts +6 -154
  243. package/dist/memory/journal/episode-log.d.ts +107 -0
  244. package/dist/memory/journal/episode-log.js +302 -0
  245. package/dist/memory/journal/journal-recorder.d.ts +7 -0
  246. package/dist/memory/journal/journal-recorder.js +22 -9
  247. package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
  248. package/dist/memory/journal/on-disk/ambient-file.js +1 -1
  249. package/dist/memory/journal/on-disk/workspace-gitignore.d.ts +24 -3
  250. package/dist/memory/journal/on-disk/workspace-gitignore.js +38 -7
  251. package/dist/memory/journal/on-disk/workspace-tiers.js +7 -0
  252. package/dist/memory/journal/self-observation.js +3 -1
  253. package/dist/memory/journal/session-end.js +23 -9
  254. package/dist/memory/journal/session-journal.js +39 -20
  255. package/dist/memory/project/artifact-root-resolver.d.ts +14 -1
  256. package/dist/memory/project/artifact-root-resolver.js +68 -23
  257. package/dist/memory/project/artifact-root.d.ts +17 -3
  258. package/dist/memory/project/artifact-root.js +47 -9
  259. package/dist/memory/project/fs/fs-port.d.ts +5 -0
  260. package/dist/memory/project/fs/fs-port.js +13 -0
  261. package/dist/memory/project/learned-routes.d.ts +3 -4
  262. package/dist/memory/project/learned-routes.js +3 -11
  263. package/dist/memory/project/link-directory.js +5 -2
  264. package/dist/memory/project/root-claims.d.ts +3 -1
  265. package/dist/memory/project/root-claims.js +41 -7
  266. package/dist/memory/project/session-root.d.ts +1 -1
  267. package/dist/memory/project/session-root.js +1 -15
  268. package/dist/memory/project/sync-status.js +5 -6
  269. package/dist/memory/recall/memory-tools.js +2 -2
  270. package/dist/memory/recall/platform-memory.d.ts +3 -1
  271. package/dist/memory/recall/platform-memory.js +9 -1
  272. package/dist/memory/recall/project-memory.js +15 -19
  273. package/dist/portal/bridge/auth-failure-reason.d.ts +13 -0
  274. package/dist/portal/bridge/auth-failure-reason.js +19 -0
  275. package/dist/portal/bridge/bridge.d.ts +19 -4
  276. package/dist/portal/bridge/bridge.js +150 -177
  277. package/dist/portal/bridge/harness-request.d.ts +15 -0
  278. package/dist/portal/bridge/harness-request.js +19 -0
  279. package/dist/portal/bridge/origin/origin-follow.d.ts +46 -0
  280. package/dist/portal/bridge/origin/origin-follow.js +110 -0
  281. package/dist/portal/bridge/pairing-token.d.ts +6 -0
  282. package/dist/portal/bridge/pairing-token.js +47 -16
  283. package/dist/portal/bridge/protocol-skew.d.ts +27 -2
  284. package/dist/portal/bridge/protocol-skew.js +66 -2
  285. package/dist/portal/bridge/session-nonces.d.ts +46 -0
  286. package/dist/portal/bridge/session-nonces.js +72 -0
  287. package/dist/portal/input/viewport-tools.d.ts +31 -0
  288. package/dist/portal/input/viewport-tools.js +106 -15
  289. package/dist/portal/pool/bounded-close.d.ts +23 -0
  290. package/dist/portal/pool/bounded-close.js +38 -0
  291. package/dist/portal/pool/browser-pool.d.ts +44 -39
  292. package/dist/portal/pool/browser-pool.js +247 -95
  293. package/dist/portal/pool/context-permissions.d.ts +9 -1
  294. package/dist/portal/pool/context-permissions.js +26 -0
  295. package/dist/portal/pool/lease-emulation.d.ts +37 -0
  296. package/dist/portal/pool/lease-emulation.js +29 -0
  297. package/dist/portal/pool/playwright-launcher.d.ts +6 -0
  298. package/dist/portal/pool/playwright-launcher.js +74 -7
  299. package/dist/portal/pool/pool-contract.d.ts +23 -1
  300. package/dist/portal/pool/pool-lease.d.ts +128 -0
  301. package/dist/portal/pool/pool-lease.js +49 -0
  302. package/dist/portal/pool/zero-install.d.ts +8 -1
  303. package/dist/portal/pool/zero-install.js +24 -2
  304. package/dist/portal/production/production-activation.d.ts +136 -0
  305. package/dist/portal/production/production-activation.js +173 -0
  306. package/dist/portal/production/production-drive.d.ts +52 -0
  307. package/dist/portal/production/production-drive.js +301 -0
  308. package/dist/portal/production/production-hello.d.ts +23 -0
  309. package/dist/portal/production/production-hello.js +23 -0
  310. package/dist/portal/realm/web-realm.js +42 -15
  311. package/dist/portal/session/control-envelope.d.ts +1 -1
  312. package/dist/portal/session/dev-server/served-document.d.ts +0 -5
  313. package/dist/portal/session/dev-server/served-document.js +6 -8
  314. package/dist/portal/session/facts/handshake-facts.d.ts +8 -1
  315. package/dist/portal/session/first-run-wiring.d.ts +3 -36
  316. package/dist/portal/session/first-run-wiring.js +10 -103
  317. package/dist/portal/session/live-control-tools.js +61 -19
  318. package/dist/portal/session/no-session-next-action.d.ts +11 -0
  319. package/dist/portal/session/no-session-next-action.js +40 -15
  320. package/dist/portal/session/no-session-watch.d.ts +7 -0
  321. package/dist/portal/session/no-session-watch.js +67 -23
  322. package/dist/portal/session/output-budget.d.ts +10 -0
  323. package/dist/portal/session/output-budget.js +16 -0
  324. package/dist/portal/session/presence/session-lease.d.ts +2 -0
  325. package/dist/portal/session/presence/session-lease.js +8 -0
  326. package/dist/portal/session/recorded-gaps.d.ts +15 -11
  327. package/dist/portal/session/recorded-gaps.js +39 -18
  328. package/dist/portal/session/serving-directory.d.ts +24 -2
  329. package/dist/portal/session/serving-directory.js +93 -5
  330. package/dist/portal/session/session-info.d.ts +26 -0
  331. package/dist/portal/session/session-info.js +20 -0
  332. package/dist/portal/session/session-manager.d.ts +35 -3
  333. package/dist/portal/session/session-manager.js +69 -14
  334. package/dist/portal/session/session-successor.js +1 -9
  335. package/dist/portal/session/session-tools.js +22 -4
  336. package/dist/portal/session/session.d.ts +10 -10
  337. package/dist/portal/session/session.js +37 -29
  338. package/dist/portal/session/zero-install-first-call.d.ts +7 -2
  339. package/dist/portal/session/zero-install-first-call.js +43 -20
  340. package/dist/start-wiring.d.ts +2 -2
  341. package/dist/start-wiring.js +17 -3
  342. package/dist/status-payload.d.ts +11 -1
  343. package/dist/status-payload.js +7 -1
  344. package/dist/surface/agent-presence-grace.d.ts +11 -0
  345. package/dist/surface/agent-presence-grace.js +34 -0
  346. package/dist/surface/http-server.d.ts +12 -1
  347. package/dist/surface/http-server.js +64 -15
  348. package/dist/surface/mcp/faults/mcp-outage.d.ts +12 -2
  349. package/dist/surface/mcp/faults/mcp-outage.js +19 -1
  350. package/dist/surface/mcp/mcp-proxy.d.ts +17 -74
  351. package/dist/surface/mcp/mcp-proxy.js +194 -267
  352. package/dist/surface/mcp/mcp.d.ts +20 -3
  353. package/dist/surface/mcp/mcp.js +88 -25
  354. package/dist/surface/mcp/proxy/drive-calls.d.ts +44 -0
  355. package/dist/surface/mcp/proxy/drive-calls.js +114 -5
  356. package/dist/surface/mcp/proxy/proxy-boot.d.ts +11 -0
  357. package/dist/surface/mcp/proxy/proxy-boot.js +1 -0
  358. package/dist/surface/mcp/proxy/proxy-daemon-probe.d.ts +6 -0
  359. package/dist/surface/mcp/proxy/proxy-daemon-probe.js +14 -1
  360. package/dist/surface/mcp/proxy/proxy-handshake.d.ts +34 -2
  361. package/dist/surface/mcp/proxy/proxy-handshake.js +76 -8
  362. package/dist/surface/mcp/server-instructions.js +35 -16
  363. package/dist/surface/mcp/shared-params.d.ts +8 -0
  364. package/dist/surface/mcp/shared-params.js +15 -1
  365. package/dist/surface/mcp/sse-frame-parser.d.ts +11 -0
  366. package/dist/surface/mcp/sse-frame-parser.js +18 -0
  367. package/dist/surface/mcp/surface-vocabulary.d.ts +2 -0
  368. package/dist/surface/mcp/surface-vocabulary.js +13 -0
  369. package/dist/surface/mcp/tool-catalog-cache.d.ts +2 -0
  370. package/dist/surface/mcp/tool-catalog-cache.js +14 -4
  371. package/dist/surface/tools/account-tool.d.ts +4 -3
  372. package/dist/surface/tools/account-tool.js +20 -31
  373. package/dist/surface/tools/act/act-danger.d.ts +2 -0
  374. package/dist/surface/tools/act/act-danger.js +41 -14
  375. package/dist/surface/tools/act/act-observation.d.ts +11 -0
  376. package/dist/surface/tools/act/act-observation.js +33 -0
  377. package/dist/surface/tools/act/act-preflight.js +10 -3
  378. package/dist/surface/tools/act/act-sequence-retry.js +2 -1
  379. package/dist/surface/tools/act/act-target.js +19 -5
  380. package/dist/surface/tools/act/durable.js +1 -1
  381. package/dist/surface/tools/act/navigation/navigate-arrival.d.ts +9 -7
  382. package/dist/surface/tools/act/navigation/navigate-arrival.js +11 -14
  383. package/dist/surface/tools/act/unsettled-find.d.ts +36 -0
  384. package/dist/surface/tools/act/unsettled-find.js +71 -0
  385. package/dist/surface/tools/act-sequence-tool.js +53 -24
  386. package/dist/surface/tools/act-tools.d.ts +2 -3
  387. package/dist/surface/tools/act-tools.js +49 -47
  388. package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
  389. package/dist/surface/tools/agent/for-the-agent.js +41 -3
  390. package/dist/surface/tools/assert/assert-grade.js +8 -3
  391. package/dist/surface/tools/assert/assert-verdict.js +4 -2
  392. package/dist/surface/tools/browser-tools.js +7 -4
  393. package/dist/surface/tools/chat-drives.js +50 -25
  394. package/dist/surface/tools/coverage-tools.js +1 -1
  395. package/dist/surface/tools/dynamic-tools.d.ts +8 -0
  396. package/dist/surface/tools/dynamic-tools.js +89 -34
  397. package/dist/surface/tools/empty-session-list.d.ts +18 -25
  398. package/dist/surface/tools/empty-session-list.js +67 -38
  399. package/dist/surface/tools/error-recovery.d.ts +17 -7
  400. package/dist/surface/tools/error-recovery.js +53 -20
  401. package/dist/surface/tools/explore-tools.d.ts +10 -0
  402. package/dist/surface/tools/explore-tools.js +72 -19
  403. package/dist/surface/tools/feedback-tools.js +23 -2
  404. package/dist/surface/tools/gap-novelty.d.ts +6 -0
  405. package/dist/surface/tools/gap-novelty.js +9 -0
  406. package/dist/surface/tools/gaps/capability-absences.js +4 -3
  407. package/dist/surface/tools/harness-explore.d.ts +1 -1
  408. package/dist/surface/tools/harness-explore.js +6 -4
  409. package/dist/surface/tools/harness-gate.d.ts +43 -21
  410. package/dist/surface/tools/harness-gate.js +55 -81
  411. package/dist/surface/tools/harness-script.d.ts +2 -0
  412. package/dist/surface/tools/harness-script.js +11 -6
  413. package/dist/surface/tools/harness-toolset.js +3 -4
  414. package/dist/surface/tools/invoke-tool.d.ts +0 -8
  415. package/dist/surface/tools/invoke-tool.js +164 -178
  416. package/dist/surface/tools/lease-hint.d.ts +9 -0
  417. package/dist/surface/tools/lease-hint.js +22 -3
  418. package/dist/surface/tools/lease-permissions.d.ts +1 -1
  419. package/dist/surface/tools/lease-readiness.d.ts +55 -0
  420. package/dist/surface/tools/lease-readiness.js +150 -2
  421. package/dist/surface/tools/lease-tools.d.ts +3 -75
  422. package/dist/surface/tools/lease-tools.js +124 -188
  423. package/dist/surface/tools/map-tools.d.ts +20 -0
  424. package/dist/surface/tools/map-tools.js +145 -0
  425. package/dist/surface/tools/merge-tools.js +11 -7
  426. package/dist/surface/tools/next-step.js +6 -3
  427. package/dist/surface/tools/observe-tools.js +46 -35
  428. package/dist/surface/tools/platform-moment.d.ts +3 -12
  429. package/dist/surface/tools/platform-moment.js +12 -24
  430. package/dist/surface/tools/read/complete-snapshot.d.ts +7 -1
  431. package/dist/surface/tools/read/complete-snapshot.js +13 -2
  432. package/dist/surface/tools/read/query-paginate.js +6 -0
  433. package/dist/surface/tools/read/query-shape.d.ts +9 -0
  434. package/dist/surface/tools/read/query-shape.js +15 -0
  435. package/dist/surface/tools/read/snapshot-unmounted-note.d.ts +1 -0
  436. package/dist/surface/tools/read/snapshot-unmounted-note.js +73 -0
  437. package/dist/surface/tools/read-tools.js +5 -5
  438. package/dist/surface/tools/real-input-attempt.d.ts +11 -0
  439. package/dist/surface/tools/real-input-attempt.js +206 -38
  440. package/dist/surface/tools/reconcile-tools.js +21 -8
  441. package/dist/surface/tools/reticle-result.d.ts +3 -0
  442. package/dist/surface/tools/reticle-result.js +8 -1
  443. package/dist/surface/tools/run-report.d.ts +22 -0
  444. package/dist/surface/tools/run-report.js +141 -0
  445. package/dist/surface/tools/session-ports.d.ts +57 -0
  446. package/dist/surface/tools/session-ports.js +102 -0
  447. package/dist/surface/tools/tool-kit.d.ts +58 -4
  448. package/dist/surface/tools/tool-kit.js +140 -6
  449. package/dist/surface/tools/tool-surface.d.ts +2 -0
  450. package/dist/surface/tools/tool-surface.js +45 -0
  451. package/dist/surface/tools/tools.js +49 -87
  452. package/dist/telemetry/automation-hint.d.ts +5 -0
  453. package/dist/telemetry/automation-hint.js +7 -0
  454. package/dist/telemetry/cli-telemetry.d.ts +22 -0
  455. package/dist/telemetry/cli-telemetry.js +80 -11
  456. package/dist/telemetry/daemon-telemetry.d.ts +3 -1
  457. package/dist/telemetry/daemon-telemetry.js +9 -2
  458. package/dist/telemetry/feedback-cli.d.ts +1 -1
  459. package/dist/telemetry/feedback-cli.js +8 -3
  460. package/dist/telemetry/feedback.d.ts +1 -1
  461. package/dist/telemetry/feedback.js +51 -4
  462. package/dist/telemetry/harness-run.d.ts +3 -3
  463. package/dist/telemetry/harness-run.js +18 -7
  464. package/dist/telemetry/hud-events.d.ts +1 -1
  465. package/dist/telemetry/hud-metrics.d.ts +6 -3
  466. package/dist/telemetry/hud-metrics.js +20 -8
  467. package/dist/telemetry/install-source.js +1 -1
  468. package/dist/telemetry/mcp-connection.d.ts +1 -1
  469. package/dist/telemetry/mcp-connection.js +21 -2
  470. package/dist/telemetry/onboarding-firsts.d.ts +6 -1
  471. package/dist/telemetry/onboarding-firsts.js +41 -1
  472. package/dist/telemetry/proxy-telemetry.d.ts +42 -0
  473. package/dist/telemetry/proxy-telemetry.js +70 -1
  474. package/dist/telemetry/session-metrics.d.ts +1 -3
  475. package/dist/telemetry/session-metrics.js +16 -12
  476. package/dist/telemetry/telemetry.d.ts +9 -1
  477. package/dist/telemetry/telemetry.js +16 -1
  478. package/dist/telemetry/verification-of.d.ts +3 -1
  479. package/dist/telemetry/verification-of.js +7 -1
  480. package/dist/wire-journal.js +12 -2
  481. package/docs/README.md +4 -2
  482. package/docs/actions.mdx +7 -6
  483. package/docs/adapters.md +2 -1
  484. package/docs/agent-cheatsheet.md +19 -5
  485. package/docs/architecture.md +13 -10
  486. package/docs/autodrive.md +6 -5
  487. package/docs/benchmarks.md +2 -2
  488. package/docs/capabilities.mdx +1 -1
  489. package/docs/cli/affected.mdx +1 -1
  490. package/docs/cli/cloud.mdx +6 -6
  491. package/docs/cli/doctor.mdx +3 -1
  492. package/docs/cli/feedback.mdx +11 -7
  493. package/docs/cli/gate.mdx +1 -1
  494. package/docs/cli/help.mdx +1 -1
  495. package/docs/cli/init.mdx +20 -16
  496. package/docs/cli/mcp.mdx +5 -2
  497. package/docs/cli/open.mdx +5 -2
  498. package/docs/cli/report.mdx +1 -1
  499. package/docs/cli/restart.mdx +1 -1
  500. package/docs/cli/rollback.mdx +4 -4
  501. package/docs/cli/serve.mdx +7 -5
  502. package/docs/cli/setup.mdx +1 -1
  503. package/docs/cli/status.mdx +6 -2
  504. package/docs/cli/stop.mdx +3 -3
  505. package/docs/cli/telemetry.mdx +5 -1
  506. package/docs/cli/try.mdx +8 -8
  507. package/docs/cli/update.mdx +8 -5
  508. package/docs/cli/verify.mdx +12 -5
  509. package/docs/cli/version.mdx +1 -1
  510. package/docs/cli.mdx +10 -6
  511. package/docs/debugging.md +1 -1
  512. package/docs/deploy-checks.md +8 -6
  513. package/docs/desktop.mdx +14 -18
  514. package/docs/enterprise.md +6 -6
  515. package/docs/environment.mdx +5 -3
  516. package/docs/faq.mdx +9 -6
  517. package/docs/first-drive.md +19 -9
  518. package/docs/flows.md +3 -4
  519. package/docs/for-agents.md +1 -1
  520. package/docs/frameworks.mdx +34 -11
  521. package/docs/getting-started.md +46 -29
  522. package/docs/http-transport.md +2 -2
  523. package/docs/human-control.md +8 -8
  524. package/docs/index.mdx +2 -2
  525. package/docs/install-agentic.mdx +18 -19
  526. package/docs/install-manual.mdx +8 -4
  527. package/docs/integration-patterns.md +5 -5
  528. package/docs/multi-agent-testing.md +7 -5
  529. package/docs/packages/browser.mdx +34 -2
  530. package/docs/packages/core.mdx +2 -1
  531. package/docs/packages/electron.mdx +15 -3
  532. package/docs/packages/eslint-plugin.mdx +1 -1
  533. package/docs/packages/next.mdx +17 -5
  534. package/docs/packages/react.mdx +8 -1
  535. package/docs/packages/server.mdx +3 -3
  536. package/docs/packages/tauri.mdx +3 -3
  537. package/docs/packages/vite-plugin.mdx +1 -1
  538. package/docs/packages.mdx +19 -6
  539. package/docs/platform-integration.md +12 -4
  540. package/docs/predicates.mdx +18 -7
  541. package/docs/production-mode.md +108 -0
  542. package/docs/prompt-capture.md +99 -0
  543. package/docs/quickstart.mdx +14 -12
  544. package/docs/recipes.mdx +9 -8
  545. package/docs/required-checks.md +3 -2
  546. package/docs/skill-file.mdx +4 -3
  547. package/docs/skill-setup.md +2 -2
  548. package/docs/skill.md +62 -70
  549. package/docs/state-files.md +1 -0
  550. package/docs/state-management.mdx +11 -9
  551. package/docs/system-map.md +14 -13
  552. package/docs/telemetry.md +32 -24
  553. package/docs/testing.md +9 -5
  554. package/docs/tools/act-and-wait.mdx +17 -13
  555. package/docs/tools/act-sequence.mdx +40 -66
  556. package/docs/tools/act.mdx +7 -5
  557. package/docs/tools/assert.mdx +1 -1
  558. package/docs/tools/look.mdx +1 -1
  559. package/docs/tools/navigate.mdx +1 -1
  560. package/docs/tools/network.mdx +13 -11
  561. package/docs/tools/overview.mdx +3 -3
  562. package/docs/tools/query.mdx +3 -3
  563. package/docs/tools/session-and-feedback.mdx +9 -6
  564. package/docs/tools/sessions.mdx +7 -0
  565. package/docs/tools/snapshot.mdx +9 -7
  566. package/docs/tools/tools-and-run.mdx +11 -10
  567. package/docs/tools/verify.mdx +1 -1
  568. package/docs/troubleshooting.mdx +21 -9
  569. package/docs/usage.md +58 -43
  570. package/docs/use-cases.mdx +2 -2
  571. package/docs/vs-chrome-devtools-mcp.mdx +5 -5
  572. package/docs/vs-playwright-mcp.mdx +5 -4
  573. package/docs/what-is-recorded.md +12 -7
  574. package/docs/what-is-reticle.mdx +2 -2
  575. package/docs/why-reticle.mdx +1 -1
  576. package/package.json +9 -12
  577. package/dist/command/dev/stale-issue-guard.d.ts +0 -34
  578. package/dist/command/dev/stale-issue-guard.js +0 -69
@@ -12,7 +12,7 @@ icon: cube
12
12
 
13
13
  Without one shared definition the browser and the server drift. One side renames a field, the other keeps reading the old one, and the failure is silent: a verdict that quietly stops carrying its evidence. Core makes that a type error instead.
14
14
 
15
- The narrow dependency list is the point. `open-verification` itself depends on `zod` alone, so the graph stays acyclic: everything can depend on core, and nothing core does can drag a filesystem call into the browser bundle. This page said "depends on `zod` and nothing else" until v3 extracted the protocol and nobody updated the sentence.
15
+ The narrow dependency list is the point. `open-verification` itself depends on `zod` alone, so the graph stays acyclic: everything can depend on core, and nothing core does can drag a filesystem call into the browser bundle.
16
16
 
17
17
  ## Do you install it?
18
18
 
@@ -32,6 +32,7 @@ npm i @reticlehq/core
32
32
  | `./hooks` | What Reticle says happened, for hook consumers |
33
33
  | `./hud` | Constants shared by the daemon and the HUD panel |
34
34
  | `./tour` | The onboarding tour |
35
+ | `./activation` | The signed activation ticket: `signActivationTicket` for the service that makes tickets, `verifyActivationTicket` for the page loader. See [Production mode](/production-mode) |
35
36
  | `./desktop-contract` | A CommonJS shim, generated at build, for the strings the desktop adapters share |
36
37
  | `./source-constants` | A CommonJS shim, generated at build, for the source-stamp constants the build adapters share |
37
38
  | `./schema/*.json` | Generated JSON Schema for the wire types |
@@ -73,13 +73,25 @@ The handler calls `webContents.capturePage()`, writes the PNG into a per-process
73
73
 
74
74
  ## Renderer wiring
75
75
 
76
- The renderer still needs the SDK. A packaged app is a production build, so the connect call has to opt in:
76
+ The renderer still needs the SDK. Connect only in development, never in the app you ship. For example, send `!app.isPackaged` from the main process to the renderer, and connect only when it is true. An Electron renderer reports `NODE_ENV=production`, so the call also needs `allowInProduction`:
77
77
 
78
78
  ```ts
79
- reticle.connect({ allowInProduction: true });
79
+ import { reticle } from '@reticlehq/browser';
80
+
81
+ // isDevelopment is `!app.isPackaged`, sent from the main process.
82
+ if (isDevelopment) {
83
+ // reticle.local.js holds this machine's pairing token. Do not commit it.
84
+ import('./reticle.local.js')
85
+ .catch(() => ({}))
86
+ .then((local) => reticle.connect({ allowInProduction: true, token: local.token }));
87
+ }
80
88
  ```
81
89
 
82
- Or, with the Vite plugin, `reticle({ desktop: true })`.
90
+ The bridge refuses a connect without the pairing token, also from a `file://` page. For an Electron app without the Vite plugin, `reticle init` does not write `reticle.local.js`. Make it from `~/.reticle/pairing-token` as the [browser page](/packages/browser) shows, and add it to `.gitignore`.
91
+
92
+ Keep `reticle.local.js` out of the package: electron-builder `files: ["!reticle.local.js"]`, or Electron Forge `packagerConfig.ignore: [/reticle\.local\.js$/]`.
93
+
94
+ With the Vite plugin, use `reticle({ desktop: true })` instead. The plugin passes the token and `allowInProduction`, and a production-mode build ships no Reticle code.
83
95
 
84
96
  <Card title="Desktop setup in full" icon="display" href="/desktop">
85
97
  Electron and Tauri wiring, and what `reticle doctor` checks for each.
@@ -4,7 +4,7 @@ description: Three lint rules that keep Reticle's signal layer and its comment h
4
4
  icon: shield-check
5
5
  ---
6
6
 
7
- `@reticlehq/eslint-plugin` is three ESLint rules that keep Reticle's signal layer and its comments self-enforcing. It is entirely optional: nothing in Reticle needs it, and you want it only once your app emits signals and you would like the compiler to notice when a new mutation forgets one.
7
+ `@reticlehq/eslint-plugin` is three ESLint rules that keep Reticle's signal layer and its comments self-enforcing. It is entirely optional: nothing in Reticle needs it, and you want it only once your app emits signals and you want the linter to tell you when a new mutation has no signal.
8
8
 
9
9
  It exists because conventions rot. Someone adds a mutation, forgets the signal, and every verdict for that flow quietly drops a grade. Nothing breaks, the tests still pass, the evidence just gets weaker. A lint rule is the only way a convention survives contact with a deadline.
10
10
 
@@ -70,24 +70,36 @@ An async webpack loader. It skips anything that is not `.jsx`, `.tsx` or a `.js`
70
70
 
71
71
  ## What it does not do
72
72
 
73
- It does not inject `connect()`. On Next you call it yourself, once, in a client component:
73
+ It does not inject `connect()`. On Next you call it once, in a client component that your root layout renders. `reticle init` writes this component for you at `app/reticle-dev.tsx` (or `src/app/reticle-dev.tsx`). To write it by hand:
74
74
 
75
75
  ```tsx
76
76
  'use client';
77
77
  import { useEffect } from 'react';
78
- import { reticle, install } from '@reticlehq/react';
79
78
 
80
79
  export function ReticleDev() {
81
80
  useEffect(() => {
82
- if (process.env.NODE_ENV !== 'production') {
81
+ if (process.env.NODE_ENV !== 'development') return;
82
+ void import('@reticlehq/react').then(({ reticle, install }) => {
83
83
  install();
84
- reticle.connect();
85
- }
84
+ // withReticle() in next.config sets these. The bridge refuses a connect without the token.
85
+ const token = process.env.NEXT_PUBLIC_RETICLE_TOKEN;
86
+ const url = process.env.NEXT_PUBLIC_RETICLE_URL;
87
+ const root = process.env.NEXT_PUBLIC_RETICLE_ROOT;
88
+ const sdkVersion = process.env.NEXT_PUBLIC_RETICLE_SDK_VERSION;
89
+ reticle.connect({
90
+ ...(url ? { url } : {}),
91
+ ...(token ? { token } : {}),
92
+ ...(root ? { root } : {}),
93
+ ...(sdkVersion ? { sdkVersion } : {}),
94
+ });
95
+ });
86
96
  }, []);
87
97
  return null;
88
98
  }
89
99
  ```
90
100
 
101
+ `NEXT_PUBLIC_RETICLE_TOKEN` is empty when the daemon has not yet written `~/.reticle/pairing-token`. Start the daemon, then restart `next dev`.
102
+
91
103
  <Card title="Framework by framework" icon="layer-group" href="/frameworks">
92
104
  What each supported stack needs, and what it gets for free.
93
105
  </Card>
@@ -22,10 +22,16 @@ npm i -D @reticlehq/react
22
22
 
23
23
  ```ts
24
24
  import { reticle, install } from '@reticlehq/react';
25
+
25
26
  install();
26
- reticle.connect();
27
+ // reticle.local.js holds this machine's pairing token. Do not commit it.
28
+ import('./reticle.local.js')
29
+ .catch(() => ({}))
30
+ .then((local) => reticle.connect({ token: local.token }));
27
31
  ```
28
32
 
33
+ The bridge refuses a connect without the pairing token, also on localhost. `reticle init` writes `reticle.local.js` and adds it to `.gitignore`. Without init, make it from `~/.reticle/pairing-token` as the [browser page](/packages/browser) shows.
34
+
29
35
  ## Exports
30
36
 
31
37
  ### Setup
@@ -72,6 +78,7 @@ The [Vite plugin](/packages/vite-plugin) injects `install()` and `reticle.connec
72
78
  One export, and the only module in the package that imports React:
73
79
 
74
80
  ```ts
81
+ import { useState } from 'react';
75
82
  import { useReticleStore } from '@reticlehq/react/store';
76
83
 
77
84
  function Cart() {
@@ -20,13 +20,13 @@ Not into your project. Your agent launches it:
20
20
  npx @reticlehq/server mcp
21
21
  ```
22
22
 
23
- The `bin` entry is `reticle`, so `npx @reticlehq/server <command>` works once it is on disk.
23
+ The `bin` entry is `reticle`. Run any command as `npx @reticlehq/server <command>`, or as `reticle <command>` after the one-line installer puts the package on your machine.
24
24
 
25
25
  ## Dependencies
26
26
 
27
27
  **Runtime:** `@modelcontextprotocol/sdk`, `@reticlehq/browser`, `@reticlehq/core`, `@reticlehq/engine`, `@reticlehq/init`, `open-verification`, `ws`, `zod`, `zod-to-json-schema`.
28
28
 
29
- **Optional:** `playwright` (also a peer dependency, `>=1.50`), `pixelmatch`, `pngjs`. Optional on purpose: Reticle observes the browser you already have. You only need Playwright for the paths that launch or diff one, which is `reticle drive`, `reticle verify`, and visual baselines.
29
+ **Optional:** `playwright` (also a peer dependency, `>=1.50`), `pixelmatch`, `pngjs`. Optional on purpose: Reticle observes the browser you already have. You need Playwright only for the paths that launch or compare a browser: the zero-install lease, `reticle try`, `reticle drive`, `reticle verify` and visual baselines. `reticle open` uses your own browser and does not need it.
30
30
 
31
31
  ## Exports map
32
32
 
@@ -71,7 +71,7 @@ await server.close();
71
71
 
72
72
  ### `RunningServer`
73
73
 
74
- `bridge: Bridge`, `close(): Promise<void>`, and the optional `realInput`, `verifyPort`, `isIdle()`, `agentAttached()`, `token`, `announceShutdown()`.
74
+ `bridge: Bridge`, `close(): Promise<void>`, and the optional `realInput`, `verifyPort`, `isIdle()`, `agentAttached()`, `token`, `announceShutdown()` and `onShutdownRequest(handler)`. The last one runs `handler` when an authenticated `POST /shutdown` asks the daemon to stop.
75
75
 
76
76
  ## What else the barrel exports
77
77
 
@@ -6,7 +6,7 @@ icon: rust
6
6
 
7
7
  `reticle-tauri` is a Rust crate on crates.io, not an npm package. You need it only if your Tauri app should answer `reticle_screenshot`, or run headless in CI. Everything else about a Tauri app, including IPC observation, works without it.
8
8
 
9
- It is versioned in **lockstep** with the `@reticlehq/*` npm packages, so `3.7` here and there is the same release. **MIT licensed, unlike the npm packages. Edition 2021.**
9
+ It is versioned in **lockstep** with the `@reticlehq/*` npm packages, so `3.8` here and `3.8` on npm is the same release. **MIT licensed, unlike the npm packages. Edition 2021.**
10
10
 
11
11
  ## Why it exists, and why it is small
12
12
 
@@ -16,7 +16,7 @@ Tauri IPC observation needs nothing on the Rust side. An `invoke('load_todos')`
16
16
 
17
17
  ```toml
18
18
  [dependencies]
19
- reticle-tauri = "3.7"
19
+ reticle-tauri = "3.8"
20
20
  ```
21
21
 
22
22
  Its own dependencies are `tauri = "2.12"` (the Windows backend must use the same `webview2-com` and `windows` versions Tauri does, so it follows Tauri's minor version) plus the per-platform capture backends: `objc2` and friends on macOS, `webview2-com` and `windows` on Windows, `webkit2gtk` and `cairo-rs` on Linux and the BSDs.
@@ -29,7 +29,7 @@ tauri::Builder::default()
29
29
  .on_page_load(reticle_tauri::on_page_load)
30
30
  ```
31
31
 
32
- **Dev builds only.** In a release build the crate is inert: `reticle_capture` refuses and `on_page_load` does nothing, so the binary you sign and ship carries no Reticle capability. A release build you test with Reticle (a CI fixture) turns it on with `reticle-tauri = { version = "3.7", features = ["in-release"] }`.
32
+ **Dev builds only.** In a release build the crate is inert: `reticle_capture` refuses and `on_page_load` does nothing, so the binary you sign and ship carries no Reticle capability. A release build you test with Reticle (a CI fixture) turns it on with `reticle-tauri = { version = "3.8", features = ["in-release"] }`.
33
33
 
34
34
  Nothing is needed on the JavaScript side. Tauri has no preload stage, so the SDK reaches `reticle_capture` through Tauri's own internals.
35
35
 
@@ -73,7 +73,7 @@ Plus a dynamic import of your dev module if one exists. It looks for `src/reticl
73
73
  | `captureErrorBodies` | `boolean` | `true`: a failed response keeps its body. `VITE_RETICLE_NO_ERROR_BODIES=1` turns it off |
74
74
  | `testIdAttribute` | `string` | `.reticle.json`'s `testIdAttribute`, else `data-testid` |
75
75
  | `allowNonLocalhost` | `boolean` | `false`. Lets Reticle run off localhost; a pairing token is still required. Also `VITE_RETICLE_ALLOW_NON_LOCALHOST=1` |
76
- | `exposePresenter` | `boolean` | `false`. Contributors only: makes Reticle's own presenter visible to its tools |
76
+ | `exposePresenter` | `boolean` | `false`. Contributors only: makes Reticle's own presenter visible to its tools. Also `VITE_RETICLE_EXPOSE_PRESENTER=1` |
77
77
  | `onWarn` | `(message: string) => void` | `console.warn` |
78
78
 
79
79
  `reticle({ present: false })` still lets the plugin create and configure the connection; it only hides Reticle's visible presenter. `reticle({ inject: false })` disables that generated connection, so your application must call `connect()` itself. In that manual call, pass the pairing token explicitly:
package/docs/packages.mdx CHANGED
@@ -33,7 +33,7 @@ It was versioned independently until 2.12.0, and that turned out to mean _stuck_
33
33
  </Card>
34
34
  </CardGroup>
35
35
 
36
- You never install `@reticlehq/server`. Your agent runs it with `npx`.
36
+ You never add `@reticlehq/server` to your project. The one-line installer puts it on your machine, or your agent runs it with `npx`.
37
37
 
38
38
  ## The architecture in one rule
39
39
 
@@ -79,7 +79,20 @@ Those rules are why the browser SDK cannot accidentally pull in a filesystem cal
79
79
 
80
80
  ```ts
81
81
  import { reticle } from '@reticlehq/browser';
82
- if (import.meta.env.DEV) reticle.connect();
82
+
83
+ if (import.meta.env.DEV) {
84
+ // reticle.local.js holds this machine's pairing token. Do not commit it.
85
+ import('./reticle.local.js')
86
+ .catch(() => ({}))
87
+ .then((local) => reticle.connect({ token: local.token }));
88
+ }
89
+ ```
90
+
91
+ The bridge refuses a connect without the pairing token, also on localhost. `reticle init` writes `reticle.local.js` at the project root and adds it to `.gitignore`. Change the import path so that it points to that file. If you did not run `reticle init`, make the file yourself from the token that the daemon keeps in `~/.reticle/pairing-token`:
92
+
93
+ ```bash
94
+ printf "export const token = '%s';\n" "$(cat ~/.reticle/pairing-token)" > reticle.local.js
95
+ echo reticle.local.js >> .gitignore
83
96
  ```
84
97
 
85
98
  ---
@@ -178,7 +191,7 @@ module.exports = withReticle({/* your config */});
178
191
 
179
192
  ## open-verification
180
193
 
181
- **The specification, as a package.** The vocabulary a verification is described in (subject, channel, intent, claim, window, observation, evidence, coverage, verdict), plus `Realm`, the interface an implementation answers, and `adjudicate()`, the function that turns evidence into a verdict. It ships `SPEC.md`, a JSON Schema for every noun, and a conformance suite that scores an implementation against the rules.
194
+ **The specification, as a package.** The vocabulary a verification is described in (subject, channel, intent, claim, window, observation, evidence, coverage, verdict), plus `Realm`, the interface an implementation answers, and `adjudicate()`, the function that turns evidence into a verdict. It ships `SPEC.md`, a JSON Schema for every noun, and test vectors that a second implementation can check itself against.
182
195
 
183
196
  **Why it exists:** Reticle's rules about what may buy a green were real and were scattered. The independence rule lived in a channel table, the four verdict values in an enum, the blind-spot idea in a coverage type, and nothing said they were one contract that something other than Reticle could implement. You do not need this package to use Reticle. You need it to write something else that can be checked the same way, or to check what Reticle's verdicts actually mean.
184
197
 
@@ -200,7 +213,7 @@ module.exports = withReticle({/* your config */});
200
213
 
201
214
  **The spec runner for CI.** `reticleTest` registers declarative specs and runs them against Reticle's tools directly, with no MCP or stdio in the loop.
202
215
 
203
- **Why it exists:** driving interactively is reconnaissance. At some point you want the same checks to run on every pull request without an agent. And without paying model tokens to re-derive them.
216
+ **Why it exists:** driving interactively is reconnaissance. At some point you want the same checks to run on every pull request, without an agent and without paying model tokens to derive them again.
204
217
 
205
218
  **Depends on:** `@reticlehq/core`, `@reticlehq/server`. **Peer:** `vitest`.
206
219
 
@@ -234,13 +247,13 @@ A lint rule makes the signal layer self-enforcing, which is the only way a conve
234
247
 
235
248
  ## reticle-tauri
236
249
 
237
- **The Rust crate**, on crates.io. Versioned in lockstep with the npm packages, so `3.7` here and `3.7` there mean the same release.
250
+ **The Rust crate**, on crates.io. Versioned in lockstep with the npm packages, so `3.8` here and `3.8` there mean the same release.
238
251
 
239
252
  **Why it exists:** Tauri IPC observation needs nothing on the Rust side; an `invoke('load_todos')` already reaches Reticle as `ipc://load_todos`. You only need this crate for screenshots and headless mode.
240
253
 
241
254
  ```toml
242
255
  [dependencies]
243
- reticle-tauri = "3.7"
256
+ reticle-tauri = "3.8"
244
257
  ```
245
258
 
246
259
  <Card title="Desktop setup in full" icon="display" href="/desktop">
@@ -33,7 +33,7 @@ curl -fsSL https://raw.githubusercontent.com/reticlehq/reticle/main/install/inst
33
33
  irm https://raw.githubusercontent.com/reticlehq/reticle/main/install/install.ps1 | iex # Windows
34
34
  ```
35
35
 
36
- It puts the CLI on the machine and registers the MCP server with the coding agents it finds. Then do what it prints: restart your coding agent so it loads Reticle's tools, and paste the prompt the script prints into it. The agent runs `reticle init` in your app (build plugin, SDK connect file, agent rules), then proves one flow. No agent? Run `reticle init` in the app yourself.
36
+ It puts the CLI on the machine and registers the MCP server with the coding agents it finds. Then do what it prints: restart your coding agent so it loads Reticle's tools, and paste the prompt the script prints into it. To teach the agent the workflow, also add the skill: `npx skills add reticlehq/reticle --skill reticle`. The agent runs `reticle init` in your app (build plugin, SDK connect file, agent rules), then proves one flow. No agent? Run `reticle init` in the app yourself.
37
37
 
38
38
  ### B. A platform / CI, driven from your pipeline (no MCP, no human)
39
39
 
@@ -56,7 +56,7 @@ const { run } = await (
56
56
  if (run.verdict.status !== 'pass') {
57
57
  for (const p of run.repair?.failurePackets ?? []) fixerAgent.send(p.suggestedPrompt); // self-heal
58
58
  blockDeploy(run);
59
- } else attachToDeploy(run); // "verified ✓"; set profile:"prod-preview" to redact internals downstream
59
+ } else attachToDeploy(run); // "verified ✓". POST /verify redacts internals by default (profile "prod-preview"); pass profile:"dev" for the full run.
60
60
  ```
61
61
 
62
62
  Or skip the HTTP server entirely with the one-shot CLI: `reticle verify <preview-url>` drives the preview, replays the saved flows, prints the verdict, and exits non-zero on fail (ideal for a CI step).
@@ -90,7 +90,7 @@ Copyable patterns: `apps/bench-app/src/reticle-dev.ts`, `apps/next-smoke/app/ret
90
90
  | UI-vs-store desync (the total lies) | reads the store, contradicts the display |
91
91
  | Blast-radius (an action corrupts unrelated state) | a `state { path, equals }` invariant on the unrelated value |
92
92
 
93
- Live, clickable demo of each: `apps/vibe-builder-demo/` (set `BUG_MODE=…`). Proven in CI: `server/src/judgement/runs/generated-app-bugs.test.ts`.
93
+ Proven in CI: `server/src/judgement/runs/generated-app-bugs.test.ts`.
94
94
 
95
95
  ---
96
96
 
@@ -140,10 +140,18 @@ The shape is identical (in-app SDK in the template → verify in the sandbox →
140
140
 
141
141
  ## The verdict artifact
142
142
 
143
- `POST /verify` (and `reticle_run_export`) return a stable, versioned `ReticleVerificationRun` (defined in `@reticlehq/core`): `verdict` (pass/fail/partial, confidence, blockingRisks), `flows[]`, `checks[]`, `risks[]` (auth/payment/db/…), `repair.failurePackets[]` (what + where to fix), `evidence`. Render a legible report with `renderRunReport()` or `reticle_run_export { format: "report" }`. Profiles: `dev` (full) vs `prod-preview` (source + state redacted for downstream sharing).
143
+ `POST /verify` (and `reticle_run_export`) return a stable, versioned `ReticleVerificationRun` (defined in `@reticlehq/core`): `verdict` (pass/fail/partial, confidence, blockingRisks), `flows[]`, `checks[]`, `risks[]` (auth/payment/db/…), `repair.failurePackets[]` (what + where to fix), `evidence`. Render a legible report with `renderRunReport()` or `reticle_run({ tool: "reticle_run_export", args: { format: "report" } })`. Profiles: `dev` (full) and `prod-preview` (source and state redacted for sharing). `POST /verify` uses `prod-preview` unless you pass `profile: "dev"`.
144
144
 
145
145
  **Why trust it:** the verdict is mechanical, derived only from observed outcomes, so it can't report green for something it never ran (a severed backend reads as _fail_, never a confident pass). Proof: `server/src/judgement/runs/false-green.test.ts`.
146
146
 
147
+ ## Building a hosted verifier on the engine
148
+
149
+ A service that drives apps it did not build uses these seams.
150
+
151
+ - **Follow a drive to another origin.** `new Bridge({ ..., followNavigation })` lets a session continue on an origin the bridge was not built with. A page on a new origin can only continue a session the bridge already admitted, after the token or nonce check, and only when `followNavigation({ sessionId, from, to, url })` returns `true`. Return `true` only when your own browser's top frame is now on `to`. Without the option, nothing changes.
152
+ - **Refuse `clean` over what the engine could not see.** Every `reticle_act_and_wait` and `reticle_assert` result carries `engineBlindSpots`: what this engine could not observe in the session so far. It is cumulative, so the last verdict result of a run is the run's list, and `[]` means none. `pixels-unobserved`: an action ran while a `<canvas>` was visible, and no canvas digest is recorded. `claim-arithmetic-unchecked`: a claim under test (the call's `intent`, or an intent declared in the run) states an amount, and no verdict ran a `compare`. Do not call a run clean while its list has an entry. The kinds and the schema are `EngineBlindSpotKind` and `EngineBlindSpotSchema` in `@reticlehq/core`.
153
+ - **Say that you injected the SDK.** When your init script connects the SDK into a page that does not import it, call `reticle.connect({ ..., injected: true })`. The HELLO then carries `instrumentation: "injected"`, `Session.instrumentation` holds it, and the session listing shows it. Do not count such a session as an app with the SDK installed: signals, module-scope stores and file:line still need the app. To read React component state and provider-passed stores (Redux, TanStack Query) on such a page, bundle `install()` from `@reticlehq/react` into the same init script and call it before `connect`. That entry imports only `@reticlehq/browser` and `@reticlehq/core` at runtime, so the bundle holds no copy of React.
154
+
147
155
  ## Licensing for embedding
148
156
 
149
157
  The embeddable SDK is **Apache-2.0** (ship it in your customers' apps). The server/CLI is **FSL** (free, no competing resale). Enterprise features + the premium-access flow: [`enterprise.md`](./enterprise.md). OEM terms: **[hey@reticle.sh](mailto:hey@reticle.sh)**.
@@ -71,7 +71,13 @@ Add `"absent": true` to assert something is **gone**. The predicate for a remova
71
71
  { "kind": "text", "contains": "Saved successfully", "visible": true }
72
72
  ```
73
73
 
74
- `contains` is the field the published schema declares. `value`, `text` and `query` are accepted as aliases and rewritten to it. The match is case-sensitive; `ignoreCase: true` relaxes that. `absent: true` asserts the text is not present, and `visible: true` requires it to be on screen rather than merely in the DOM.
74
+ `contains` is the field the published schema declares. `value`, `text` and `query` are accepted as aliases and rewritten to it. The match is case-sensitive. `ignoreCase: true` relaxes that. Curly quotes (`‘ ’ “ ”`), the en dash and the em dash match their plain forms. So `It's saved - done` matches a page that shows `It’s saved – done`. Text that Reticle reports back keeps the page's own characters. `absent: true` asserts the text is not present, and `visible: true` requires it to be on screen rather than merely in the DOM.
75
+
76
+ `text` reads the text that the page renders. It does not read what is typed into an `<input>` or a `<textarea>`, because that is the field's value, not text on the page. `value` on a `text` predicate is only an alias for `contains`, so it also reads rendered text. To assert what a field holds, use an `element` predicate with `value`:
77
+
78
+ ```json
79
+ { "kind": "element", "query": { "role": "textbox", "name": "Notes", "value": "Ship on Friday" } }
80
+ ```
75
81
 
76
82
  Use `scope` to restrict the search to a CSS selector or element ref. If Reticle reports that the text is split across the scope's children, retry its generated predicate with `"self": true`; that checks the scope root's combined subtree text while still enforcing `contains`.
77
83
 
@@ -178,7 +184,7 @@ A passing route verdict quotes the transition itself:
178
184
  { "kind": "signal", "name": "webhook:received", "dataMatches": { "provider": "stripe", "id": "*" } }
179
185
  ```
180
186
 
181
- The app emitted a named signal via `reticle.signal()`. `dataMatches` matches field by field, a key can be a dotted path (`"order.total"`), and `*` means "present, any value".
187
+ The app emitted a named signal via `reticle.signal()`. `dataMatches` matches field by field, a key can be a dotted path (`"order.total"`), and `*` means "present, any value". Without `name`, the check matches any signal from the app. It ignores Reticle's own signals, such as `reticle:busy`. To match one of those, name it.
182
188
 
183
189
  `count` works here exactly as it does on `net`:
184
190
 
@@ -186,7 +192,7 @@ The app emitted a named signal via `reticle.signal()`. `dataMatches` matches fie
186
192
  { "kind": "signal", "name": "order:placed", "count": 1 }
187
193
  ```
188
194
 
189
- **Exactly once.** A handler wired twice fires the signal twice and leaves the store in the right shape either way, so every state-only check stays green. `count: 0` is a claim of its own (the signal never fired) and is not the same as leaving `count` out, which asserts presence.
195
+ **Exactly once.** A handler wired twice fires the signal twice and leaves the store in the right shape either way, so every state-only check stays green. `count` is exact on `signal` and on `net`. Leave it out to ask for at least one. `count: 0` means never, and Reticle holds it like every other absence: for at least one second, and until the page goes quiet. A signal or a request that comes late still fails it.
190
196
 
191
197
  Nothing outranks this. A `200` proves the server was reachable; a rendered row proves React ran. A signal is the application itself saying the thing succeeded. See [instrumentation](/instrumentation) for how to emit them.
192
198
 
@@ -219,7 +225,7 @@ Omit `equals` entirely to assert presence. A real `$length` check against this f
219
225
  }
220
226
  ```
221
227
 
222
- Note `grade: state` in the `because` line, and that the evidence collapses each row to a size marker rather than returning forty objects.
228
+ The `because` line names the grade ("at state grade"). The evidence shows each row as a size marker, not as forty objects.
223
229
 
224
230
  #### satisfies: asserting a property instead of exact bytes
225
231
 
@@ -318,7 +324,12 @@ This is the predicate that catches a UI-versus-store desync. A deploy that only
318
324
  { "kind": "settled", "quietMs": 500 }
319
325
  ```
320
326
 
321
- Network and DOM idle. This is the deterministic replacement for a fixed sleep, not a proof of anything: combine it with a real consequence rather than asserting it alone. Omitting `until` on [`reticle_act_and_wait`](/tools/act-and-wait) waits for exactly this.
327
+ The page is quiet: no request in flight, no response body still streaming, no work that the app declared with `reticle.busy()` still pending, and no network or DOM activity for `quietMs` (default 500). This is the deterministic replacement for a fixed sleep, not a proof of anything. Combine it with a real consequence. Do not assert it alone. If you omit `until` on [`reticle_act_and_wait`](/tools/act-and-wait), it waits for exactly this.
328
+
329
+ `channel` changes what counts as activity:
330
+
331
+ - `"network"`: requests only. No request in flight, and no request completed in the last `quietMs`. DOM changes, such as a running animation, do not hold it open. A saved `net` check with a `count` uses this, so a late duplicate request is still counted.
332
+ - `"app"`: the default activity plus every framework render commit. Use it for an app whose renders are its work. The default ignores render commits, because on many pages a clock or a counter renders every second, and the page would never go quiet.
322
333
 
323
334
  ### compare
324
335
 
@@ -380,7 +391,7 @@ A fault-injection test (mock a 500, check the error UI) is asserting that a requ
380
391
 
381
392
  Asserting only the error text is not enough, and this is the most common way to get a confusing `verified: "no"`. Reticle watches for "the UI moved forward while a request failed", a swallowed rejection, and one of the most expensive bugs it catches. A fault-injection test looks **exactly** like that bug from the outside: a request failed, the screen changed, nothing said that was the plan.
382
393
 
383
- Naming the failing call is what tells the two apart. A `net` clause with `status` of 400 or more, or `"ok": false`, which is the honest field for IPC, where there is no status code, marks that call as expected to fail, and a failure there stops being a disagreement.
394
+ Naming the failing call is what tells the two apart. A `net` clause with `status` of 400 or more, or `"ok": false` (the field for IPC, which has no status code), marks that call as expected to fail. A failure there is then not a disagreement. The same rule applies to the `expect` of each step in `reticle_act { steps }` and in a replayed flow: each step declares its own expected failures. A failure that no step declared is still reported.
384
395
 
385
396
  <Warning>
386
397
  Declare it in the top level or inside `allOf`. A declaration inside `anyOf` is deliberately
@@ -452,7 +463,7 @@ On a failure each child reports separately too, so you can see which one broke:
452
463
  | `timeout_ms` | `reticle_assert` (both actions), `reticle_act_and_wait` | Wait up to N ms for it to become true |
453
464
  | `since` | `net`, `route`, `console`, `animation` and `signal` leaves, and the call itself | Only consider events after this cursor |
454
465
 
455
- The `since` cursor comes from a prior `reticle_act` or `reticle_observe` response. Use it whenever you are asserting something an action was supposed to cause. Without it, an assertion can pass on an event from two clicks ago. That applies to every one of the five kinds above, not only to network calls: an unscoped `signal` matches a fire from an earlier action just as readily.
466
+ The `since` cursor comes from a prior `reticle_act` or `reticle_observe` response. When you leave it out, the window starts at your last act, so a signal from an earlier action cannot pass the check. Give `since` when the cause is not your last act, for example when you assert on a cursor that you took before two actions. Before your first act there is no last act, and the window is the whole buffer.
456
467
 
457
468
  <Card title="Where predicates get used" icon="circle-check" href="/tools/act-and-wait">
458
469
  Naming the consequence before the action is the whole point.
@@ -0,0 +1,108 @@
1
+ ---
2
+ title: 'Production mode'
3
+ description: 'Let an agent drive your live site under a policy that refuses payments, deletions, invites and role changes.'
4
+ icon: shield
5
+ ---
6
+
7
+ Production mode lets an agent drive a live site, not only a development build. It is opt-in. It is dormant until you activate it for one drive. A visitor who did not activate it gets no SDK, no socket and no prompt.
8
+
9
+ ## What you need
10
+
11
+ - A Reticle service that issues activation tickets (`POST /v1/production-mode/tickets`). A service without this route answers 404, and the lease says "the server does not offer production mode".
12
+ - This project linked to that service: `reticle connect`, or `RETICLE_API_KEY`.
13
+ - The loader in your site's staging and production builds (below). It checks the ticket in the page, with the service's public key.
14
+ - A browser that is signed in to the site, as the person whose API key asks for the ticket. The service issues a ticket only for that person, in that workspace. A leased browser starts signed out, so give the lease your session cookies in `seedStorage` (see below).
15
+
16
+ ## Install the loader on staging and production
17
+
18
+ Call `activate` once, at startup, with the public key that the dashboard shows you:
19
+
20
+ ```ts
21
+ import { activate } from '@reticlehq/browser/activate';
22
+
23
+ void activate({ publicKey: '<the public key from the dashboard>' });
24
+ ```
25
+
26
+ In Vite, put it in `main.ts`. In Next.js, put it in a client component that the root layout renders, inside a `useEffect`.
27
+
28
+ A visitor's page load reads one query parameter and stops. It loads no SDK, opens no socket, and writes no storage and no DOM. Only a URL with a valid `reticle_activate` ticket loads the SDK. The loader then removes the parameter from the address bar and connects with the ticket's nonce, bridge and scope. The loader refuses a ticket that has a bad signature, that expired, that is for another origin, or whose bridge is not `wss://` (`ws://` only on a loopback host). A refused ticket loads nothing and writes one `console.warn` line.
29
+
30
+ The session reads as an installed SDK, not an injected one.
31
+
32
+ ### The ticket
33
+
34
+ The ticket is `<payload>.<signature>`, both base64url. The payload is JSON: `{ v: 1, nonce, origin, bridge, scope, exp }`, where `exp` is epoch ms. The signature is Ed25519 over the ASCII bytes of the payload part. A service mints tickets with `signActivationTicket(privateKey, payload)` from `@reticlehq/core`. The page checks them with `verifyActivationTicket`.
35
+
36
+ ## Activate a drive
37
+
38
+ One `reticle_lease` call does it:
39
+
40
+ ```json
41
+ {
42
+ "action": "acquire",
43
+ "url": "https://app.example.com/",
44
+ "seedStorage": { "cookies": { "<session cookie name>": "<value>" } },
45
+ "production": {
46
+ "workspaceId": "ws_123",
47
+ "scope": "act",
48
+ "intent": "create a project, then delete it"
49
+ }
50
+ }
51
+ ```
52
+
53
+ The daemon then does three things:
54
+
55
+ 1. It mints a single-use session nonce for the site's origin. The nonce expires after 60 minutes.
56
+ 2. It asks the service for a ticket with the linked API key: `{ workspaceId, nonce, bridgePort, scope, origin, bridge }`. `origin` is the site's origin and `bridge` is the bridge the page dials (`ws://127.0.0.1:<port>/reticle`). The service signs the ticket for exactly those two values. It also decides who may activate.
57
+ 3. It opens `https://app.example.com/?reticle_activate=<ticket>` in a leased browser.
58
+
59
+ A host that embeds the engine and runs its own bridge passes its cloud link as `ToolDeps.linkedCloud`, and its bridge as `bridgePort` and `nonces`. It needs no `cloud.json`. Such a host must not inject the SDK into a production lease's browser context. An injected copy connects first, as a development session, and the loader's `connect` then does nothing.
60
+
61
+ If no page connects, the lease answers `ready: false`. The usual cause is a signed-out browser: the service refused the ticket, and the page loaded without an activation. Release the lease, then acquire again with your session cookies in `seedStorage`.
62
+
63
+ The page connects with the nonce. The daemon accepts a production HELLO only with a live production nonce, never with the machine's pairing token. The first tab that presents the nonce owns it. That tab can reconnect after a reload. Another tab is refused.
64
+
65
+ ## What the policy refuses
66
+
67
+ The daemon enforces the policy where it sends commands, not in the page.
68
+
69
+ **Scope `observe`** refuses every act. The agent can still look, observe, assert and navigate.
70
+
71
+ **Scope `act`** refuses these actions, unless the drive's `intent` names the action:
72
+
73
+ | Rule | Examples |
74
+ | ----------------------------- | ---------------------------------------------------- |
75
+ | payment or checkout | Upgrade, Pay, Add card; `POST /billing`, `/checkout` |
76
+ | delete a workspace or project | Delete project; `DELETE /projects/:id` |
77
+ | revoke or rotate a key | Revoke key, Rotate secret; `DELETE /keys/:id` |
78
+ | send an invite or email | Send invite, Resend; `POST /invites` |
79
+ | cancel a subscription | Cancel subscription; `DELETE /subscriptions/:id` |
80
+ | change a member's role | Make admin, a Role picker; `PATCH /members/:id` |
81
+
82
+ The daemon recognises an action in two ways:
83
+
84
+ - **The control.** Its name, text, value, test id, link and form target.
85
+ - **The request.** Its method and path, from a policy list. The service can send its own list with the ticket. Without one, the daemon uses `DEFAULT_PRODUCTION_POLICY` from `@reticlehq/core`.
86
+
87
+ In a leased browser, each request the page sends passes the policy before it leaves the browser. A refused request gets a 403 and never reaches the site.
88
+
89
+ A key press on a production drive runs in the page, never on the native keyboard. A native key goes to the control that has focus, so the policy could not see it. The policy judges a key press by the control it names. A key press that names no control is judged only by the requests it sends.
90
+
91
+ These are always allowed:
92
+
93
+ - navigation on the activated origin (leaving the origin is refused);
94
+ - reading, filters, tabs and panels;
95
+ - deleting something the drive itself created. The daemon notes the ids that the drive's own creates returned (a 2xx `POST` or `PUT` whose body has an `id`).
96
+
97
+ An intent with a negation asks for nothing: "she does not invite anybody" does not allow an invite.
98
+
99
+ ## What a refusal looks like
100
+
101
+ A refusal is never a silent no-op. The act fails, and its error names the rule:
102
+
103
+ ```
104
+ refused: production policy: send an invite or email. A production drive does this only when its
105
+ declared intent names it (reticle_lease production.intent).
106
+ ```
107
+
108
+ The drive ends when the nonce expires. After that, every act is refused with `the session nonce expired`, and the page cannot reconnect.
@@ -0,0 +1,99 @@
1
+ ---
2
+ title: Prompt capture
3
+ description: How Reticle keeps each prompt you send and the agent's own tool calls, where they go, and every way to turn them off.
4
+ ---
5
+
6
+ A verdict is checked against what the user asked for. An agent tells Reticle the request only when it remembers to, so `reticle init` installs a hook that hands over each prompt before the agent reads it.
7
+
8
+ ## What `init` installs
9
+
10
+ `reticle init` adds a prompt-submit hook to the project-level config of each agent it finds that has one:
11
+
12
+ | Agent | Config file |
13
+ | --- | --- |
14
+ | Claude Code | `.claude/settings.json` |
15
+ | Cursor | `.cursor/hooks.json` |
16
+ | Codex CLI | `.codex/hooks.json` |
17
+ | Gemini CLI | `.gemini/settings.json` |
18
+ | Windsurf | `.windsurf/hooks.json`, or `.devin/hooks.json` when it is there |
19
+ | VS Code Copilot and Copilot CLI | `.github/hooks/reticle-prompt-capture.json` |
20
+ | Factory Droid | `.factory/hooks.json` |
21
+
22
+ Each hook runs `node "<bin>" hook prompt --agent <id> || npx -y @reticlehq/server@<version> hook prompt --agent <id>`. `<bin>` is the CLI that ran `init`, written as `$HOME/…` when it is under your home folder. When that file is not there, `node` stops before it reads the prompt and `npx` runs instead. On Windows, and in Copilot's `powershell` field, the hook runs the `npx` command alone. The version is pinned to the one that ran `init`. Run `init` or `reticle hook install` again after an upgrade to move the pin. These files are in your repository, so a teammate who commits them shares the hook. Codex runs these hooks only after you trust them: open `codex` in the project, type `/hooks` and trust the Reticle entries.
23
+
24
+ Agents with no prompt hook, such as Claude Desktop, get an instruction in the MCP server's instructions: declare the request with `reticle_intent` once for each user request.
25
+
26
+ ## What it writes
27
+
28
+ The hook writes two files in the project's `.reticle/` folder:
29
+
30
+ | File | What is in it |
31
+ | --- | --- |
32
+ | `request.json` | the newest prompt, split into statements and classified |
33
+ | `requests.jsonl` | every prompt, one JSON line each, oldest first. At 2 MB it moves to `requests.1.jsonl` |
34
+
35
+ Secrets are removed before anything is written: credential assignments (`password: …`, `STRIPE_SECRET_KEY=…`), vendor keys (`sk_live_…`, `ghp_…`, `AKIA…`, `AIza…`, `glpat-…`, `xoxb-…`), JWTs, emails, card numbers, phone numbers, home paths and hostnames. This is a pattern match, not a proof: a secret that looks like an ordinary word stays. A prompt is capped at 20,000 characters.
36
+
37
+ `request.json`, `requests.jsonl` and `requests.1.jsonl` are in `.reticle/.gitignore`. Reticle adds them to an older ignore file that does not have them, and keeps every line you wrote.
38
+
39
+ The hook makes no network call of its own and never blocks a prompt: a failure is exit 0 and nothing written. It answers the agent at once and writes the prompt in a separate background process. `npx` downloads the pinned version once when its cache does not have it. Nothing about a prompt reaches telemetry.
40
+
41
+ ## The agent's own tool calls
42
+
43
+ The same config files also get hooks for the agent's own work: the shell commands, file edits and web calls that do not go through Reticle's tools, the model the agent runs, and the message that ends each turn. Each of these hooks runs `reticle hook tool --agent <id>` in the same two forms as the prompt hook.
44
+
45
+ | Agent | Hooks | What they keep |
46
+ | --- | --- | --- |
47
+ | Claude Code | `PostToolUse`, `PostToolUseFailure`, `SessionStart`, `PostModelSwitch`, `Stop` | `Bash`, `Edit`, `Write`, `MultiEdit`, `NotebookEdit`, `WebFetch` and `WebSearch` calls; the model; the closing message |
48
+ | Cursor | `postToolUse`, `postToolUseFailure`, `afterAgentResponse` | `Shell`, `Write` and `Delete` calls; the closing message |
49
+ | Codex CLI | `PostToolUse`, `Stop` | `Bash` and `apply_patch` calls; the closing message; web searches, read from Codex's own session transcript |
50
+ | Gemini CLI | `AfterTool`, `AfterAgent` | `run_shell_command` calls; the closing message |
51
+ | Windsurf | `post_run_command`, `post_write_code`, `post_cascade_response` | commands and edits, with no result; the closing message |
52
+ | Copilot CLI | `postToolUse` | `bash` and `edit` calls |
53
+ | Factory Droid | `PostToolUse` | `Execute`, `Edit`, `ApplyPatch`, `Create`, `FetchUrl` and `WebSearch` calls |
54
+
55
+ Cursor and Codex send the model with each call, and Windsurf sends it unless it is "Unknown". VS Code Copilot gets no tool hook.
56
+
57
+ Each record goes to `.reticle/episodes/agent-<session>.jsonl`. A tool record holds the tool, its arguments, the first 4,000 characters of its result and the result's full size, whether it failed, its exit code, and its timing. A closing-message record holds the first 4,000 characters of the message and its full size. Secrets are removed from every string with the same patterns as a prompt, and paths inside the project are made relative. Reticle's own tools are skipped, because the episode log below already keeps them. The prompt-capture switch stops these records too: `"promptCapture": false` or `RETICLE_PROMPT_CAPTURE=0` stops the prompts, the tool calls, the model and the closing messages together.
58
+
59
+ The daemon also keeps every call to Reticle's own tools in `.reticle/episodes/<connection>.jsonl`, one file for each agent connection. The first line holds the git HEAD, the uncommitted change for each file, and the request. Each line after it holds one call: the tool, its arguments with typed values removed, its whole result or error, its timing, the tab, the agent, and the page events it caused. A field longer than 200,000 characters keeps its start and is named in `truncated`.
60
+
61
+ The `episodes/` folder is in `.reticle/.gitignore`, and retention removes old files with the other evidence. No file in it leaves the machine. `"sync": { "episodes": true }` in `.reticle/cloud.json` is kept for a later upload, which also needs a workspace that agreed to share its data. Nothing uploads the files today.
62
+
63
+ ## What leaves the machine
64
+
65
+ **Requests are shared by default for a linked project.** A project is linked by `reticle connect` (`.reticle/cloud.json`) or by `RETICLE_API_KEY` in the environment. A run written soon after a prompt carries that prompt, and the run goes to your own workspace when it syncs. The Harness also sends the newest request to the platform planner as a goal. An unlinked project sends the request nowhere.
66
+
67
+ A synced run also carries two values from the agent's hook records. `agent.model` is the model the agent ran. `context.closingClaim` is the first closing message the agent wrote at or after the run's last Reticle call, with secrets removed. The closing message follows the same rule as the request: it leaves only when the project shares requests.
68
+
69
+ To keep requests on the machine, set `"shareRequests": false` in `.reticle.json`. Capture goes on, and nothing about a request or a closing message leaves: not with a run, and not to the Harness.
70
+
71
+ A run syncs through `reticle sync`, through the daemon's background sync, or when `reticle verify` closes in CI. Background sync runs only for a project linked by its own `cloud.json`, and only while somebody is signed in to that address or `RETICLE_API_KEY` is the key for that link.
72
+
73
+ ## Turn it off
74
+
75
+ Agent capture is the prompts, the tool calls, the model and the closing messages that the agent hooks keep. One switch stops all of it. The episode log is the daemon's record of calls to Reticle's own tools. The journal switch stops it, and the agent's tool calls, model and closing messages, but not the prompts.
76
+
77
+ | What | How |
78
+ | ---------------------------------------- | -------------------------------------------- |
79
+ | Do not install the hooks | `reticle init --no-prompt-capture` |
80
+ | Stop all agent capture in one project | `"promptCapture": false` in `.reticle.json` |
81
+ | Stop all agent capture on this machine | `RETICLE_PROMPT_CAPTURE=0` |
82
+ | Stop the episode log in one project | `"journal": false` in `.reticle.json` |
83
+ | Stop the episode log on this machine | `RETICLE_JOURNAL=0` |
84
+ | Keep requests and closing messages local | `"shareRequests": false` in `.reticle.json` |
85
+ | Stop background sync in one project | `"backgroundSync": false` in `.reticle.json` |
86
+ | Stop background sync on this machine | `RETICLE_BACKGROUND_SYNC=0` |
87
+ | Remove every hook | `reticle hook uninstall` |
88
+
89
+ ## `reticle hook`
90
+
91
+ ```bash
92
+ npx @reticlehq/server hook status # per agent: is each prompt captured here
93
+ npx @reticlehq/server hook install # add the hook for the agents this project uses
94
+ npx @reticlehq/server hook uninstall # remove exactly what was added
95
+ ```
96
+
97
+ `hook install` writes a config only for an agent this project already uses (its folder is in the project, or the Claude Code CLI is on this machine). It also rewrites an older entry that runs only `npx` to the `node … || npx …` form. `hook prompt --agent <id>` and `hook tool --agent <id>` are what the agent's hooks run; you do not run them yourself. `reticle doctor` prints the same rows as `hook status`, and whether background sync is on. `hook status` names an entry that still runs only `npx`.
98
+
99
+ `npx @reticlehq/server hook export --structure` writes the page structure of each snapshot step in `.reticle/episodes/` to stdout, one JSON line for each step. A line holds the roles, refs, layout and states of the nodes. It holds no page text: a node says only whether it had a name, a value or text.