explorbot 0.2.3 → 0.2.5

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 (174) hide show
  1. package/README.md +1 -1
  2. package/bin/explorbot-cli.ts +26 -8
  3. package/boat/api-tester/src/cli.ts +17 -0
  4. package/boat/api-tester/src/config.ts +4 -2
  5. package/boat/doc-collector/bin/doc-collector-cli.ts +2 -0
  6. package/boat/doc-collector/src/ai/documentarian.ts +61 -31
  7. package/boat/doc-collector/src/cli.ts +14 -1
  8. package/boat/doc-collector/src/config.ts +4 -2
  9. package/boat/prima/bin/prima-cli.ts +0 -0
  10. package/boat/prima/src/activity-line.ts +33 -0
  11. package/boat/prima/src/cli.ts +127 -86
  12. package/boat/prima/src/envelope.ts +102 -52
  13. package/boat/prima/src/prima.ts +567 -128
  14. package/boat/prima/src/pw-parser.ts +11 -1
  15. package/boat/prima/src/pw-registry.ts +4 -5
  16. package/boat/prima/src/session-log.ts +126 -0
  17. package/dist/bin/explorbot-cli.js +26 -8
  18. package/dist/boat/api-tester/bin/apibot-cli.js +2 -0
  19. package/dist/boat/api-tester/src/cli.js +17 -0
  20. package/dist/boat/api-tester/src/config.js +4 -2
  21. package/dist/boat/doc-collector/bin/doc-collector-cli.js +2 -0
  22. package/dist/boat/doc-collector/src/ai/documentarian.js +44 -19
  23. package/dist/boat/doc-collector/src/cli.js +14 -1
  24. package/dist/boat/doc-collector/src/config.js +4 -2
  25. package/dist/boat/prima/src/activity-line.js +30 -0
  26. package/dist/boat/prima/src/cli.js +109 -77
  27. package/dist/boat/prima/src/envelope.js +94 -44
  28. package/dist/boat/prima/src/prima.js +533 -119
  29. package/dist/boat/prima/src/pw-parser.js +13 -1
  30. package/dist/boat/prima/src/pw-registry.js +4 -5
  31. package/dist/boat/prima/src/session-log.js +108 -0
  32. package/dist/package.json +3 -2
  33. package/dist/rules/navigator/verification-actions.md +20 -0
  34. package/dist/src/action-result.d.ts +7 -0
  35. package/dist/src/action-result.js +4 -0
  36. package/dist/src/action.d.ts +2 -0
  37. package/dist/src/action.js +41 -2
  38. package/dist/src/ai/captain/web-mode.js +6 -3
  39. package/dist/src/ai/captain.js +2 -0
  40. package/dist/src/ai/navigator.d.ts +34 -0
  41. package/dist/src/ai/navigator.js +237 -181
  42. package/dist/src/ai/pilot.d.ts +7 -0
  43. package/dist/src/ai/pilot.js +90 -2
  44. package/dist/src/ai/provider.d.ts +2 -2
  45. package/dist/src/ai/provider.js +14 -23
  46. package/dist/src/ai/rerunner.js +2 -1
  47. package/dist/src/ai/researcher/cache.d.ts +2 -0
  48. package/dist/src/ai/researcher/cache.js +10 -2
  49. package/dist/src/ai/researcher.js +3 -2
  50. package/dist/src/ai/rules.js +17 -10
  51. package/dist/src/ai/session-analyst.js +2 -0
  52. package/dist/src/ai/task-agent.js +4 -1
  53. package/dist/src/ai/tester.d.ts +6 -3
  54. package/dist/src/ai/tester.js +50 -46
  55. package/dist/src/ai/tools.d.ts +14 -0
  56. package/dist/src/ai/tools.js +117 -37
  57. package/dist/src/commands/config-command.d.ts +51 -0
  58. package/dist/src/commands/config-command.js +117 -0
  59. package/dist/src/commands/index.js +2 -0
  60. package/dist/src/config.d.ts +9 -1
  61. package/dist/src/config.js +53 -4
  62. package/dist/src/execution-controller.d.ts +2 -0
  63. package/dist/src/execution-controller.js +6 -0
  64. package/dist/src/explorbot.d.ts +2 -1
  65. package/dist/src/explorbot.js +7 -2
  66. package/dist/src/explorer.js +2 -3
  67. package/dist/src/playwright-recorder.js +30 -0
  68. package/dist/src/remote.d.ts +55 -0
  69. package/dist/src/remote.js +235 -0
  70. package/dist/src/reporter.d.ts +1 -0
  71. package/dist/src/reporter.js +7 -1
  72. package/dist/src/state-manager.d.ts +2 -1
  73. package/dist/src/state-manager.js +3 -1
  74. package/dist/src/stats.d.ts +1 -0
  75. package/dist/src/stats.js +1 -0
  76. package/dist/src/test-plan.d.ts +3 -0
  77. package/dist/src/test-plan.js +26 -0
  78. package/dist/src/utils/aria.d.ts +2 -8
  79. package/dist/src/utils/aria.js +69 -40
  80. package/dist/src/utils/html.js +1 -0
  81. package/dist/src/utils/logger.d.ts +7 -1
  82. package/dist/src/utils/logger.js +32 -0
  83. package/dist/src/utils/page-readiness.js +18 -1
  84. package/dist/src/utils/url-matcher.js +3 -0
  85. package/dist/src/utils/web-element.d.ts +2 -0
  86. package/dist/src/utils/web-element.js +8 -0
  87. package/dist/src/utils/web-sandbox.d.ts +1 -1
  88. package/dist/src/utils/web-sandbox.js +2 -3
  89. package/docs/api-testing/basics.md +90 -0
  90. package/docs/api-testing/planning.md +57 -0
  91. package/docs/api-testing/running-tests.md +55 -0
  92. package/docs/assets/cloud-report.png +0 -0
  93. package/docs/assets/html-report.png +0 -0
  94. package/docs/assets/langfuse-trace.png +0 -0
  95. package/docs/assets/successful-explore-run.png +0 -0
  96. package/docs/basics/getting-started.md +140 -0
  97. package/docs/basics/prerequisites.md +63 -0
  98. package/docs/basics/providers.md +362 -0
  99. package/docs/basics/running.md +78 -0
  100. package/docs/contributing/ai-integration-tests.md +57 -0
  101. package/docs/contributing/contributing.md +90 -0
  102. package/docs/contributing/demo-videos.md +36 -0
  103. package/docs/contributing/npm-package.md +138 -0
  104. package/docs/contributing/observability.md +227 -0
  105. package/docs/contributing/regression-tests.md +103 -0
  106. package/docs/contributing/testing.md +95 -0
  107. package/docs/doc-collection/basics.md +128 -0
  108. package/docs/doc-collection/crawling.md +67 -0
  109. package/docs/doc-collection/interactive-mode.md +99 -0
  110. package/docs/index.json +87 -0
  111. package/docs/reference/commands.md +997 -0
  112. package/docs/reference/configuration.md +569 -0
  113. package/docs/reference/scripting.md +303 -0
  114. package/docs/reference/websocket.md +50 -0
  115. package/docs/superpowers/plans/2026-08-01-actor-boat.md +925 -0
  116. package/docs/superpowers/plans/2026-08-01-prima-boat.md +1120 -0
  117. package/docs/superpowers/reviews/2026-08-06-prima-vs-playwright-cli.md +268 -0
  118. package/docs/superpowers/specs/2026-08-01-actor-boat-design.md +204 -0
  119. package/docs/superpowers/specs/2026-08-01-prima-boat-design.md +242 -0
  120. package/docs/superpowers/specs/2026-08-03-global-config-design.md +138 -0
  121. package/docs/superpowers/specs/2026-08-07-prima-fixes-design.md +394 -0
  122. package/docs/superpowers/specs/2026-08-18-prima-false-verdicts.md +159 -0
  123. package/docs/web-testing/agents.md +158 -0
  124. package/docs/web-testing/automated-tests.md +134 -0
  125. package/docs/web-testing/basics.md +91 -0
  126. package/docs/web-testing/customization.md +131 -0
  127. package/docs/web-testing/hooks.md +238 -0
  128. package/docs/web-testing/page-interaction.md +84 -0
  129. package/docs/web-testing/planner.md +122 -0
  130. package/docs/web-testing/rerun.md +164 -0
  131. package/docs/web-testing/researcher.md +380 -0
  132. package/docs/workflow/agentic-usage.md +233 -0
  133. package/docs/workflow/application-spec.md +73 -0
  134. package/docs/workflow/ci.md +202 -0
  135. package/docs/workflow/knowledge.md +310 -0
  136. package/docs/workflow/planning-styles.md +67 -0
  137. package/docs/workflow/reporting.md +133 -0
  138. package/docs/workflow/test-plans.md +90 -0
  139. package/package.json +3 -2
  140. package/rules/navigator/verification-actions.md +20 -0
  141. package/src/action-result.ts +11 -0
  142. package/src/action.ts +43 -3
  143. package/src/ai/captain/web-mode.ts +6 -3
  144. package/src/ai/captain.ts +3 -0
  145. package/src/ai/navigator.ts +255 -186
  146. package/src/ai/pilot.ts +104 -2
  147. package/src/ai/provider.ts +14 -24
  148. package/src/ai/rerunner.ts +2 -1
  149. package/src/ai/researcher/cache.ts +12 -2
  150. package/src/ai/researcher.ts +3 -2
  151. package/src/ai/rules.ts +17 -10
  152. package/src/ai/session-analyst.ts +2 -0
  153. package/src/ai/task-agent.ts +3 -1
  154. package/src/ai/tester.ts +52 -45
  155. package/src/ai/tools.ts +136 -37
  156. package/src/commands/config-command.ts +146 -0
  157. package/src/commands/index.ts +2 -0
  158. package/src/config.ts +60 -5
  159. package/src/execution-controller.ts +8 -0
  160. package/src/explorbot.ts +7 -3
  161. package/src/explorer.ts +2 -2
  162. package/src/playwright-recorder.ts +23 -0
  163. package/src/remote.ts +244 -0
  164. package/src/reporter.ts +7 -1
  165. package/src/state-manager.ts +6 -2
  166. package/src/stats.ts +1 -0
  167. package/src/test-plan.ts +29 -0
  168. package/src/utils/aria.ts +65 -45
  169. package/src/utils/html.ts +1 -0
  170. package/src/utils/logger.ts +33 -2
  171. package/src/utils/page-readiness.ts +24 -1
  172. package/src/utils/url-matcher.ts +3 -0
  173. package/src/utils/web-element.ts +9 -0
  174. package/src/utils/web-sandbox.ts +3 -4
