@reticlehq/server 2.11.0 → 2.12.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 (252) hide show
  1. package/SKILL.md +26 -2
  2. package/dist/bridge/bridge.d.ts +0 -13
  3. package/dist/bridge/bridge.js +1 -1
  4. package/dist/bridge/bridge.test-harness.d.ts +2 -0
  5. package/dist/bridge/bridge.test-harness.js +8 -1
  6. package/dist/capsule/capsule-store.d.ts +2 -1
  7. package/dist/capsule/capsule-store.js +1 -1
  8. package/dist/capsule/causal-summary.d.ts +2 -2
  9. package/dist/chromium-launch-options.d.ts +28 -0
  10. package/dist/chromium-launch-options.js +29 -0
  11. package/dist/cli/cli-doctor.js +8 -0
  12. package/dist/cli/cli-flow-commands.d.ts +3 -1
  13. package/dist/cli/cli-flow-commands.js +34 -4
  14. package/dist/cli/cli-kill.d.ts +2 -1
  15. package/dist/cli/cli-parse.d.ts +3 -1
  16. package/dist/cli/cli-parse.js +29 -7
  17. package/dist/cli/cli-update-commands.js +20 -1
  18. package/dist/cli/cli-verify.d.ts +1 -1
  19. package/dist/cli/cli-verify.js +2 -2
  20. package/dist/cli/cloud-cli.js +12 -6
  21. package/dist/cli/config-discovery.d.ts +2 -1
  22. package/dist/cli/doctor-rows.d.ts +3 -1
  23. package/dist/cli/doctor-rows.js +3 -1
  24. package/dist/cli/gate-exit.d.ts +21 -0
  25. package/dist/cli/gate-exit.js +21 -0
  26. package/dist/cli/gate-hook-message.d.ts +33 -0
  27. package/dist/cli/gate-hook-message.js +46 -0
  28. package/dist/cli/mcp-command.d.ts +25 -0
  29. package/dist/cli/mcp-command.js +143 -0
  30. package/dist/cli/sibling-ports.d.ts +37 -0
  31. package/dist/cli/sibling-ports.js +56 -0
  32. package/dist/cli.js +37 -110
  33. package/dist/cloud/cloud-config.d.ts +2 -1
  34. package/dist/cloud/cloud-sync.d.ts +11 -0
  35. package/dist/cloud/cloud-sync.js +32 -0
  36. package/dist/crawl/crawl.d.ts +9 -13
  37. package/dist/crawl/crawl.js +20 -3
  38. package/dist/daemon/daemon-resolve.d.ts +79 -0
  39. package/dist/daemon/daemon-resolve.js +118 -0
  40. package/dist/daemon/free-port.d.ts +29 -0
  41. package/dist/daemon/free-port.js +55 -0
  42. package/dist/daemon/heartbeat.d.ts +0 -4
  43. package/dist/daemon/heartbeat.js +2 -2
  44. package/dist/dev/stale-issue-guard.d.ts +0 -2
  45. package/dist/dev/stale-issue-guard.js +1 -1
  46. package/dist/events/contradictions.d.ts +41 -0
  47. package/dist/events/contradictions.js +125 -12
  48. package/dist/events/declared.d.ts +14 -0
  49. package/dist/events/declared.js +33 -0
  50. package/dist/events/echo-mismatch.js +14 -0
  51. package/dist/events/observed-in-window.d.ts +12 -0
  52. package/dist/events/observed-in-window.js +17 -0
  53. package/dist/events/predicate-asks.d.ts +13 -0
  54. package/dist/events/predicate-asks.js +22 -0
  55. package/dist/events/predicate-eval.js +64 -22
  56. package/dist/events/predicate-parse.d.ts +0 -6
  57. package/dist/events/predicate-parse.js +43 -3
  58. package/dist/events/predicate-schema.d.ts +44 -0
  59. package/dist/events/predicate-schema.js +126 -23
  60. package/dist/events/predicate.d.ts +15 -0
  61. package/dist/events/predicate.js +41 -2
  62. package/dist/flows/coverage.d.ts +0 -8
  63. package/dist/flows/coverage.js +1 -1
  64. package/dist/flows/decision.d.ts +5 -1
  65. package/dist/flows/decision.js +33 -7
  66. package/dist/flows/flake.d.ts +0 -2
  67. package/dist/flows/flake.js +1 -1
  68. package/dist/flows/flow-intent.d.ts +52 -0
  69. package/dist/flows/flow-intent.js +123 -0
  70. package/dist/flows/flow-replay-run.js +27 -4
  71. package/dist/flows/flow-success.js +15 -3
  72. package/dist/flows/flow-tools.js +32 -4
  73. package/dist/flows/flows.d.ts +6 -1
  74. package/dist/flows/flows.js +34 -22
  75. package/dist/flows/predicate-to-expect.js +6 -3
  76. package/dist/flows/server-verify.js +16 -2
  77. package/dist/flows/verify-change-tools.js +4 -1
  78. package/dist/honesty/blind-spots.d.ts +0 -17
  79. package/dist/honesty/blind-spots.js +1 -1
  80. package/dist/honesty/feature-capture.d.ts +150 -0
  81. package/dist/honesty/feature-capture.js +233 -0
  82. package/dist/honesty/instrumentation-gaps.d.ts +30 -6
  83. package/dist/honesty/instrumentation-gaps.js +61 -5
  84. package/dist/honesty/tool-hit-rate.d.ts +86 -0
  85. package/dist/honesty/tool-hit-rate.js +90 -0
  86. package/dist/honesty/undeclared-change.d.ts +51 -0
  87. package/dist/honesty/undeclared-change.js +56 -0
  88. package/dist/honesty/verified.d.ts +15 -0
  89. package/dist/honesty/verified.js +68 -4
  90. package/dist/http-server.d.ts +0 -1
  91. package/dist/http-server.js +1 -1
  92. package/dist/hunt/hunt-report.d.ts +0 -2
  93. package/dist/hunt/hunt-report.js +1 -1
  94. package/dist/impact/impact-store.d.ts +0 -5
  95. package/dist/impact/impact-store.js +1 -1
  96. package/dist/index.d.ts +4 -1
  97. package/dist/init/agent-rules.d.ts +17 -0
  98. package/dist/init/agent-rules.js +31 -1
  99. package/dist/init/capabilities.d.ts +0 -2
  100. package/dist/init/capabilities.js +1 -1
  101. package/dist/init/closing-hint.d.ts +36 -0
  102. package/dist/init/closing-hint.js +120 -0
  103. package/dist/init/confirm.d.ts +0 -25
  104. package/dist/init/confirm.js +3 -3
  105. package/dist/init/cra.d.ts +14 -1
  106. package/dist/init/cra.js +43 -12
  107. package/dist/init/dev-script.d.ts +48 -0
  108. package/dist/init/dev-script.js +63 -0
  109. package/dist/init/mcp.d.ts +16 -5
  110. package/dist/init/mcp.js +26 -10
  111. package/dist/init/plan-framework.d.ts +0 -5
  112. package/dist/init/plan-framework.js +83 -9
  113. package/dist/init/plan.d.ts +10 -30
  114. package/dist/init/plan.js +30 -15
  115. package/dist/init/refresh-rules.d.ts +39 -0
  116. package/dist/init/refresh-rules.js +51 -0
  117. package/dist/init/run.d.ts +0 -26
  118. package/dist/init/run.js +14 -87
  119. package/dist/init/snippets.js +53 -10
  120. package/dist/input/real-input.d.ts +2 -0
  121. package/dist/input/real-input.js +3 -2
  122. package/dist/input/scroll-find.d.ts +7 -4
  123. package/dist/input/scroll-find.js +63 -25
  124. package/dist/intent/inline-intent.d.ts +46 -0
  125. package/dist/intent/inline-intent.js +103 -0
  126. package/dist/intent/intent-store.d.ts +37 -0
  127. package/dist/intent/intent-store.js +112 -0
  128. package/dist/intent/intent-tools.d.ts +2 -0
  129. package/dist/intent/intent-tools.js +80 -0
  130. package/dist/intent/open-intents.d.ts +21 -0
  131. package/dist/intent/open-intents.js +25 -0
  132. package/dist/journal/envelope.d.ts +26 -26
  133. package/dist/journal/journal-recorder.d.ts +23 -0
  134. package/dist/journal/journal-recorder.js +35 -0
  135. package/dist/mcp/attach-memory.d.ts +67 -0
  136. package/dist/mcp/attach-memory.js +142 -0
  137. package/dist/mcp/mcp-proxy.d.ts +0 -7
  138. package/dist/mcp/mcp-proxy.js +14 -2
  139. package/dist/mcp/mcp.d.ts +2 -0
  140. package/dist/mcp/mcp.js +45 -23
  141. package/dist/mcp/server-instructions.js +45 -3
  142. package/dist/mcp/tool-catalog-cache.d.ts +8 -0
  143. package/dist/mcp/tool-catalog-cache.js +10 -0
  144. package/dist/oracles/flow-instrument-gaps.d.ts +4 -4
  145. package/dist/oracles/flow-instrument-gaps.js +4 -5
  146. package/dist/oracles/self-instrument.d.ts +9 -9
  147. package/dist/oracles/self-instrument.js +19 -13
  148. package/dist/pool/browser-pool.d.ts +12 -1
  149. package/dist/pool/browser-pool.js +31 -1
  150. package/dist/pool/playwright-launcher.js +3 -1
  151. package/dist/project/fs-port.d.ts +3 -0
  152. package/dist/project/fs-port.js +3 -2
  153. package/dist/project/memory-fs.js +6 -1
  154. package/dist/project/project-tools.js +3 -32
  155. package/dist/project/reticle-dir.d.ts +2 -0
  156. package/dist/project/reticle-dir.js +1 -0
  157. package/dist/runs/context-tools.d.ts +2 -0
  158. package/dist/runs/context-tools.js +89 -0
  159. package/dist/runs/run-context.d.ts +40 -0
  160. package/dist/runs/run-context.js +158 -0
  161. package/dist/runs/run-diff.d.ts +2 -1
  162. package/dist/runs/verification-sync.js +2 -2
  163. package/dist/session/dev-server-probe.d.ts +0 -8
  164. package/dist/session/dev-server-probe.js +1 -1
  165. package/dist/session/last-act.d.ts +7 -1
  166. package/dist/session/last-act.js +2 -2
  167. package/dist/session/live-control-tools.js +1 -42
  168. package/dist/session/no-session-diagnosis.d.ts +10 -0
  169. package/dist/session/no-session-diagnosis.js +24 -7
  170. package/dist/session/no-session-next-action.d.ts +5 -0
  171. package/dist/session/no-session-next-action.js +35 -3
  172. package/dist/session/no-session-watch.d.ts +8 -0
  173. package/dist/session/no-session-watch.js +82 -64
  174. package/dist/session/output-budget.js +4 -1
  175. package/dist/session/session-health.d.ts +9 -0
  176. package/dist/session/session-health.js +23 -0
  177. package/dist/session/session-manager.js +50 -1
  178. package/dist/session/session-successor.d.ts +37 -0
  179. package/dist/session/session-successor.js +78 -0
  180. package/dist/session/session.d.ts +31 -1
  181. package/dist/session/session.js +75 -2
  182. package/dist/telemetry/automation-hint.d.ts +2 -1
  183. package/dist/telemetry/feedback-outbox.d.ts +2 -1
  184. package/dist/telemetry/project-profile.d.ts +0 -8
  185. package/dist/telemetry/project-profile.js +1 -1
  186. package/dist/telemetry/run-telemetry.d.ts +0 -2
  187. package/dist/telemetry/run-telemetry.js +1 -1
  188. package/dist/telemetry/verification-of.js +2 -2
  189. package/dist/tools/act-tools.js +126 -21
  190. package/dist/tools/assert-source.d.ts +22 -0
  191. package/dist/tools/assert-source.js +53 -0
  192. package/dist/tools/assert-verdict.d.ts +20 -3
  193. package/dist/tools/assert-verdict.js +36 -4
  194. package/dist/tools/browser-tools.js +0 -20
  195. package/dist/tools/complete-snapshot.d.ts +48 -0
  196. package/dist/tools/complete-snapshot.js +75 -0
  197. package/dist/tools/coverage-tools.d.ts +10 -1
  198. package/dist/tools/coverage-tools.js +123 -69
  199. package/dist/tools/dynamic-tools.js +29 -8
  200. package/dist/tools/error-recovery.d.ts +24 -14
  201. package/dist/tools/error-recovery.js +70 -9
  202. package/dist/tools/feedback-tools.d.ts +1 -1
  203. package/dist/tools/feedback-tools.js +2 -2
  204. package/dist/tools/invoke-tool.js +62 -2
  205. package/dist/tools/lease-hint.d.ts +10 -0
  206. package/dist/tools/lease-hint.js +53 -4
  207. package/dist/tools/lease-tools.d.ts +5 -1
  208. package/dist/tools/lease-tools.js +22 -8
  209. package/dist/tools/navigate-arrival.d.ts +0 -2
  210. package/dist/tools/navigate-arrival.js +1 -1
  211. package/dist/tools/observe-tools.js +63 -26
  212. package/dist/tools/read-tools.js +5 -3
  213. package/dist/tools/real-input-attempt.d.ts +22 -0
  214. package/dist/tools/real-input-attempt.js +153 -1
  215. package/dist/tools/reconcile-tools.js +18 -4
  216. package/dist/tools/resolve-target.d.ts +0 -7
  217. package/dist/tools/sdk-marker-probe.d.ts +29 -0
  218. package/dist/tools/sdk-marker-probe.js +57 -0
  219. package/dist/tools/snapshot-delta.d.ts +1 -1
  220. package/dist/tools/tool-kit.d.ts +12 -0
  221. package/dist/tools/tool-kit.js +16 -0
  222. package/dist/tools/tool-names.d.ts +3 -0
  223. package/dist/tools/tool-names.js +3 -0
  224. package/dist/tools/tool-surface.d.ts +85 -6
  225. package/dist/tools/tool-surface.js +122 -2
  226. package/dist/tools/tools.js +22 -4
  227. package/dist/tools/unadvertised-help.js +4 -4
  228. package/dist/tools/verify-next-baton.d.ts +53 -0
  229. package/dist/tools/verify-next-baton.js +52 -0
  230. package/dist/update/update-nudge.d.ts +7 -10
  231. package/dist/update/update-nudge.js +12 -3
  232. package/dist/update/updater.d.ts +1 -1
  233. package/docs/README.md +2 -1
  234. package/docs/cli/cloud.mdx +1 -1
  235. package/docs/cli/doctor.mdx +1 -0
  236. package/docs/cli/verify.mdx +4 -5
  237. package/docs/desktop.mdx +1 -1
  238. package/docs/docs.json +2 -2
  239. package/docs/gates.md +1 -1
  240. package/docs/install-manual.mdx +1 -1
  241. package/docs/packages/browser.mdx +2 -2
  242. package/docs/packages/server.mdx +1 -1
  243. package/docs/packages.mdx +8 -6
  244. package/docs/platform-integration.md +17 -0
  245. package/docs/predicates.mdx +8 -0
  246. package/docs/reticle-manual.md +106 -0
  247. package/docs/tools-tools-and-run.mdx +2 -4
  248. package/docs/troubleshooting.mdx +9 -0
  249. package/docs/usage.md +3 -2
  250. package/package.json +2 -2
  251. package/dist/session/session-readiness.d.ts +0 -34
  252. package/dist/session/session-readiness.js +0 -36
