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,242 @@
1
+ # Prima 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 Prima 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/prima/
33
+ ├── package.json # name: "prima", own bin
34
+ ├── bin/prima-cli.ts # standalone CLI
35
+ └── src/
36
+ ├── cli.ts # createPrimaCommands('prima') → composed into main CLI
37
+ ├── prima.ts # Prima 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(createPrimaCommands('prima'))`. The `Prima` class wraps `ExplorBot`, reusing `agentNavigator()`, `agentResearcher()`, `stateManager()`, Historian, and the Explorer/Action capture pipeline. Business logic lives in the Prima class and agents; CLI handlers stay thin, per repo convention.
43
+
44
+ ## Command Surface
45
+
46
+ ```
47
+ explorbot prima pw "({ page }) => page.click('text=Login')" # raw Playwright fn, healed on failure
48
+ explorbot prima do "click the login link" # NL action via Navigator
49
+ explorbot prima click "the login link" # single AI-resolved action (alias over do)
50
+ explorbot prima fill "search box" "wireless mouse" # single AI-resolved fill (alias over do)
51
+ explorbot prima ask "what do I see here?" # cheap-model page Q&A via Researcher
52
+ explorbot prima research [--data] [--deep] [--fresh] # verified UI map for precise pw driving
53
+ explorbot prima verify "user is logged in" # AI assertion (alias: assert)
54
+ explorbot prima go "billing settings" # URL or NL navigation
55
+ explorbot prima browser start|stop|status|list # instance management (stop --all)
56
+ ```
57
+
58
+ Tiering: `pw` = precise, no AI — for when the orchestrator already holds a verified locator (from `research`) or drives via playwright-cli conventions; `click`/`fill` = one high-level action, always AI-resolved — the orchestrator never sees ARIA/HTML, so "the login link" is a description, not a locator, and the cheap model resolves it against the page; `do` = a set of high-level instructions executed tester-style in one AI loop. There are NO deterministic no-AI paths in the NL commands — precision without AI is exactly what `pw`/playwright-cli exist for, and duplicating it here would be surface without value. `select`, `pressKey`, `hover`, `drag` stay behind `pw`.
59
+
60
+ ### Common flags
61
+
62
+ - `--endpoint <ep>` / `--pw-session <title>` — attach to a specific Playwright-protocol browser server (playwright-cli registry) instead of the ladder's automatic pick.
63
+ - `--instance <name>` / `-i` — which named prima-owned browser daemon to talk to when not attached. Default instance otherwise.
64
+ - `--session [file]` — existing auth-session semantics; a browser launched via explicit `prima browser start` loads the saved cookies/storage state. Ignored in attached mode.
65
+ - `--no-heal` — fail fast without cheap-model recovery.
66
+ - `--ephemeral` — throwaway temp state dir instead of the per-host persistent one.
67
+ - `--framework playwright|codeceptjs` — output dialect for `used:` code (default from `ai.agents.historian.framework`).
68
+ - `--no-vision` — `ask` answers from compact ARIA/UI map instead of the default screenshot pass.
69
+
70
+ ### Execution paths
71
+
72
+ - **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.
73
+ - **do**: takes one or more high-level instructions and performs them tester-style — a bounded cheap-model loop over the existing CodeceptJS tools (click/type/form ladders), holding page context (compact ARIA + relevant experience) the orchestrator never sees, iterating until the instructions are done or the budget is exhausted. Multi-step by design: `prima do "open the first invoice" "download its PDF"`.
74
+ - **click / fill**: shorter aliases over the same AI resolution — a single instruction (`click <description>`, `fill <field description> <value>`) resolved by the cheap model against the current page (Navigator-style state resolution) and executed via the tool ladders. Never deterministic: the caller supplies a description, not a locator.
75
+ - **ask**: vision by default — Researcher answers from a fresh screenshot via the vision model; `--no-vision` (or no `visionModel` configured, with a note in the envelope) falls back to compact ARIA / cached UI map. Non-mutating.
76
+ - **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.
77
+ - **verify / assert**: `navigator.verifyState()` on the cheap model; verdict plus the assertion code that proved it.
78
+ - **go**: URL-shaped input navigates directly; intent-shaped input uses Navigator's stateful navigation with visited-state history and knowledge. Like every command, requires an existing browser session — it never launches one.
79
+
80
+ ### Examples of `do`
81
+
82
+ - `prima do "click the login link"` → cheap model resolves the description against compact ARIA → `I.click('Login')`.
83
+ - `prima do "search for 'wireless mouse'"` → cheap model plans fill + Enter → both lines reported in `used:`.
84
+ - `prima do "dismiss the cookie banner"` → ambiguous → cheap model picks `button "Accept all"` from compact ARIA.
85
+ - `prima do "open the newest invoice"` → list interpretation → cheap model over the UI map picks the first row link.
86
+
87
+ ## The Envelope
88
+
89
+ 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).
90
+
91
+ ### Success (~200–400 tokens inline)
92
+
93
+ ```
94
+ ### Result
95
+ ok: true
96
+ command: pw ({ page }) => page.click('text=Login')
97
+ healed: false
98
+ used: I.click('Login')
99
+
100
+ ### Page
101
+ url: https://app.example.com/dashboard (changed: /login → /dashboard)
102
+ title: Dashboard
103
+ state: dashboard_h1_dashboard (new state, visit #1)
104
+
105
+ ### Changes
106
+ ariaDiff:
107
+ added:
108
+ - heading "Dashboard"
109
+ - button "New Project"
110
+ removed:
111
+ - textbox "Email"
112
+
113
+ ### Instance
114
+ instance: default (3 tabs) | other instances: auth-test (1 tab)
115
+ browser: running (started 12m ago)
116
+
117
+ ### Artifacts
118
+ aria: <abs path>/output/prima/<ts>/aria.yml
119
+ html: <abs path>/output/prima/<ts>/page.html
120
+ network: <abs path>/output/prima/<ts>/network.jsonl
121
+ ```
122
+
123
+ - `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.
124
+ - `### Changes` becomes `### Answer` for `ask`, `### Verdict` (pass/fail + evidence line + assertion code) for `verify`, and `### Research` (the UI map, inline) for `research`.
125
+ - `### Instance` appears on every response — tab counts and other live instances — so the orchestrator sees leftover state and knows to close it when finished.
126
+ - Artifact paths are always absolute; full HTML, full ARIA, and the network log are always written, never inlined.
127
+
128
+ ### Failure (after healing exhausted, ~1–2k tokens inline)
129
+
130
+ Same sections, plus:
131
+
132
+ ```
133
+ ### Failure
134
+ error: locator 'text=Login' not found (timeout 5s)
135
+
136
+ ### Healing attempts (3)
137
+ 1. I.click('Login') → not visible
138
+ 2. scroll + retry → covered by cookie banner
139
+ 3. click 'Accept cookies', retry → navigation timeout
140
+ reasoning (compacted): ~5-line cheap-model summary of what it observed and why each attempt was chosen
141
+
142
+ ### Current page (compact ARIA, inline)
143
+ - button "Accept cookies"
144
+ - link "Login"
145
+ ...
146
+ ```
147
+
148
+ 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.
149
+
150
+ ## Heal Loop
151
+
152
+ 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.
153
+
154
+ 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.
155
+
156
+ ## Connectivity — Sharing the Browser with playwright-cli
157
+
158
+ Prima is a smart layer over whatever browser already exists, not an owner of a competing one. Every playwright-cli daemon browser is auto-`bind()`-ed as a Playwright-protocol browser server (public `browser.bind()` API, Playwright 1.62+), with a descriptor JSON in `~/.cache/ms-playwright/b/<guid>`: `{ playwrightVersion, playwrightLib, title: <session name>, endpoint, workspaceDir, browser: { browserName, ... } }`. Connecting to `endpoint` yields the same live Browser — same contexts, same tabs — exactly what `playwright-cli attach` does internally.
159
+
160
+ **Browser resolution ladder (every prima command):**
161
+
162
+ 1. Explicit `--endpoint <ep>` (raw Playwright-protocol endpoint) or `--pw-session <title>` (registry lookup by title).
163
+ 2. `PLAYWRIGHT_CLI_SESSION` env, matched against registry titles for this workspace.
164
+ 3. Live registry descriptor with `workspaceDir` equal to the resolved cwd and `title` of `default`.
165
+ 4. Exactly one live descriptor for this workspace → use it; multiple → tool-error envelope listing candidate titles.
166
+ 5. A prima-owned instance previously started explicitly via `prima browser start` (`--instance` semantics below), if alive.
167
+ 6. Nothing available → **fail** with a tool-error envelope instructing the caller to create a session first: start one with playwright-cli (`playwright-cli open <url>`) — the preferred path — or `prima browser start`. Prima never launches a browser implicitly.
168
+
169
+ Descriptors may be stale — always liveness-probe (attempt connect) before selecting; skip dead ones. Version skew: prefer connecting with our own playwright-core; if the wire handshake rejects, load the daemon's own lib from `descriptor.playwrightLib` (the same trick playwright-cli uses).
170
+
171
+ **Attached-mode rules:** prima never closes a browser it did not launch — `prima browser stop` detaches only; `--session` (auth storage-state) is ignored in attached mode (the attached browser owns its cookies); prima adopts the browser's existing default context and active page rather than creating a fresh context. The envelope's `### Instance` block reports the attachment (`browser: attached (playwright-cli session "default", workspace <dir>)`) so the orchestrator knows this browser is not its to kill.
172
+
173
+ A CDP attach mode (`--cdp <url>`, for a user's real Chrome, CI browsers, or a playwright-cli browser with `launchOptions.args: ["--remote-debugging-port=..."]` injected via `.playwright/cli.config.json`) is a documented follow-up, not v1.
174
+
175
+ ## Instances & Sessions
176
+
177
+ - Named browser daemons via `--instance`; state persists across CLI invocations through the existing `explorbot browser start` server and `.browser-endpoint` discovery. Used only when the resolution ladder found no playwright-cli browser to attach to.
178
+ - No implicit launching: a `prima` command with no attachable browser and no running owned instance fails with the create-a-session guidance above.
179
+ - `prima browser start|stop|status|list` manages owned instances explicitly; `start` combined with `--session [file]` launches already authenticated; `stop --all` kills every owned instance (attached browsers are only detached). `list` shows owned instances and attachable playwright-cli sessions for this workspace.
180
+
181
+ ## Degraded Modes
182
+
183
+ Prima is a layer over playwright-cli, so when prima itself cannot help, its job is to say so and point back down:
184
+
185
+ - **No browser session** (ladder step 6 above): tool-error envelope with the create-a-session instruction. Exit code 1.
186
+ - **AI unavailable** — no provider configured, missing/expired credentials, provider errors at startup: commands that require a model (`do`, `click`, `fill`, `ask`, `verify`, `research`, intent-`go`) fail fast with a tool-error envelope stating the specific reason (general shape: which layer failed and why) and suggesting the fallback: use playwright-cli for direct browser control, or fix the AI config (`~/.explorbot/config.js` / `EXPLORBOT_AI_PROVIDER`). No partial AI attempts.
187
+ - **`pw` stays useful without AI**: it executes normally (it needs no model); healing is skipped with a `healed: false (ai unavailable)` note in the envelope. URL-`go` likewise works.
188
+
189
+ The distinction rule from the heal section applies everywhere: tool-layer failures (browser missing, AI missing, invalid input) are never disguised as page failures.
190
+
191
+ ## Config-Free Operation
192
+
193
+ Resolution ladder, first hit wins per setting:
194
+
195
+ 1. Project config — `explorbot.config.js|ts` in cwd.
196
+ 2. Global user config — `~/.explorbot/config.js|ts` (models, providers, keys).
197
+ 3. Env vars — existing `EXPLORBOT_*` set, from process env, cwd `.env`, or `~/.explorbot/.env`.
198
+
199
+ All global paths resolve through `os.homedir()`, so the same single directory works on Linux (`/home/<user>/.explorbot`), macOS (`/Users/<user>/.explorbot`), and Windows (`C:\Users\<user>\.explorbot`) — no per-OS conventions (XDG, Library, AppData) to document or branch on.
200
+
201
+ The ladder lives in core config loading (`buildEnvConfig` grows global-config and global-`.env` sources); the boat inherits it.
202
+
203
+ With no project config, working dirs move to a persistent per-host state dir:
204
+
205
+ ```
206
+ ~/.explorbot/sites/<host>/
207
+ ├── experience/
208
+ ├── knowledge/
209
+ └── output/prima/...
210
+ ```
211
+
212
+ Experience accumulates per target host across runs from any directory — zero-setup feel with memory. `--ephemeral` opts into a throwaway temp dir (CI, demos).
213
+
214
+ ## Discovery
215
+
216
+ `explorbot prima --help` (and `prima --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).
217
+
218
+ ## Testing
219
+
220
+ - Unit: envelope rendering (success, failure, ask/verify variants), `pw` expression validation, config ladder resolution.
221
+ - Integration: heal-loop prompts via the existing `@copilotkit/aimock` harness per `docs/contributing/ai-integration-tests.md`; fictional fixture data only.
222
+ - End-to-end smoke against a local fixture page: `pw` success, healed failure, exhausted failure, no-browser failure with create-a-session guidance, `pw` without AI (heal-skipped note); `do`/`click` covered by aimock integration tests (they always require a model), plus an AI-unavailable test asserting the playwright-cli fallback suggestion.
223
+
224
+ ## Decisions Log
225
+
226
+ - Heal-first on all action failures (not fail-fast, not opt-in). `--no-heal` escape hatch.
227
+ - Failure delivery: ariaDiff + error + compact ARIA inline; full HTML/ARIA/network as files.
228
+ - Full command surface in v1 (pw, do, click, fill, ask, verify/assert, go, browser mgmt).
229
+ - Discovery via `--help` only; no SKILL.md or MCP in v1.
230
+ - Boat architecture (`boat/prima`, namespace `prima`), not core commands.
231
+ - `--instance` for daemon switching; `--session` keeps existing auth-state meaning.
232
+ - Persistent per-host state dir by default in config-free mode; `--ephemeral` for temp.
233
+ - All global paths under a single cross-platform `~/.explorbot/` dir (config.js, .env, state/<host>/) — no XDG/Library/AppData branching.
234
+ - `ask` is vision-first; `--no-vision` opts into the ARIA text path.
235
+ - Prima attaches to playwright-cli's browser by default via the Playwright-protocol registry (`~/.cache/ms-playwright/b/`), matched by `workspaceDir` + session `title`; own daemon is the fallback, never the first choice.
236
+ - Attached browsers are never closed by prima; CDP attach (`--cdp`) deferred to a follow-up.
237
+ - No implicit browser launch: missing session → fail with "create one via playwright-cli" guidance; own daemon only via explicit `prima browser start`.
238
+ - AI unavailable → NL commands fail fast suggesting playwright-cli as fallback; `pw`/URL-`go` keep working with healing skipped.
239
+ - `used:` code in envelope via Historian converters; `verify` exposes assertion code.
240
+ - click/fill are single-instruction aliases over the same AI resolution as `do`; `do` accepts multiple high-level instructions run tester-style. No deterministic no-AI paths in NL commands — precision belongs to `pw`/playwright-cli. select/pressKey/hover/drag stay behind `pw`.
241
+ - `research` exposed with `--data`/`--deep`/`--fresh`; UI map inline as the deliverable (verified locators enable precise `pw` driving).
242
+ - Implementation runs on Opus.
@@ -0,0 +1,138 @@
1
+ # Global Configuration Mode
2
+
3
+ **Date:** 2026-08-03
4
+ **Status:** Approved in brainstorming, pending spec review
5
+
6
+ ## Problem
7
+
8
+ Explorbot requires a project directory with `explorbot.config.js`, or a stack of `EXPLORBOT_*` environment variables on every invocation. The env-var mode is deliberately stateless: output goes to a temp directory, experience is never written, the Historian is off. A coding agent that wants to explore a site it visited yesterday starts from zero.
9
+
10
+ The prima boat spec (`2026-08-01-prima-boat-design.md`) already commits to a global user config and per-host persistent state under `~/.explorbot`. This spec defines that mechanism for the whole tool — core commands and every boat — plus the `init --global` command that sets it up.
11
+
12
+ ## Goals
13
+
14
+ - `explorbot init --global` configures AI models and keys once, in `~/.explorbot`.
15
+ - Any explorbot command run from any directory uses that config when no project config exists.
16
+ - Each explored site gets a persistent subfolder under `~/.explorbot/sites/` with knowledge, experience, and output — full project semantics, so learning accumulates across runs.
17
+ - Sites auto-register on first visit; later runs reference them by bare host.
18
+ - All boats (prima, api-tester, doc-collector) inherit the mechanism with no boat changes.
19
+ - Cross-platform through `os.homedir()` alone — no XDG/Library/AppData branching.
20
+
21
+ ## Non-Goals
22
+
23
+ - No per-setting merging between config sources. A config file wins wholesale, as documented today.
24
+ - No site aliases, environments (staging/prod), or a central `sites.json`.
25
+ - No changes to the env-var config-free mode; it remains the last resort with its current stateless behavior.
26
+
27
+ ## Directory Layout
28
+
29
+ ```
30
+ ~/.explorbot/
31
+ ├── config.js # global AI config (models, keys, agent settings)
32
+ ├── .env # API keys and EXPLORBOT_* vars
33
+ └── sites/
34
+ ├── app.example.com/
35
+ │ ├── site.json # { url, createdAt, lastRunAt }
36
+ │ ├── knowledge/
37
+ │ ├── experience/
38
+ │ └── output/ # states, plans, reports, tests
39
+ └── localhost_3000/
40
+ └── ...
41
+ ```
42
+
43
+ Folder names derive from the target URL's host and port, lowercased, with characters invalid in directory names replaced by `_` (so `localhost:3000` → `localhost_3000`).
44
+
45
+ ## Config Resolution Ladder
46
+
47
+ All changes live in core `ConfigParser` (`src/config.ts`); boats inherit them because they obtain AI config and dirs through it.
48
+
49
+ **Env loading.** `loadConfig()` loads `~/.explorbot/.env` first, then cwd `.env`. Nearest wins on duplicate keys.
50
+
51
+ **Config lookup.** `findConfigFile()` gains one rung after the existing project paths: `~/.explorbot/config.js|mjs|ts`. First hit wins. The full order per invocation:
52
+
53
+ 1. Project config in cwd (existing paths, including `config/` and `src/config/`).
54
+ 2. Global config `~/.explorbot/config.*` → **global mode**.
55
+ 3. `EXPLORBOT_*` env-built config (existing behavior, unchanged: temp output, experience off, Historian off).
56
+ 4. Nothing → error, now also suggesting `explorbot init --global`.
57
+
58
+ Precedence is wholesale, never per setting. A project config wins over everything; the `EXPLORBOT_*` variables win over the global config, so a machine-wide installation never silently overrides what a command asked for. `EXPLORBOT_URL` and command-line URLs still apply in global mode because the URL is per-invocation there. The prima spec's "first hit wins per setting" line is amended to this wholesale rule.
59
+
60
+ **Global mode.** Active when the loaded config path is the global one:
61
+
62
+ - `dirs` resolve to `~/.explorbot/sites/<host>/{knowledge,experience,output}`; `getProjectRoot()` returns the site dir. States, plans, reports, and generated tests land there.
63
+ - Full project semantics: experience read and write enabled, Historian on, reporter as configured.
64
+ - A `dirs` section in the global config is ignored; the site layout is fixed.
65
+ - A `web.url` in the global config is a load-time error — the global config is site-agnostic; the URL comes per command or from a registered site.
66
+
67
+ ## Site Resolution & Auto-Registration
68
+
69
+ In global mode the target site comes from the command's URL argument, else `EXPLORBOT_URL`. One argument carries both site and path:
70
+
71
+ - **Absolute URL** (`https://app.example.com/login`) — host+port become the site folder. First visit auto-registers: creates `sites/<host>/` with `site.json` and the three subdirs. Every run updates `lastRunAt`.
72
+ - **Bare reference** (`app.example.com/login`, `localhost_3000`) — the token before the first `/` is matched against registered sites by folder name or by the host of their `site.json` URL; the rest is the path. Unknown reference → error listing registered sites and suggesting an absolute URL to register a new one.
73
+ - **Leading-slash path** (`/login`) — needs a base URL from `EXPLORBOT_URL`; otherwise error listing registered sites.
74
+
75
+ `explorbot sites` lists registered sites — folder name, base URL, last run — via a `SitesCommand` class in `src/commands/`.
76
+
77
+ ## `explorbot init` — Local or Global
78
+
79
+ Plain `explorbot init` in an interactive terminal first asks which installation to set up:
80
+
81
+ ```
82
+ ? Where should explorbot be initialized?
83
+ ❯ Local — creates the config file in the current directory
84
+ Global — initializes explorbot to run from anywhere on this machine
85
+ ```
86
+
87
+ - **Local** runs the existing project flow, unchanged.
88
+ - **Global** runs the global wizard below.
89
+ - When a global config already exists, the Global option is disabled and labeled `(already installed)`; reinstalling requires `explorbot init --global --force`.
90
+ - Outside a TTY (agents, CI), plain `init` skips the chooser and runs the local flow exactly as today. `--global` skips the chooser and goes straight to the global wizard; any other init flag (`--config-path`, `--path`) implies local.
91
+
92
+ ### The global wizard
93
+
94
+ An interactive React Ink wizard (same interaction pattern as `explorbot learn`):
95
+
96
+ 1. Pick a provider from the supported list (`PROVIDERS` in `src/config.ts`).
97
+ 2. Enter the API key (stored in `~/.explorbot/.env` under the provider's conventional variable).
98
+ 3. Optionally validate the key with a single test AI call.
99
+ 4. Writes `~/.explorbot/config.js` with provider code and the recommended model IDs from `models.json` snapshotted in — no `web.url`, no `dirs` — plus a comment pointing at the providers doc for later edits.
100
+
101
+ Prints next steps: `explorbot explore https://your-app.example.com` from anywhere.
102
+
103
+ Non-interactive path for agents: `explorbot init --global --provider <name> [--api-key <key>]` skips the wizard; the key may also come from the environment. `--force` overwrites an existing global config, mirroring project `init`. Logic lives in the init command class in `src/commands/`; the CLI handler stays thin.
104
+
105
+ The local flow itself is unchanged.
106
+
107
+ ## Boats
108
+
109
+ No boat changes. AI config, dirs, and project root flow through core `ConfigParser`:
110
+
111
+ - **prima** — its spec's `state/<host>` layout is renamed to `sites/<host>`; its Config-Free Operation section now defers to this spec.
112
+ - **api-tester** — the site folder derives from the endpoint host (`EXPLORBOT_URL` / absolute endpoint).
113
+ - **doc-collector** — from the absolute URL argument of `docs collect`.
114
+
115
+ Boat-specific config files (`docbot.config.js`, apibot) stay project-local; their options all have defaults, so global-mode runs use those.
116
+
117
+ ## Testing
118
+
119
+ Unit tests only — nothing here prompts a model except the wizard's optional key validation:
120
+
121
+ - Ladder order: project config beats global; global beats env-built; env-built error message names `init --global`.
122
+ - Env file order: global `.env` loaded, cwd `.env` overrides.
123
+ - Global mode dir resolution: site dirs, project root, `dirs`-ignored and `web.url`-error rules.
124
+ - Host sanitization: ports, case, invalid characters.
125
+ - Auto-registration: folder + `site.json` created once, `lastRunAt` updated.
126
+ - Bare-reference resolution: folder name, host match, unknown-reference error listing sites.
127
+ - Non-interactive `init --global --provider` writes both files; `--force` semantics.
128
+ - Init chooser: Global option disabled when the global config exists; non-TTY plain `init` falls back to the local flow.
129
+
130
+ ## Decisions Log
131
+
132
+ - Global config is a rung in core `ConfigParser`'s lookup, not a flag and not env-only — boats inherit for free.
133
+ - Site folders live under `~/.explorbot/sites/<host>/`, each with `site.json` meta enabling bare-host references and `explorbot sites`.
134
+ - Global mode runs with full project semantics (experience on, Historian on) — the point is memory across runs.
135
+ - Config file beats env vars wholesale, consistent with existing docs; prima spec's per-setting wording amended.
136
+ - `init --global` is an interactive wizard with a `--provider` non-interactive escape for agents.
137
+ - Plain `init` opens a Local/Global chooser in interactive terminals; Global shows `(already installed)` and is disabled once configured.
138
+ - `web.url` in global config errors; `dirs` in global config is ignored.