@@ -0,0 +1,268 @@
1
+ # Prima boat vs playwright-cli — field review
2
+
3
+ **Date:** 2026-08-06
4
+ **Target:** Testeiya Agent (`localhost:3050`) — sidebar Workflows section + Skill editor
5
+ **Setup:** global config (`~/.explorbot/config.js`), no project config
6
+ **Models:** `groq/openai/gpt-oss-20b` (model), `openrouter/gpt-5.6-luna` (vision + agentic)
7
+ **Comparator:** `@playwright/cli` 0.1.13
8
+ **Method:** drive the feature with prima, fall back to playwright-cli whenever prima stalled
9
+
10
+ ---
11
+
12
+ ## Verdict up front
13
+
14
+ Prima is not a replacement for playwright-cli today. It is a strong *complement*: two of its
15
+ commands (`verify`, `ask`) do work playwright-cli cannot do at all, and four defects stop it
16
+ from owning the driving loop. Recommended split as it stands:
17
+
18
+ - **playwright-cli** — attach, navigate, read page state, drive verified locators.
19
+ - **prima** — `verify` for assertions, `ask` for visual judgement, `--no-heal` for a failure
20
+ report you can retarget from.
21
+
22
+ ---
23
+
24
+ ## The feature under test — it works
25
+
26
+ Everything the sidebar Workflow and Skill editor promises checked out.
27
+
28
+ **Workflows section**
29
+
30
+ - The rail button opens a Workflows panel with five categories: Analysis & Planning,
31
+ Test Design & Management, Test Execution & Automation, Reporting/CI-CD & Quality Gates,
32
+ Metrics/Release & Analytics.
33
+ - Accordion is single-open; the first category is expanded by default and lists its four
34
+ prompts (Review requirements, Risk-based focus, Analyze PR requirements, Analyze PR diff).
35
+ - "Workflow overview" opens the diagram dialog. Vision check and my own screenshot agree:
36
+ a clean left-to-right five-stage pipeline, arrows between stages, nothing clipped or
37
+ overlapping.
38
+
39
+ **Skill editor**
40
+
41
+ - Skills popover lists 42 skills with category filter chips.
42
+ - Row actions menu offers "Change skill globally", "Edit for this project", "Disable".
43
+ - The editor opens with the skill markdown loaded, Save disabled.
44
+ - Typing flips the header to `● unsaved` and enables Save.
45
+ - "Close editor" discards: no file appeared under `~/.testeiya/skills/`, and the agent
46
+ repo's `git status` stayed clean.
47
+
48
+ One cosmetic thing worth a look: the filter chips include single-item categories named
49
+ after the skill itself — "Playwright Best Practices Skill 1", "Playwright Cli 1" — next to
50
+ real groupings like "Test Management 12". Category derivation looks like it falls back to
51
+ the skill name when a skill has no category.
52
+
53
+ ---
54
+
55
+ ## Where prima was better
56
+
57
+ **1. `verify` — the standout.** One command turns a sentence into a pass/fail *and* the
58
+ assertion code that proved it.
59
+
60
+ ```
61
+ prima verify "the sidebar Workflows section lists five workflow categories, and the
62
+ Analysis & Planning category is expanded showing individual workflow prompts"
63
+ → 14.8s, passed: true
64
+ I.seeElement({"role":"button","text":"Analysis & Planning"});
65
+ ... all five categories ...
66
+ I.see('Review requirements', '#base-ui-_r_2al_'); ... all four prompts ...
67
+ ```
68
+
69
+ With playwright-cli the same check is snapshot → read the tree myself → write five
70
+ assertions by hand. Prima did it in one call, and the output is reusable test material.
71
+ This is the command that justifies the boat.
72
+
73
+ **2. `ask` — visual judgement with no image in my context.**
74
+
75
+ ```
76
+ prima ask "Is the workflow diagram laid out as a readable left-to-right pipeline,
77
+ or is anything visually broken, overlapping or cut off?"
78
+ → 8.7s, correct answer
79
+ ```
80
+
81
+ I checked it against the PNG afterwards and it was right. playwright-cli can only hand me
82
+ a file; *I* have to look at it, and the image lands in my context permanently.
83
+
84
+ **3. Descriptions outlive refs.** playwright-cli refs (`e13`, `e26`, `e647`) are snapshot-scoped.
85
+ This app re-renders constantly, so every interaction meant re-snapshotting for fresh refs —
86
+ 8k bytes each time. `prima click "the Workflows button in the left vertical sidebar rail"`
87
+ needs no prior read at all.
88
+
89
+ **4. Artifacts stay on disk.** Every envelope wrote `aria.yml` / `page.html` and cited absolute
90
+ paths. `page.html` was 376K and never entered my context. That is the design goal, delivered.
91
+
92
+ **5. The `--no-heal` failure envelope is exactly right.**
93
+
94
+ ```
95
+ prima pw '({page}) => page.click("[data-test=nonexistent-thing]", {timeout:3000})' --no-heal
96
+ → 8.6s, ok: false
97
+ error: page.click: Timeout 3000ms exceeded. Call log: waiting for locator(...)
98
+ ### Current page (compact ARIA) ← enough to retarget, without the full tree
99
+ ```
100
+
101
+ Error plus a compact ARIA snapshot in one response is better than what playwright-cli gives
102
+ on a failed click, which is the error alone.
103
+
104
+ ---
105
+
106
+ ## Where playwright-cli was better
107
+
108
+ **1. Speed — one to two orders of magnitude.** `snapshot` returned in **0.2–0.3s**. Prima's
109
+ cheapest command was 6.1s; the median was ~12s; `go` took **3m00s** and one owned-browser
110
+ `verify` took **2m32s**. Across ~17 prima commands I spent roughly ten minutes waiting.
111
+
112
+ **2. It does exactly what you asked — nothing else.** `prima do` given two instructions
113
+ ("close the dialog", "open the Skills menu") performed both and then kept going: searched the
114
+ skill list for "playwright-cli" and inserted the skill, leaving `/playwright-cli` typed into a
115
+ live chat box. Two instructions in, four actions out, `ok: true`. Prima's `go` did the same
116
+ during recovery — it clicked "Workspace", "Show panel", pressed F5 and clicked "Cancel" while
117
+ merely trying to navigate. playwright-cli has never once done something I did not type.
118
+
119
+ **3. Attach just works.** playwright-cli opened and reattached to its own browser with no
120
+ ceremony. Prima could not attach at all without hand-patching a file (details below).
121
+
122
+ **4. `eval` reaches state prima cannot express.** The one assertion prima got wrong —
123
+ "is Save enabled now?" — was a one-liner for playwright-cli:
124
+
125
+ ```
126
+ $PW eval '() => [...document.querySelectorAll("button")].filter(b=>/Save/.test(b.textContent))
127
+ .map(b=>({t:b.textContent.trim(), disabled:b.disabled}))'
128
+ → [{ "t": "saveSave", "disabled": false }]
129
+ ```
130
+
131
+ playwright-cli's snapshot also carries `[disabled]`, `[pressed]`, `[active]` inline. Prima's
132
+ UI map carries none of that.
133
+
134
+ **5. Honest failures.** playwright-cli never told me an action succeeded when it hadn't.
135
+ Prima did (see #1 below).
136
+
137
+ **6. `research` costs more context than a snapshot, not less.** The one `research` call
138
+ returned ~5k tokens of UI-map markdown — versus 8,110 bytes (~2k tokens) for a full
139
+ playwright-cli snapshot of the same page. Its locators were also worse: generated Base-UI ids
140
+ (`button#base-ui-_R_qcmpbmulb_`) and positional CSS chains
141
+ (`div:nth-of-type(1) > div > div:nth-of-type(1) > div`), neither of which survives a re-render.
142
+ Prima's own compact-ARIA failure block is the cheaper, better read.
143
+
144
+ ---
145
+
146
+ ## Defects found in prima, worst first
147
+
148
+ **1. Heal converts a failed action into a different action and reports success.**
149
+
150
+ ```
151
+ prima pw '({page}) => page.click("[data-test=nonexistent-thing]", {timeout:3000})'
152
+ → ok: true
153
+ healed: true (recovered after 1 attempt)
154
+ used: // Click the "New agent" button
155
+ I.click({ role: "button", text: "New agent" });
156
+ ```
157
+
158
+ The requested element does not exist. Heal did not find another route to the same intent —
159
+ there was no such intent to reach. It picked an unrelated control, clicked it, and returned
160
+ `ok: true`. An orchestrator that trusts the envelope believes its own action landed. Heal
161
+ should only re-route toward the *same* target; when the target cannot be identified, the
162
+ correct answer is the `--no-heal` envelope.
163
+
164
+ **2. `verify` false-negatives with no diagnostic.**
165
+
166
+ ```
167
+ prima verify "the Save button in the skill editor is now enabled because the skill
168
+ content has unsaved changes"
169
+ → passed: false
170
+ evidence: no assertion held on the current page
171
+ code: (empty)
172
+ ```
173
+
174
+ The app was working — `● unsaved` was displayed and Save was enabled.
175
+
176
+ The cause is the vocabulary, not the model. `rules/navigator/verification-actions.md` offers
177
+ exactly nine assertions — `see`, `seeElement`, `seeInField`, `seeInTitle`, `seeInSource` and
178
+ their `dontSee*` counterparts — none of which express enabled/disabled/checked/selected, and
179
+ the rules additionally steer away from attribute selectors (`NEVER use ':has-text(...)'`,
180
+ "never check value via CSS attribute selectors"). So a claim about interactive state is
181
+ unprovable by construction, and prima reports that as the *feature* failing rather than as a
182
+ check it could not express. Empty `code:` and a generic evidence line leave no way to tell
183
+ "the app is broken" from "I could not phrase this".
184
+
185
+ **3. Auto-discovery of a playwright-cli session cannot work; `--endpoint` needs playwright 1.62.**
186
+
187
+ > **Corrected 2026-08-07 after re-testing.** The original run was on explorbot's pinned
188
+ > playwright **1.60.0** against a 1.61.0-alpha daemon, and concluded attach was broken
189
+ > outright. That was a stale-dependency artifact. Re-tested with `playwright@1.62.1` and
190
+ > `@playwright/cli@0.1.17` (playwright 1.62.0-alpha): `chromium.connect()` succeeds with
191
+ > **our own** playwright, and `prima verify --endpoint <sock>` returns `ok: true` in 16.6s.
192
+ > Upgrading the pin fixes the connect half. What remains is discovery.
193
+
194
+ - **Version skew (fixed by upgrading).** `playwright@^1.60` could not `connect()` to a
195
+ 1.61/1.62 browser server — it timed out. `playwright@1.62.1` connects to both its own
196
+ minor and the 1.62.0-alpha daemon. The pin should move to `^1.62`.
197
+ - **Missing `workspaceDir` (still broken).** No `@playwright/cli` release writes a
198
+ `workspaceDir` field into `~/.cache/ms-playwright/b/browser@<guid>` — verified on 0.1.13
199
+ and 0.1.17. `parseDescriptor` (`boat/prima/src/pw-registry.ts:56`) requires it, so every
200
+ descriptor is dropped, `selectDescriptor` filters on a field that never exists, and
201
+ auto-discovery finds nothing no matter what version is installed. Prima cannot attach
202
+ without `--endpoint` unless it stops keying on `workspaceDir`.
203
+ - **The failure message sends you in a circle.** With a session open, discovery fails with
204
+ "No browser to drive... Open one first: `playwright-cli open <url>`" — advising exactly
205
+ what the user already did. `prima browser list` likewise reports "no browser instances
206
+ running" while a session is live.
207
+
208
+ **4. A redirect that appends query params is treated as failed navigation.** The app sends
209
+ `/` → `/?session=<uuid>&ws=1`. `prima go http://localhost:3050` burned **3 minutes** and eight
210
+ attempts before healing; against prima's own browser the same navigation ended in a hard tool
211
+ error after **2m32s** —
212
+
213
+ ```
214
+ error: tool: Navigation to / failed: redirected to /?session=...&ws=1 and could not resolve
215
+ ```
216
+
217
+ — in an envelope whose own inlined ARIA proves the page had loaded correctly. Session-param
218
+ redirects are common enough that this alone blocks unattended use.
219
+
220
+ ### Smaller issues
221
+
222
+ - **`used:` is often not runnable.** `click` concatenated all five ladder attempts, including
223
+ invalid JS: `I.click(".sidebar button:has-text("Workflows")")`. `do` emitted a
224
+ `// 1. Open dialog...` comment line inside the code. The spec promises "the exact code that
225
+ worked" — it should be the winning line only.
226
+ - **`### Changes` / ariaDiff never appeared** in any successful envelope. That block is the
227
+ envelope's core evidence promise; without it, a successful `click` proves nothing and I had
228
+ to spend a playwright-cli snapshot to confirm every action.
229
+ - **`network.jsonl` is advertised in every envelope and was 0 bytes in all 18 runs.**
230
+ - **`click` reports itself as `do`.** Every `click` envelope printed `command: do "..."`.
231
+ - **Every command requires a URL** even when attached to a browser already sitting on the page,
232
+ and even when the site is registered. `EXPLORBOT_URL` satisfies config loading but not page
233
+ opening on an empty owned browser, which needs `--url` as well.
234
+ - **Prima pollutes a shared browser.** After `research`, the visual-annotation overlays
235
+ (`Legend`, `e8`, `e10`, …) were still in the live DOM and showed up in the next
236
+ playwright-cli snapshot.
237
+
238
+ ### Environment friction (not prima's design)
239
+
240
+ - **`node_modules` is a committed, self-referential symlink.** `git ls-files -s node_modules`
241
+ shows mode `120000` pointing at `/home/davert/projects/explorbot/node_modules` — itself.
242
+ It was added in `7cc52eb` ("Let EXPLORBOT_* variables win over the global config"). Being
243
+ tracked, it overrides the `node_modules/` line in `.gitignore`. Every Node resolution fails
244
+ with `ELOOP` / "Too many levels of symbolic links", so `npx tsc`, the build, and the CLI are
245
+ all dead on a fresh checkout of this branch. Removing it and running `bun install` fixes it.
246
+ - `bun run build:npm` fails with `env: unknown error: execvp failed`; `bash scripts/build-npm.sh`
247
+ works.
248
+ - The `prima` bin is not exposed by the existing global npm link — `explorbot prima ...` only.
249
+ - Prima needs the Node build for browser-server endpoints, so `dist/` must exist before any of
250
+ this runs.
251
+
252
+ ---
253
+
254
+ ## What would make prima a replacement
255
+
256
+ In priority order:
257
+
258
+ 1. Heal must never substitute a different target; unresolvable intent → failure envelope.
259
+ 2. `verify` must distinguish "assertion failed" from "cannot express this assertion", and
260
+ `rules/navigator/verification-actions.md` needs state assertions
261
+ (enabled/disabled/checked/selected) alongside the nine text/presence ones it has now.
262
+ 3. Treat a redirect that preserves origin and path as navigation success.
263
+ 4. Move the playwright pin to `^1.62` (fixes `--endpoint`), and stop keying discovery on
264
+ `workspaceDir` — no `@playwright/cli` release emits it.
265
+ 5. Emit `### Changes` on every action, and reduce `used:` to the winning line.
266
+
267
+ With 1–3 fixed, prima could own the assertion and inspection half of a session outright.
268
+ Driving would still belong to playwright-cli until the per-command latency comes down.
@@ -0,0 +1,204 @@
1
+ # Actor Boat — High-Level Browser Driver for Orchestrating Agents
2
+
3
+ **Date:** 2026-08-01
4
+ **Status:** Draft for review
5
+ **Implementation model:** Opus
6
+
7
+ ## Problem
8
+
9
+ Coding agents (Claude Code on Opus/Fable) drive browsers through playwright-cli or Playwright MCP. Every action forces page state (aria snapshots) into the orchestrator's context: the expensive model pays to read the tree, pick a ref, and re-read after every step, and each snapshot stays in conversation history compounding cost for the rest of the session. A 20-step flow means 20+ expensive perception roundtrips.
10
+
11
+ Explorbot already owns the layers that fix this: cheap-model perception (Navigator, Researcher), semantic diffs (ariaDiff, pageDiff), state tracking, and experience replay. The Actor boat exposes those layers as an intent-level CLI so the orchestrator sends instructions and receives compact evidence — page data never enters the expensive context on the happy path.
12
+
13
+ ## Goals
14
+
15
+ - Orchestrator issues precise Playwright calls or natural-language instructions; explorbot's cheap models run the perception–action micro-loop.
16
+ - Every response is a uniform envelope: evidence of what happened, never a raw page dump.
17
+ - Failures exhaust cheap healing first, then return a compacted investigation so the orchestrator can drop down a level and drive directly.
18
+ - Zero project setup: works from any directory via env vars and a global user config, with per-host persistent state.
19
+ - Every successful action reports the exact code that worked, so sessions double as verified-locator material for test generation.
20
+
21
+ ## Non-Goals
22
+
23
+ - Not a replacement for playwright-cli as a general browser tool.
24
+ - No MCP server, no SKILL.md package in v1 — the contract is taught entirely by `--help` text.
25
+ - No new core agents unless heal orchestration proves to need one (then it lives inside the boat).
26
+
27
+ ## Architecture
28
+
29
+ A boat, following the existing `boat/api-tester` / `boat/doc-collector` pattern:
30
+
31
+ ```
32
+ boat/actor/
33
+ ├── package.json # name: "actbot", own bin
34
+ ├── bin/actbot-cli.ts # standalone CLI
35
+ └── src/
36
+ ├── cli.ts # createActCommands('act') → composed into main CLI
37
+ ├── actor.ts # Actor class wrapping ExplorBot (like DocBot)
38
+ ├── envelope.ts # result envelope: inline render + artifact files
39
+ └── config.ts
40
+ ```
41
+
42
+ Registered in `bin/explorbot-cli.ts` via `program.addCommand(createActCommands('act'))`. The `Actor` class wraps `ExplorBot`, reusing `agentNavigator()`, `agentResearcher()`, `stateManager()`, Historian, and the Explorer/Action capture pipeline. Business logic lives in the Actor class and agents; CLI handlers stay thin, per repo convention.
43
+
44
+ ## Command Surface
45
+
46
+ ```
47
+ explorbot act pw "({ page }) => page.click('text=Login')" # raw Playwright fn, healed on failure
48
+ explorbot act do "click the login link" # NL action via Navigator
49
+ explorbot act click "Login" # targeted click via existing fallback ladder
50
+ explorbot act fill "Search" "wireless mouse" # targeted fill via existing ladder
51
+ explorbot act ask "what do I see here?" # cheap-model page Q&A via Researcher
52
+ explorbot act research [--data] [--deep] [--fresh] # verified UI map for precise pw driving
53
+ explorbot act verify "user is logged in" # AI assertion (alias: assert)
54
+ explorbot act go "billing settings" # URL or NL navigation
55
+ explorbot act browser start|stop|status|list # instance management (stop --all)
56
+ ```
57
+
58
+ Tiering: `pw` = precise (no AI on happy path), `click`/`fill` = targeted with deterministic fallback ladders (AI only on ambiguity), `do` = intent (cheap-model planning). `select`, `pressKey`, `hover`, `drag` intentionally stay behind `pw` — a subcommand without a ladder is surface without value.
59
+
60
+ ### Common flags
61
+
62
+ - `--instance <name>` / `-i` — which named browser daemon to talk to. Default instance otherwise.
63
+ - `--session [file]` — existing auth-session semantics; an autostarted instance launches with the saved cookies/storage state.
64
+ - `--no-heal` — fail fast without cheap-model recovery.
65
+ - `--ephemeral` — throwaway temp state dir instead of the per-host persistent one.
66
+ - `--framework playwright|codeceptjs` — output dialect for `used:` code (default from `ai.agents.historian.framework`).
67
+ - `--vision` — force screenshot pass for `ask`.
68
+
69
+ ### Execution paths
70
+
71
+ - **pw**: the argument is a function expression in the exact shape `I.usePlaywrightTo` accepts — `({ page, browserContext, browser }) => ...` — checked only for being a parseable function, then interpolated directly into `I.usePlaywrightTo('pw', <fn>)` and executed through the Explorer/Action pipeline so state capture, ariaDiff, and experience recording come for free. Destructure whichever Playwright objects the call needs. Deterministic and near-instant on the happy path.
72
+ - **do**: one bounded Navigator invocation (max ~3 tool roundtrips) reusing the existing click/type/form tool ladders. Deterministic fast path first: if the instruction resolves to exactly one interactive ARIA node by role+name, execute with zero AI calls.
73
+ - **click / fill**: the existing multi-fallback ladders directly (text → ARIA → experience candidates); cheap-model disambiguation only when multiple candidates match.
74
+ - **ask**: Researcher answers from current compact ARIA / cached UI map; `--vision` routes through the vision model. Non-mutating.
75
+ - **research**: `researcher.research(state, { screenshot: true, data, deep, force })`. The envelope's `### Research` section carries the UI map inline — it is the deliverable: verified, live-tested locators that let the orchestrator drive `pw` precisely without reading raw ARIA. `--data` adds extracted data sections, `--deep` deep analysis, `--fresh` bypasses the cache; cached results keep the existing staleness banner. Non-mutating.
76
+ - **verify / assert**: `navigator.verifyState()` on the cheap model; verdict plus the assertion code that proved it.
77
+ - **go**: URL-shaped input navigates directly; intent-shaped input uses Navigator's stateful navigation with visited-state history and knowledge. Autostarts the instance like every other command.
78
+
79
+ ### Examples of `do`
80
+
81
+ - `act do "click the login link"` → ARIA has one `link "Login"` → `I.click('Login')`, zero AI.
82
+ - `act do "search for 'wireless mouse'"` → cheap model plans fill + Enter → both lines reported in `used:`.
83
+ - `act do "dismiss the cookie banner"` → ambiguous → cheap model picks `button "Accept all"` from compact ARIA.
84
+ - `act do "open the newest invoice"` → list interpretation → cheap model over the UI map picks the first row link.
85
+
86
+ ## The Envelope
87
+
88
+ The uniform response contract: every command prints the same block structure in the same order to stdout, success or failure. Two jobs: evidence (prove what happened without showing the page) and housekeeping (what is open, what to clean up, where to dig deeper).
89
+
90
+ ### Success (~200–400 tokens inline)
91
+
92
+ ```
93
+ ### Result
94
+ ok: true
95
+ command: pw ({ page }) => page.click('text=Login')
96
+ healed: false
97
+ used: I.click('Login')
98
+
99
+ ### Page
100
+ url: https://app.example.com/dashboard (changed: /login → /dashboard)
101
+ title: Dashboard
102
+ state: dashboard_h1_dashboard (new state, visit #1)
103
+
104
+ ### Changes
105
+ ariaDiff:
106
+ added:
107
+ - heading "Dashboard"
108
+ - button "New Project"
109
+ removed:
110
+ - textbox "Email"
111
+
112
+ ### Instance
113
+ instance: default (3 tabs) | other instances: auth-test (1 tab)
114
+ browser: running (started 12m ago)
115
+
116
+ ### Artifacts
117
+ aria: <abs path>/output/act/<ts>/aria.yml
118
+ html: <abs path>/output/act/<ts>/page.html
119
+ network: <abs path>/output/act/<ts>/network.jsonl
120
+ ```
121
+
122
+ - `used:` — the exact code that worked (healed form when healed), rendered in the configured framework via Historian's converters. Sessions thereby double as a verified-locator oracle for test generation.
123
+ - `### Changes` becomes `### Answer` for `ask`, `### Verdict` (pass/fail + evidence line + assertion code) for `verify`, and `### Research` (the UI map, inline) for `research`.
124
+ - `### Instance` appears on every response — tab counts and other live instances — so the orchestrator sees leftover state and knows to close it when finished.
125
+ - Artifact paths are always absolute; full HTML, full ARIA, and the network log are always written, never inlined.
126
+
127
+ ### Failure (after healing exhausted, ~1–2k tokens inline)
128
+
129
+ Same sections, plus:
130
+
131
+ ```
132
+ ### Failure
133
+ error: locator 'text=Login' not found (timeout 5s)
134
+
135
+ ### Healing attempts (3)
136
+ 1. I.click('Login') → not visible
137
+ 2. scroll + retry → covered by cookie banner
138
+ 3. click 'Accept cookies', retry → navigation timeout
139
+ reasoning (compacted): ~5-line cheap-model summary of what it observed and why each attempt was chosen
140
+
141
+ ### Current page (compact ARIA, inline)
142
+ - button "Accept cookies"
143
+ - link "Login"
144
+ ...
145
+ ```
146
+
147
+ Inline: ariaDiff, error, compact ARIA. On disk: full HTML, full ARIA, network log. The orchestrator investigates from the inline compact ARIA and reads artifact files only when it needs depth.
148
+
149
+ ## Heal Loop
150
+
151
+ On `pw`, `do`, `click`, or `fill` failure, the failing intent goes to Navigator's existing recovery ladder on the cheap model: alternative locators from ARIA/experience, scroll-into-view, overlay dismissal, retry. Capped at 3 attempts by default; `--no-heal` disables. Every attempt logs `{action, code, result, ariaDiff}`; reasoning is compacted to ~5 lines at the end. Heal success returns a success envelope with `healed: true` and writes the fix to experience so the next run replays it without AI. Heal exhaustion returns the failure envelope.
152
+
153
+ Tool errors (daemon unreachable, AI provider missing, invalid `pw` expression) are reported as `ok: false` with a `### Failure` naming the failed layer — never disguised as page failures.
154
+
155
+ ## Instances & Sessions
156
+
157
+ - Named browser daemons via `--instance`; state persists across CLI invocations through the existing `explorbot browser start` server and `.browser-endpoint` discovery.
158
+ - Any `act` command with no running daemon autostarts one for its instance; combined with `--session [file]`, the autostarted browser launches already authenticated.
159
+ - `act browser start|stop|status|list` manages instances explicitly; `stop --all` kills everything.
160
+
161
+ ## Config-Free Operation
162
+
163
+ Resolution ladder, first hit wins per setting:
164
+
165
+ 1. Project config — `explorbot.config.js|ts` in cwd.
166
+ 2. Global user config — `~/.config/explorbot/config.js|ts` (models, providers, keys).
167
+ 3. Env vars — existing `EXPLORBOT_*` set, from process env, cwd `.env`, or `~/.config/explorbot/.env`.
168
+
169
+ The ladder lives in core config loading (`buildEnvConfig` grows global-config and global-`.env` sources); the boat inherits it.
170
+
171
+ With no project config, working dirs move to a persistent per-host state dir:
172
+
173
+ ```
174
+ ~/.local/state/explorbot/<host>/
175
+ ├── experience/
176
+ ├── knowledge/
177
+ └── output/act/...
178
+ ```
179
+
180
+ Experience accumulates per target host across runs from any directory — zero-setup feel with memory. `--ephemeral` opts into a throwaway temp dir (CI, demos).
181
+
182
+ ## Discovery
183
+
184
+ `explorbot act --help` (and `actbot --help`) is the sole teaching surface: it must compactly document the envelope shape, heal semantics, tiering (`pw` vs `click`/`fill` vs `do`), instance/session flags, and the artifact-file pattern. Clean stdout throughout (no banner).
185
+
186
+ ## Testing
187
+
188
+ - Unit: envelope rendering (success, failure, ask/verify variants), `pw` expression validation, config ladder resolution.
189
+ - Integration: heal-loop prompts via the existing `@copilotkit/aimock` harness per `docs/contributing/ai-integration-tests.md`; fictional fixture data only.
190
+ - End-to-end smoke against a local fixture page: `pw` success, healed failure, exhausted failure, `do` fast path (zero AI), instance autostart with `--session`.
191
+
192
+ ## Decisions Log
193
+
194
+ - Heal-first on all action failures (not fail-fast, not opt-in). `--no-heal` escape hatch.
195
+ - Failure delivery: ariaDiff + error + compact ARIA inline; full HTML/ARIA/network as files.
196
+ - Full command surface in v1 (pw, do, click, fill, ask, verify/assert, go, browser mgmt).
197
+ - Discovery via `--help` only; no SKILL.md or MCP in v1.
198
+ - Boat architecture (`boat/actor`, namespace `act`), not core commands.
199
+ - `--instance` for daemon switching; `--session` keeps existing auth-state meaning.
200
+ - Persistent per-host state dir by default in config-free mode; `--ephemeral` for temp.
201
+ - `used:` code in envelope via Historian converters; `verify` exposes assertion code.
202
+ - click/fill exposed as ladder-backed sugar; select/pressKey/hover/drag stay behind `pw`.
203
+ - `research` exposed with `--data`/`--deep`/`--fresh`; UI map inline as the deliverable (verified locators enable precise `pw` driving).
204
+ - Implementation runs on Opus.