@@ -93,6 +93,23 @@ Live, clickable demo of each: `apps/vibe-builder-demo/` (set `BUG_MODE=…`). Pr
93
93
 
94
94
  ---
95
95
 
96
+ ## The minimal attach contract (for a harness or MCP host)
97
+
98
+ Reticle is a stdio MCP server. A host that wires it correctly does four things, and each one is a step Reticle can see:
99
+
100
+ 1. **Spawn it.** `npx @reticlehq/server mcp`, over stdio, one process per host. That process is the proxy: it starts the local daemon on demand, reconnects on its own when the stream drops, and answers from cache while a daemon comes back.
101
+ 2. **Complete `initialize`.** Reticle answers the handshake itself when the daemon is slow, so a host that waits for a reply gets one either way.
102
+ 3. **Send `tools/list`, and send it again on `notifications/tools/list_changed`.** This is the step hosts skip. Registering a server is not the same as enumerating it: a host can register Reticle and never ask for the tool list until the client is restarted, and the model then has no Reticle tools at all while the install looks healthy from every other angle. Reticle declares `tools.listChanged` so a host that honours the notification recovers without a restart.
103
+ 4. **Call the tools.** `tools/call`, with the tool name and its arguments.
104
+
105
+ `reticle status` reports how far a host has got. `mcpClient: "never-attached"` means no client has started the server on this port. `mcpClient: "never-enumerated"` means one started it and never asked for the tool list, which is the state a client restart fixes. `mcpClient: "enumerated"` means the client side is done, and anything still missing is the app rather than the host. The record is per port rather than per client, and it begins the first time a client starts a Reticle version that keeps it, so `status` says both of those out loud instead of naming a client it cannot see.
106
+
107
+ ### Hosts that cap the number of tools
108
+
109
+ Some editors cap the total tool count across every MCP server, which is why Reticle advertises a small surface instead of everything it can do. Nothing is out of reach: `reticle_tools { names: [...] }` lists the tools and returns the full argument grammar for the ones you name, and `reticle_run { tool, args }` invokes any of them, advertised or not. A host that is short on tool slots pays for the advertised handful and still reaches the whole surface through that pair. See [`reticle_tools` and `reticle_run`](/tools-tools-and-run).
110
+
111
+ ---
112
+
96
113
  ## Exact steps per platform
97
114
 
98
115
  The shape is identical (in-app SDK in the template → verify in the sandbox → act on the verdict); the specifics differ by where each platform runs the preview.
@@ -115,6 +115,14 @@ A passing route verdict quotes the transition itself:
115
115
 
116
116
  The app emitted a named signal via `reticle.signal()`. `dataMatches` is shallow JSON matching, and `*` means "present, any value".
117
117
 
118
+ `count` works here exactly as it does on `net`:
119
+
120
+ ```json
121
+ { "kind": "signal", "name": "order:placed", "count": 1 }
122
+ ```
123
+
124
+ **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.
125
+
118
126
  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.
119
127
 
120
128
  ### state
@@ -0,0 +1,106 @@
1
+ ---
2
+ title: 'Reticle: what each tool actually does'
3
+ description: Generated from real calls against a running app. Every row is a probe that ran and the answer it got.
4
+ icon: table-list
5
+ ---
6
+
7
+ **Generated by `bench/harness/behaviour-matrix.mjs`. Do not edit by hand.**
8
+
9
+ Every row below is a call that was made against a running app and the answer that came back. Nothing here is described from the source or from intent. If a claim has no probe behind it, it is not in this file. That is the whole point: the hand-written guides drifted, and the drift was invisible because nobody ran them.
10
+
11
+ `refused (names the fix)` means the error told you what to call instead, so you can correct without reading anything else. `refused (no fix named)` means it did not.
12
+
13
+ ## reticle_snapshot
14
+
15
+ | you call it with | you get back | bytes |
16
+ | --- | --- | --- |
17
+ | an argument the tool does not declare: `{"thisArgDoesNotExist":1}` | refused (names the fix) | 273 |
18
+ | the documented call: `{"mode":"interactive"}` | ran | 434 |
19
+ | a value outside the allowed set: `{"mode":"not-a-mode"}` | refused (names the fix) | 236 |
20
+
21
+ ## reticle_query
22
+
23
+ | you call it with | you get back | bytes |
24
+ | --- | --- | --- |
25
+ | an argument the tool does not declare: `{"thisArgDoesNotExist":1}` | refused (names the fix) | 368 |
26
+ | the documented call: `{"by":"role","value":"button"}` | ran | 200 |
27
+ | a value outside the allowed set: `{"by":"telepathy","value":"x"}` | refused (names the fix) | 290 |
28
+
29
+ ## reticle_network
30
+
31
+ | you call it with | you get back | bytes |
32
+ | --- | --- | --- |
33
+ | an argument the tool does not declare: `{"thisArgDoesNotExist":1}` | refused (names the fix) | 354 |
34
+ | the documented call: `{"limit":5}` | ran | 1175 |
35
+ | a number outside its range: `{"limit":-1}` | refused (names the fix) | 222 |
36
+
37
+ ## reticle_console
38
+
39
+ | you call it with | you get back | bytes |
40
+ | --- | --- | --- |
41
+ | an argument the tool does not declare: `{"thisArgDoesNotExist":1}` | refused (names the fix) | 293 |
42
+
43
+ ## reticle_state
44
+
45
+ | you call it with | you get back | bytes |
46
+ | --- | --- | --- |
47
+ | an argument the tool does not declare: `{"thisArgDoesNotExist":1}` | refused (names the fix) | 268 |
48
+ | a number outside its range: `{"depth":-5}` | refused (names the fix) | 173 |
49
+ | the documented call: `{"depth":2}` | ran | 210 |
50
+
51
+ - a negative depth was silently ignored before v2.12.0
52
+
53
+ ## reticle_observe
54
+
55
+ | you call it with | you get back | bytes |
56
+ | --- | --- | --- |
57
+ | an argument the tool does not declare: `{"thisArgDoesNotExist":1}` | refused (names the fix) | 305 |
58
+
59
+ ## reticle_act_and_wait
60
+
61
+ | you call it with | you get back | bytes |
62
+ | --- | --- | --- |
63
+ | no expectation declared: `{"ref":"e1005","action":"click"}` | verified:no-fault | 1343 |
64
+ | the documented call: `{"ref":"e1105","action":"click","until":{"kind":"text","value":"Invalid email or password"},"timeout_ms":6000}` | verified:yes | 1297 |
65
+ | no expectation declared: `{"ref":"e1205","action":"click","until":{"kind":"settled"}}` | verified:no-fault | 1343 |
66
+ | a value outside the allowed set: `{"ref":"e903","action":"click","until":[{"kind":"text","value":"x"}]}` | refused (names the fix) | 399 |
67
+ | a ref that no longer resolves: `{"ref":"e999999","action":"click"}` | refused (names the fix) | 519 |
68
+
69
+ - no `until`: this returned verified:"yes" before v2.12.0
70
+
71
+ - a consequence the click CAUSES: the shape that earns verified:"yes"
72
+
73
+ - an explicit `{kind:"settled"}` is the idle wait, not a declaration, so it grades no-fault too
74
+
75
+ - a bare array is not a predicate
76
+
77
+ ## reticle_act
78
+
79
+ | you call it with | you get back | bytes |
80
+ | --- | --- | --- |
81
+ | a required argument omitted: `{"ref":"e901"}` | refused (names the fix) | 192 |
82
+ | a value outside the allowed set: `{"ref":"e901","action":"teleport"}` | refused (names the fix) | 415 |
83
+ | an argument the tool does not declare: `{"ref":"e901","action":"fill","value":"x"}` | refused (names the fix) | 314 |
84
+ | the documented call: `{"ref":"e901","action":"fill","args":{"value":"probe"}}` | refused (names the fix) | 516 |
85
+
86
+ - action arguments nest under `args`
87
+
88
+ ## reticle_assert
89
+
90
+ | you call it with | you get back | bytes |
91
+ | --- | --- | --- |
92
+ | a required argument omitted: `{}` | refused (names the fix) | 592 |
93
+ | the documented call: `{"predicate":{"kind":"text","value":"Sign in"},"timeout_ms":3000}` | verified:yes | 794 |
94
+
95
+ ## reticle_tools
96
+
97
+ | you call it with | you get back | bytes |
98
+ | ------------------------- | ----------------------- | ----- |
99
+ | the documented call: `{}` | refused (names the fix) | 246 |
100
+
101
+ ## reticle_run
102
+
103
+ | you call it with | you get back | bytes |
104
+ | --- | --- | --- |
105
+ | a value outside the allowed set: `{"tool":"reticle_nope","args":{}}` | refused (names the fix) | 894 |
106
+ | the documented call: `{"tool":"reticle_context","args":{}}` | ran | 54 |
@@ -6,9 +6,7 @@ icon: boxes-stacked
6
6
 
7
7
  `reticle_tools` lists every Reticle tool and, on request, returns the full argument grammar for the ones you name. `reticle_run` then invokes any of them. Reach for the pair whenever you need a capability that is not in the default advertised surface, which is most of what Reticle can do.
8
8
 
9
- Reticle ships 46 tools plus these two meta-tools. On the default profile your agent is shown 17 of them plus the meta pair, so 29 sit in the cold tail. These two are how it reaches those 29 without paying for their schemas on every turn.
10
-
11
- `reticle_tools` discovers. `reticle_run` invokes. Together they cost two tool definitions instead of twenty-nine.
9
+ `reticle_tools` discovers. `reticle_run` invokes. Together they cost two tool definitions instead of the rest of the catalog.
12
10
 
13
11
  ## Discovering what exists
14
12
 
@@ -41,7 +39,7 @@ The response also tells you which surface is active:
41
39
  "profile": {
42
40
  "active": "all",
43
41
  "source": "RETICLE_ADVERTISE_ALL_TOOLS set in the DAEMON's environment at startup",
44
- "note": "The profile is read once at daemon startup: change RETICLE_TOOL_PROFILE and restart the daemon, or it has no effect. Under this profile every unadvertised tool is reachable through reticle_run; under `full` there are no meta-tools because every tool is advertised directly."
42
+ "note": "The surface is read once at daemon startup: set RETICLE_ADVERTISE_ALL_TOOLS=1 and restart the daemon, or it has no effect. No surface advertises every tool: the advertised count is capped because editors budget tools across all connected MCP servers. Every tool listed here is callable through reticle_run { tool, args } whether or not it is advertised."
45
43
  },
46
44
  "next": "Load params with reticle_tools { names:[…] }, then call reticle_run { tool, args }."
47
45
  }
@@ -83,6 +83,15 @@ the URL explicitly (Vite: VITE_RETICLE_WS_URL, or reticle.connect({ url })). An
83
83
  open a ws:// socket at all. Still retrying…
84
84
  ```
85
85
 
86
+ **You should not have to read this page to find that out.** If the agent opened the app with `reticle_lease`, which is the path `init` steers it to, the daemon reads that address off the page's own console, compares it with the port it is bound to, and puts the mismatch in the tool result:
87
+
88
+ ```
89
+ The page dialled ws://localhost:4460/reticle (port 4460) and this daemon is on
90
+ 4400, so the dial never reached it. Nothing about the app's wiring is in question.
91
+ ```
92
+
93
+ Neither side can work that out alone: the page cannot see the daemon, and the daemon never saw a dial that went somewhere else. The rest of this section covers what the lease cannot: a tab you opened yourself, or an app the pool cannot reach.
94
+
86
95
  That message names the exact address it tried. Compare its port with `bridge port` from `doctor` and set whichever is wrong:
87
96
 
88
97
  ```bash
package/docs/usage.md CHANGED
@@ -183,7 +183,7 @@ The timeline + summary of what happened.
183
183
 
184
184
  Act, then wait for a predicate: the whole act→observe→assert loop in one hop.
185
185
 
186
- - **args:** `ref`, `action`, `args?`, `until: <predicate>`, `timeout_ms?` (default 4000; 0 = evaluate once), `refuseWhenThrottled?`, `sessionId?`.
186
+ - **args:** `ref`, `action`, `args?`, `until: <predicate>`, `timeout_ms?` (default 4000; 0 = evaluate once), `refuseWhenThrottled?`, `intent?`, `sessionId?`.
187
187
  - **returns:** `{ effect, verdict, trace, session, warning? }`. `effect` is the action result (`{ ok, ref, action }`), `verdict` is `{ pass, evidence?, failureReason? }`, `trace` is the reaction report of everything the app did after the action, and `session` is the tab-health block `{ lastSeenMs, throttled, focused }` (with a `warning` when throttled). A failing `verdict` still returns `effect` + `trace` so you can see what _did_ happen. The predicate is automatically floored at this act's cursor, so it only matches events the action actually caused.
188
188
 
189
189
  ### `reticle_wait_for`
@@ -197,9 +197,10 @@ Block until a predicate holds (or time out). Looks both backward (recent buffer)
197
197
 
198
198
  Verify a predicate; optionally wait for it.
199
199
 
200
- - **args:** `predicate`, `timeout_ms?` (0 = evaluate once), `since?`, `sessionId?`.
200
+ - **args:** `predicate`, `timeout_ms?` (0 = evaluate once), `since?`, `intent?`, `sessionId?`.
201
201
  - Same `since` default as `reticle_wait_for`: scoped to your last act so a stale buffered event can't fake a pass; override with an explicit `since`.
202
202
  - **returns:** `{ verified, because, pass, evidence, contradictions?, coverage?, failureReason?, session, warning? }`. On failure includes a **near-miss** (e.g. "found the dialog but not visible", or "no button named 'Submit'; saw: Cancel"). The `session` block `{ lastSeenMs, throttled, focused }` reports tab health on every assert; when throttled a `warning` is attached so you never assert against a tab that is silently no-oping.
203
+ - **`intent` declares what the change was FOR, inline.** Pass a sentence in your own words and it lands in `.reticle/intent.json`, the same git-checked ledger `reticle_intent` writes, before the verdict is drawn; a green verdict then marks it proved and names itself as the proof. Pass the **id** of an intent you already declared instead, to point several verdicts at one statement rather than restating it. `reticle_act_and_wait` takes the same argument. Omit it and nothing is written.
203
204
  - **Read `verified`, not `pass`.** `pass` says the predicate held; `verified` says whether that means anything. It is `"no"` when a channel contradicts the assertion (a failed write under a green screen, a batch whose body reports per-item failures, a request still in flight), and `"unknown"` when the outcome could not be known yet: a `202 Accepted` that has not reconciled, or a write whose response body was never recorded. `because` names the deciding evidence in one sentence.
204
205
 
205
206
  ### `reticle_reconcile`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reticlehq/server",
3
- "version": "2.11.0",
3
+ "version": "2.12.0",
4
4
  "description": "Reticle bridge + MCP server. Hosts the browser WS endpoint and exposes MCP tools to the coding agent.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "@modelcontextprotocol/sdk": "^1.30.0",
23
23
  "ws": "^8.21.3",
24
24
  "zod": "^3.24.1",
25
- "@reticlehq/core": "2.11.0"
25
+ "@reticlehq/core": "2.12.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/pngjs": "^6.0.5",
@@ -1,34 +0,0 @@
1
- /**
2
- * First-run readiness: the agent often issues its first tool call in the window between `reticle init`
3
- * and the app's SDK actually connecting its WebSocket — so a naive resolve throws "no session". This
4
- * lets the agent (via reticle_wait_ready) BLOCK briefly until a session appears instead of failing the
5
- * race, smoothing the most common first-5-minutes footgun.
6
- *
7
- * Pure control loop: the session count, clock, and sleep are all injected, so it is unit-tested with
8
- * no real timers — and in production it polls a real `setTimeout` sleep.
9
- */
10
- interface WaitForReadyOptions {
11
- /** Live count of connected sessions (SessionManager.count). */
12
- count: () => number;
13
- /** Give up after this much elapsed time. */
14
- timeoutMs: number;
15
- /** Injected monotonic clock (ms). */
16
- now: () => number;
17
- /** Injected delay between polls. */
18
- sleep: (ms: number) => Promise<void>;
19
- /** Poll interval (ms). Default 25 — see DEFAULT_POLL_MS. */
20
- pollMs?: number;
21
- }
22
- /**
23
- * One-line orientation for a FRESH agent — the Reticle loop, returned by reticle_wait_ready (the first call)
24
- * so an agent learns how to drive Reticle without reading docs. Named so it is not a free string; kept
25
- * terse on purpose (it rides the first response, where token budget is tightest).
26
- */
27
- export declare const RETICLE_LOOP_GUIDE: string;
28
- /**
29
- * Resolve `true` as soon as at least one session is connected, or `false` if the timeout elapses
30
- * first. Returns immediately when a session is already connected (the common, already-ready case —
31
- * so this never adds latency on the happy path, including the benchmark which always has a session).
32
- */
33
- export declare function waitForReady(opts: WaitForReadyOptions): Promise<boolean>;
34
- export {};
@@ -1,36 +0,0 @@
1
- /**
2
- * Same reasoning as session-reconnect: the check is an in-memory lookup and the thing awaited is an
3
- * event (a session registering), so a coarse grid only adds latency to the first call an agent
4
- * makes. Four times the checks of something with no I/O costs nothing measurable.
5
- */
6
- const DEFAULT_POLL_MS = 25;
7
- /**
8
- * One-line orientation for a FRESH agent — the Reticle loop, returned by reticle_wait_ready (the first call)
9
- * so an agent learns how to drive Reticle without reading docs. Named so it is not a free string; kept
10
- * terse on purpose (it rides the first response, where token budget is tightest).
11
- */
12
- export const RETICLE_LOOP_GUIDE = 'Reticle loop — LOOK: reticle_snapshot / reticle_query / reticle_inspect · ACT: reticle_act (or reticle_act_and_wait) · ' +
13
- 'OBSERVE: reticle_observe / reticle_wait_for / reticle_network / reticle_console · ASSERT: reticle_assert over program ' +
14
- 'truth, not just the DOM · REGRESS: reticle_record{action:"start"} → reticle_replay, or reticle_verify{action:"flows"} for the whole ' +
15
- 'suite. The human can flag bugs from the panel — drain them with reticle_session{action:"review"} and resolve each once fixed. ' +
16
- 'MANDATORY: the moment you stop driving — finishing your reply or waiting on the human — call reticle_session {action:"yield"} ' +
17
- '(mode:"waiting", or mode:"ask" with the question) so the panel shows your real state; reticle_session{action:"end"} ' +
18
- 'only when the whole task is done. Never leave the panel reading "live" when you have actually stopped.';
19
- /**
20
- * Resolve `true` as soon as at least one session is connected, or `false` if the timeout elapses
21
- * first. Returns immediately when a session is already connected (the common, already-ready case —
22
- * so this never adds latency on the happy path, including the benchmark which always has a session).
23
- */
24
- export async function waitForReady(opts) {
25
- if (opts.count() > 0)
26
- return true;
27
- const start = opts.now();
28
- const poll = opts.pollMs ?? DEFAULT_POLL_MS;
29
- for (;;) {
30
- if (opts.now() - start >= opts.timeoutMs)
31
- return opts.count() > 0;
32
- await opts.sleep(poll);
33
- if (opts.count() > 0)
34
- return true;
35
- }
36
- }