explorbot 0.2.2 → 0.2.4

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 (214) hide show
  1. package/README.md +1 -1
  2. package/bin/explorbot-cli.ts +59 -38
  3. package/boat/api-tester/src/apibot.ts +4 -2
  4. package/boat/api-tester/src/cli.ts +2 -2
  5. package/boat/api-tester/src/config.ts +43 -10
  6. package/boat/doc-collector/bin/doc-collector-cli.ts +2 -0
  7. package/boat/doc-collector/src/ai/documentarian.ts +61 -31
  8. package/boat/doc-collector/src/cli.ts +1 -0
  9. package/boat/doc-collector/src/config.ts +4 -2
  10. package/boat/doc-collector/src/docs-renderer.ts +18 -4
  11. package/boat/doc-collector/src/state-diagram.ts +61 -14
  12. package/boat/prima/bin/prima-cli.ts +5 -0
  13. package/boat/prima/package.json +16 -0
  14. package/boat/prima/src/activity-line.ts +33 -0
  15. package/boat/prima/src/cli.ts +251 -0
  16. package/boat/prima/src/envelope.ts +169 -0
  17. package/boat/prima/src/prima.ts +1124 -0
  18. package/boat/prima/src/pw-parser.ts +27 -0
  19. package/boat/prima/src/pw-registry.ts +74 -0
  20. package/boat/prima/src/session-log.ts +126 -0
  21. package/dist/bin/explorbot-cli.js +51 -32
  22. package/dist/boat/api-tester/bin/apibot-cli.js +2 -0
  23. package/dist/boat/api-tester/src/apibot.js +3 -2
  24. package/dist/boat/api-tester/src/cli.js +2 -2
  25. package/dist/boat/api-tester/src/config.js +40 -10
  26. package/dist/boat/doc-collector/bin/doc-collector-cli.js +2 -0
  27. package/dist/boat/doc-collector/src/ai/documentarian.js +44 -19
  28. package/dist/boat/doc-collector/src/cli.js +1 -0
  29. package/dist/boat/doc-collector/src/config.js +4 -2
  30. package/dist/boat/doc-collector/src/docs-renderer.js +17 -3
  31. package/dist/boat/doc-collector/src/state-diagram.js +57 -13
  32. package/dist/boat/prima/bin/prima-cli.js +4 -0
  33. package/dist/boat/prima/src/activity-line.js +30 -0
  34. package/dist/boat/prima/src/cli.js +220 -0
  35. package/dist/boat/prima/src/envelope.js +142 -0
  36. package/dist/boat/prima/src/prima.js +1031 -0
  37. package/dist/boat/prima/src/pw-parser.js +30 -0
  38. package/dist/boat/prima/src/pw-registry.js +65 -0
  39. package/dist/boat/prima/src/session-log.js +108 -0
  40. package/dist/models.json +3 -0
  41. package/dist/package.json +8 -3
  42. package/dist/rules/navigator/verification-actions.md +20 -0
  43. package/dist/src/action-result.d.ts +7 -0
  44. package/dist/src/action-result.js +4 -0
  45. package/dist/src/action.d.ts +7 -2
  46. package/dist/src/action.js +41 -6
  47. package/dist/src/ai/captain/mixin.js +3 -4
  48. package/dist/src/ai/captain/web-mode.js +7 -4
  49. package/dist/src/ai/captain.js +2 -0
  50. package/dist/src/ai/navigator.d.ts +11 -0
  51. package/dist/src/ai/navigator.js +21 -12
  52. package/dist/src/ai/pilot.d.ts +4 -0
  53. package/dist/src/ai/pilot.js +48 -2
  54. package/dist/src/ai/planner.d.ts +1 -0
  55. package/dist/src/ai/planner.js +6 -0
  56. package/dist/src/ai/provider.js +2 -2
  57. package/dist/src/ai/rerunner.js +2 -1
  58. package/dist/src/ai/researcher.js +2 -2
  59. package/dist/src/ai/rules.js +17 -10
  60. package/dist/src/ai/task-agent.js +5 -2
  61. package/dist/src/ai/tester.d.ts +1 -0
  62. package/dist/src/ai/tester.js +33 -20
  63. package/dist/src/ai/tools.d.ts +14 -0
  64. package/dist/src/ai/tools.js +113 -36
  65. package/dist/src/application-spec-contract.d.ts +8 -0
  66. package/dist/src/application-spec-contract.js +8 -0
  67. package/dist/src/application-spec.d.ts +15 -0
  68. package/dist/src/application-spec.js +71 -0
  69. package/dist/src/browser-server.d.ts +12 -6
  70. package/dist/src/browser-server.js +74 -19
  71. package/dist/src/commands/clean-command.js +2 -7
  72. package/dist/src/commands/init-command.d.ts +5 -0
  73. package/dist/src/commands/init-command.js +119 -1
  74. package/dist/src/commands/navigate-command.js +1 -1
  75. package/dist/src/commands/research-command.js +1 -1
  76. package/dist/src/commands/sites-command.d.ts +6 -0
  77. package/dist/src/commands/sites-command.js +23 -0
  78. package/dist/src/components/InitWizard.d.ts +10 -0
  79. package/dist/src/components/InitWizard.js +133 -0
  80. package/dist/src/components/InputReadline.d.ts +1 -0
  81. package/dist/src/components/InputReadline.js +7 -4
  82. package/dist/src/config.d.ts +25 -5
  83. package/dist/src/config.js +158 -40
  84. package/dist/src/execution-controller.d.ts +2 -0
  85. package/dist/src/execution-controller.js +6 -0
  86. package/dist/src/explorbot.d.ts +11 -1
  87. package/dist/src/explorbot.js +27 -6
  88. package/dist/src/explorer.d.ts +4 -1
  89. package/dist/src/explorer.js +42 -9
  90. package/dist/src/global-config.d.ts +22 -0
  91. package/dist/src/global-config.js +117 -0
  92. package/dist/src/knowledge-tracker.d.ts +5 -1
  93. package/dist/src/knowledge-tracker.js +14 -1
  94. package/dist/src/playwright-recorder.js +30 -0
  95. package/dist/src/remote.d.ts +54 -0
  96. package/dist/src/remote.js +229 -0
  97. package/dist/src/reporter.d.ts +1 -0
  98. package/dist/src/reporter.js +7 -1
  99. package/dist/src/state-manager.d.ts +2 -1
  100. package/dist/src/stats.d.ts +1 -0
  101. package/dist/src/stats.js +1 -0
  102. package/dist/src/test-plan.d.ts +2 -0
  103. package/dist/src/test-plan.js +7 -0
  104. package/dist/src/utils/aria.d.ts +2 -8
  105. package/dist/src/utils/aria.js +69 -40
  106. package/dist/src/utils/cli-name.js +6 -2
  107. package/dist/src/utils/html.js +1 -0
  108. package/dist/src/utils/logger.d.ts +6 -0
  109. package/dist/src/utils/logger.js +24 -0
  110. package/dist/src/utils/page-readiness.js +18 -1
  111. package/dist/src/utils/test-files.js +1 -2
  112. package/dist/src/utils/url-matcher.d.ts +1 -0
  113. package/dist/src/utils/url-matcher.js +12 -0
  114. package/dist/src/utils/web-element.d.ts +2 -0
  115. package/dist/src/utils/web-element.js +8 -0
  116. package/dist/src/utils/web-sandbox.d.ts +1 -1
  117. package/dist/src/utils/web-sandbox.js +2 -3
  118. package/docs/api-testing/basics.md +90 -0
  119. package/docs/api-testing/planning.md +57 -0
  120. package/docs/api-testing/running-tests.md +55 -0
  121. package/docs/assets/cloud-report.png +0 -0
  122. package/docs/assets/html-report.png +0 -0
  123. package/docs/assets/langfuse-trace.png +0 -0
  124. package/docs/assets/successful-explore-run.png +0 -0
  125. package/docs/basics/getting-started.md +140 -0
  126. package/docs/basics/prerequisites.md +63 -0
  127. package/docs/basics/providers.md +362 -0
  128. package/docs/basics/running.md +78 -0
  129. package/docs/contributing/ai-integration-tests.md +57 -0
  130. package/docs/contributing/contributing.md +90 -0
  131. package/docs/contributing/demo-videos.md +36 -0
  132. package/docs/contributing/npm-package.md +138 -0
  133. package/docs/contributing/observability.md +227 -0
  134. package/docs/contributing/regression-tests.md +103 -0
  135. package/docs/contributing/testing.md +95 -0
  136. package/docs/doc-collection/basics.md +128 -0
  137. package/docs/doc-collection/crawling.md +67 -0
  138. package/docs/doc-collection/interactive-mode.md +99 -0
  139. package/docs/index.json +86 -0
  140. package/docs/reference/commands.md +994 -0
  141. package/docs/reference/configuration.md +569 -0
  142. package/docs/reference/scripting.md +303 -0
  143. package/docs/superpowers/plans/2026-08-01-actor-boat.md +925 -0
  144. package/docs/superpowers/plans/2026-08-01-prima-boat.md +1120 -0
  145. package/docs/superpowers/reviews/2026-08-06-prima-vs-playwright-cli.md +268 -0
  146. package/docs/superpowers/specs/2026-08-01-actor-boat-design.md +204 -0
  147. package/docs/superpowers/specs/2026-08-01-prima-boat-design.md +242 -0
  148. package/docs/superpowers/specs/2026-08-03-global-config-design.md +138 -0
  149. package/docs/superpowers/specs/2026-08-07-prima-fixes-design.md +394 -0
  150. package/docs/web-testing/agents.md +158 -0
  151. package/docs/web-testing/automated-tests.md +134 -0
  152. package/docs/web-testing/basics.md +91 -0
  153. package/docs/web-testing/customization.md +131 -0
  154. package/docs/web-testing/hooks.md +238 -0
  155. package/docs/web-testing/page-interaction.md +84 -0
  156. package/docs/web-testing/planner.md +122 -0
  157. package/docs/web-testing/rerun.md +164 -0
  158. package/docs/web-testing/researcher.md +380 -0
  159. package/docs/workflow/agentic-usage.md +233 -0
  160. package/docs/workflow/application-spec.md +73 -0
  161. package/docs/workflow/ci.md +202 -0
  162. package/docs/workflow/knowledge.md +310 -0
  163. package/docs/workflow/planning-styles.md +67 -0
  164. package/docs/workflow/reporting.md +133 -0
  165. package/docs/workflow/test-plans.md +90 -0
  166. package/models.json +3 -0
  167. package/package.json +8 -3
  168. package/rules/navigator/verification-actions.md +20 -0
  169. package/src/action-result.ts +11 -0
  170. package/src/action.ts +47 -7
  171. package/src/ai/captain/mixin.ts +3 -3
  172. package/src/ai/captain/web-mode.ts +7 -4
  173. package/src/ai/captain.ts +3 -0
  174. package/src/ai/navigator.ts +26 -15
  175. package/src/ai/pilot.ts +53 -2
  176. package/src/ai/planner.ts +7 -0
  177. package/src/ai/provider.ts +2 -4
  178. package/src/ai/rerunner.ts +2 -1
  179. package/src/ai/researcher.ts +2 -2
  180. package/src/ai/rules.ts +17 -10
  181. package/src/ai/task-agent.ts +4 -2
  182. package/src/ai/tester.ts +32 -18
  183. package/src/ai/tools.ts +132 -36
  184. package/src/application-spec-contract.ts +10 -0
  185. package/src/application-spec.ts +87 -0
  186. package/src/browser-server.ts +74 -19
  187. package/src/commands/clean-command.ts +1 -6
  188. package/src/commands/init-command.ts +146 -1
  189. package/src/commands/navigate-command.ts +1 -1
  190. package/src/commands/research-command.ts +1 -1
  191. package/src/commands/sites-command.ts +27 -0
  192. package/src/components/InitWizard.tsx +166 -0
  193. package/src/components/InputReadline.tsx +8 -4
  194. package/src/config.ts +177 -43
  195. package/src/execution-controller.ts +8 -0
  196. package/src/explorbot.ts +34 -7
  197. package/src/explorer.ts +47 -9
  198. package/src/global-config.ts +148 -0
  199. package/src/knowledge-tracker.ts +17 -1
  200. package/src/playwright-recorder.ts +23 -0
  201. package/src/remote.ts +238 -0
  202. package/src/reporter.ts +7 -1
  203. package/src/state-manager.ts +2 -1
  204. package/src/stats.ts +1 -0
  205. package/src/test-plan.ts +9 -0
  206. package/src/utils/aria.ts +65 -45
  207. package/src/utils/cli-name.ts +5 -2
  208. package/src/utils/html.ts +1 -0
  209. package/src/utils/logger.ts +24 -1
  210. package/src/utils/page-readiness.ts +24 -1
  211. package/src/utils/test-files.ts +1 -2
  212. package/src/utils/url-matcher.ts +13 -0
  213. package/src/utils/web-element.ts +9 -0
  214. package/src/utils/web-sandbox.ts +3 -4
@@ -0,0 +1,134 @@
1
+ # Automated Tests
2
+
3
+ When Explorbot runs a plan, it saves the executed scenarios to a runnable test file under `output/tests/`. Commit it, run it from CI, or edit it by hand.
4
+
5
+ Pick the framework you use:
6
+
7
+ - **Playwright** — set `ai.agents.historian.framework: 'playwright'` in your config. Output is a `.spec.ts` file.
8
+ - **CodeceptJS** — the default. Output is a `.js` file.
9
+
10
+ If you use neither, start with Playwright.
11
+
12
+ ## Playwright
13
+
14
+ A file Explorbot produced from a plan called *Creating a plan*, trimmed for readability. See `example/output/tests/` for full examples.
15
+
16
+ ```ts
17
+ import { test, expect } from '@playwright/test';
18
+
19
+ test.describe('Creating a plan', () => {
20
+ test.beforeEach(async ({ page }) => {
21
+ await page.goto('/projects/zyntra/plans/');
22
+ await page.waitForTimeout(1000);
23
+ });
24
+
25
+ test('Create a new manual plan and verify it appears in the list', async ({ page }) => {
26
+ await test.step("Click the 'New plan' button in toolbar", async () => {
27
+ await page.getByRole('button', { name: 'New plan' }).first().click();
28
+ });
29
+
30
+ await test.step('Select Manual plan type in modal', async () => {
31
+ await page.locator('#portal-container').getByRole('button', { name: 'Manual' }).click();
32
+ });
33
+
34
+ await test.step('Click Save', async () => {
35
+ await page.getByRole('button', { name: 'Save' }).click();
36
+ });
37
+
38
+ await test.step('Verification', async () => {
39
+ await expect(page).toContainText('Test Plan UI Creation 001');
40
+ });
41
+ });
42
+
43
+ // FAILED: Create a new automated plan and verify it appears under automated tab
44
+ test.skip('Create a new automated plan and verify it appears under automated tab', async ({ page }) => {
45
+ // ...
46
+ });
47
+
48
+ test.fixme('Delete a plan from the list', async ({ page }) => {
49
+ // open the action menu
50
+ // click Delete
51
+ // confirm in dialog
52
+ });
53
+ });
54
+ ```
55
+
56
+ Three things to notice:
57
+
58
+ 1. Every action is its own `test.step`. The label is the AI's description of that action, so the Playwright report tree reads like the plan it came from. Failures land on a single step.
59
+ 2. The locators are real. `page.getByRole('button', { name: 'New plan' })` is what Playwright ran during the session, not a translation. If it worked then, it works now.
60
+ 3. `test.beforeEach` reaches the starting state. It navigates to the plan's start URL and replays the `wait` / `waitForElement` knowledge you declared for that page. The closing `test.step('Verification', ...)` block holds whatever the Pilot verified.
61
+
62
+ Run it the normal way:
63
+
64
+ ```bash
65
+ npx playwright test output/tests/runs_archive_feature_testing.spec.ts
66
+ ```
67
+
68
+ `npx explorbot rerun` does not run Playwright specs. It points you at `npx playwright test` instead.
69
+
70
+ ### Scenarios that didn't pass
71
+
72
+ The file always runs, even when some scenarios failed:
73
+
74
+ - Passed scenarios become plain `test(...)`.
75
+ - Failed scenarios become `test.skip(...)` with a `// FAILED: <scenario>` comment above them, so you can see what broke and decide whether to fix or drop it.
76
+ - Scenarios Explorbot didn't reach become `test.fixme(...)`, with the planned steps preserved as comments.
77
+
78
+ Commit the file as-is. Passing scenarios run, broken ones are skipped and visible, planned ones wait for you.
79
+
80
+ ## CodeceptJS
81
+
82
+ The default output is a `Feature` with one `Scenario` per plan entry, plus a `Before` block for setup:
83
+
84
+ ```js
85
+ import step, { Section } from 'codeceptjs/steps';
86
+
87
+ Feature('Runs Archive Feature Testing')
88
+
89
+ Before(({ I }) => {
90
+ I.amOnPage('/projects/zyntra/runs/archive');
91
+ I.wait(1);
92
+ });
93
+
94
+ Scenario('Apply filters specific to archived runs and verify results', ({ I }) => {
95
+ Section('Open the filter panel');
96
+ I.click({ css: 'button.btn-only-icon.btn-lg:has(svg.md-icon-filter)' });
97
+
98
+ Section('Pick the Passed status');
99
+ I.click('Select status');
100
+ I.click('Passed');
101
+ I.click('Apply');
102
+
103
+ I.see('1 run found');
104
+ });
105
+ ```
106
+
107
+ Two things to notice:
108
+
109
+ 1. `Before` reaches the starting state. It calls `I.amOnPage` for the plan's start URL and replays the `wait` / `waitForElement` knowledge you declared for that page.
110
+ 2. Steps are grouped by `Section('...')`. Each label is the AI's description of that group, so the test reads top to bottom like the plan it came from.
111
+
112
+ Run it with:
113
+
114
+ ```bash
115
+ npx explorbot rerun output/tests/runs_archive_feature_testing.js
116
+ ```
117
+
118
+ `npx explorbot rerun` heals broken steps automatically. See [Rerun](./rerun.md).
119
+
120
+ ### Scenarios that didn't pass
121
+
122
+ The file always runs, even when some scenarios failed:
123
+
124
+ - Passed scenarios become plain `Scenario(...)`.
125
+ - Failed scenarios become `Scenario.skip(...)` with a `// FAILED: <scenario>` comment above them.
126
+ - Scenarios Explorbot didn't reach become `Scenario.todo(...)`, with the planned steps preserved as comments.
127
+
128
+ Commit the file as-is. Passing scenarios run, broken ones are skipped and visible, planned ones wait for you.
129
+
130
+ ## See also
131
+
132
+ - [Test Plans](../workflow/test-plans.md) — the markdown plans that drive these test files
133
+ - [Rerun](./rerun.md) — re-run CodeceptJS tests with auto-healing
134
+ - [Configuration → Historian Agent Options](../reference/configuration.md#historian-agent-options) — the `framework` option
@@ -0,0 +1,91 @@
1
+ # Web Testing Basics
2
+
3
+ Explorbot tests a web app the way a curious QA engineer would: open a page, figure out what it does, invent test scenarios, run them, and remember what happened. You write no test scripts up front — the tests come from the app itself.
4
+
5
+ This page explains the concepts behind that loop and the minimum configuration to start. If you haven't installed Explorbot yet, do [Getting Started](../basics/getting-started.md) first.
6
+
7
+ ## What it does
8
+
9
+ One exploration cycle has four parts:
10
+
11
+ 1. **Research.** The Researcher agent reads the current page — HTML, ARIA snapshot, and optionally a screenshot — and builds a map of what's on it: forms, buttons, tables, navigation.
12
+ 2. **Plan.** The Planner turns that map into test scenarios with priorities and expected outcomes, cycling through planning styles to broaden coverage.
13
+ 3. **Test.** The Tester runs each scenario step by step in a real browser, adapting when a click misses or a modal appears. The Pilot supervises from above and steps in when the test gets stuck.
14
+ 4. **Learn.** Outcomes are recorded — what worked, what failed, how failures were resolved — so the next run starts smarter.
15
+
16
+ When you run `/explore`, this cycle repeats. After the start page is covered, Explorbot picks promising sub-pages linked from it and continues there, until it runs out of pages or hits your test limit.
17
+
18
+ Two ideas hold this loop together, and you will meet them everywhere in these docs: states and learning.
19
+
20
+ ### States
21
+
22
+ A page state is the URL plus the page's main headings (`h1` and `h2`). That's how Explorbot knows where it is. A URL alone isn't enough — a single-page app can show a list, an edit form, and a confirmation dialog all on one URL — so headings are part of the identity.
23
+
24
+ States are the anchor points for everything else. Navigation history is a chain of state transitions, knowledge and experience are matched to the current state, and loop detection compares recent state hashes: if the bot keeps cycling through the same one or two states, it knows it's stuck and changes strategy instead of burning iterations.
25
+
26
+ ### Learning
27
+
28
+ Explorbot keeps two directories of markdown files next to your config:
29
+
30
+ - `knowledge/` — facts **you** teach it: credentials, quirks, hints, small automations. Each file targets pages by URL pattern, so knowledge for `/login` loads only on the login page and knowledge for `*` loads everywhere.
31
+ - `experience/` — what it **learned by doing**: failed attempts, working resolutions, session notes. Files are named after state hashes, so lessons from a page are re-read the next time that page appears.
32
+
33
+ Knowledge is the input you control; experience accumulates on its own. Both are plain markdown you can read and edit. See [Knowledge](../workflow/knowledge.md).
34
+
35
+ ## Configure
36
+
37
+ Web testing needs one thing beyond the AI setup from Getting Started — the base URL of your app:
38
+
39
+ ```javascript
40
+ export default {
41
+ web: {
42
+ url: 'http://localhost:3000',
43
+ },
44
+ ai: {
45
+ model: openrouter('openai/gpt-oss-20b:nitro'),
46
+ visionModel: openrouter('google/gemma-4-31b-it'),
47
+ agenticModel: openrouter('minimax/minimax-m2.5:nitro'),
48
+ },
49
+ };
50
+ ```
51
+
52
+ The three models split the work by cost: `model` does the heavy page reading on every step, `visionModel` analyzes screenshots, and `agenticModel` makes the high-level decisions on short inputs, so it can be smarter without costing much. The full breakdown is in [Getting Started](../basics/getting-started.md); provider setup is in [Providers](../basics/providers.md). Every other option — browser settings, directories, per-agent tuning — lives in the [Configuration reference](../reference/configuration.md).
53
+
54
+ ## First run
55
+
56
+ One tip from Getting Started is worth repeating: don't start on your homepage. Point Explorbot at one focused page with a clear CRUD interface — a list-and-edit screen, a settings page. It gives the bot an obvious job and you an obvious way to judge the result.
57
+
58
+ The interactive route opens the TUI, where you watch the run and can step in:
59
+
60
+ ```bash
61
+ npx explorbot start /admin/projects
62
+ ```
63
+
64
+ Then type `/explore` to run the full loop, or go one step at a time with `/research` (analyze the page), `/plan` (propose scenarios), and `/test` (run the next one).
65
+
66
+ The headless route runs the same loop without the TUI and exits when done — good for CI or overnight runs:
67
+
68
+ ```bash
69
+ npx explorbot explore /admin/projects --max-tests 10 --focus "project management"
70
+ ```
71
+
72
+ `--max-tests` caps how many tests run; `--focus` narrows planning to one feature. Both are optional.
73
+
74
+ ## Output files
75
+
76
+ Every run leaves artifacts behind:
77
+
78
+ - **Test plans** in `output/plans/` — the scenarios as markdown, with priorities and results. You can re-run, edit, or extend them. See [Test Plans](../workflow/test-plans.md).
79
+ - **Runnable tests** in `output/tests/` — CodeceptJS/Playwright code generated from successful runs, ready to commit and run in CI. See [Automated Tests](./automated-tests.md).
80
+ - **A session report** in `output/reports/` — a human-readable summary that clusters defects, UX issues, and execution problems by root cause. See [Reporting](../workflow/reporting.md).
81
+ - **Experience files** in `experience/` — the lessons that make the next run faster and less error-prone.
82
+
83
+ ## Where to go next
84
+
85
+ - [Customization](./customization.md) — make it work on *your* app: login, cookie banners, modals, test data.
86
+ - [Planner](./planner.md) — tune what gets tested: styles, priorities, custom rules.
87
+ - [Researcher](./researcher.md) — how pages are analyzed and what the UI map contains.
88
+ - [Page Interaction](./page-interaction.md) — how Explorbot reads pages and picks locators.
89
+ - [Automated Tests](./automated-tests.md) and [Rerun](./rerun.md) — the tests you keep, and re-running them with AI healing.
90
+ - [Agents](./agents.md) — the agents behind the loop, and per-agent model configuration.
91
+ - [Hooks](./hooks.md) — run your own code before and after agents.
@@ -0,0 +1,131 @@
1
+ # Customization
2
+
3
+ Most real apps need a little setup before Explorbot can test them: a login, a cookie banner to dismiss, a slow page to wait for. This page shows the shortest recipe for each common case.
4
+
5
+ You have two tools:
6
+
7
+ - **Knowledge files** — markdown hints and small automations that run per URL. Start here.
8
+ - **Hooks** — code that runs for one agent only. Use these when knowledge isn't enough.
9
+
10
+ Each recipe below links to the full reference.
11
+
12
+ ## Log in
13
+
14
+ Add a knowledge file for your login page and give Explorbot the credentials. Keep secrets in environment variables and reference them with `${env.NAME}`.
15
+
16
+ `knowledge/login.md`:
17
+
18
+ ```markdown
19
+ ---
20
+ url: /login
21
+ ---
22
+
23
+ Log in with these credentials:
24
+ - email: ${env.APP_EMAIL}
25
+ - password: ${env.APP_PASSWORD}
26
+ ```
27
+
28
+ Explorbot reads this when it opens the login page and signs in on its own. See [Knowledge](../workflow/knowledge.md).
29
+
30
+ ## Stay logged in between runs
31
+
32
+ Logging in on every run is slow. Use `--session` to save cookies and local storage, then restore them next time:
33
+
34
+ ```bash
35
+ npx explorbot start /login --session # logs in, saves the session
36
+ npx explorbot start /dashboard --session # restores it, skips login
37
+ ```
38
+
39
+ Pass a filename to keep more than one session: `--session auth.json`.
40
+
41
+ ## Dismiss a cookie banner
42
+
43
+ A cookie bar blocks the page until you accept it. Dismiss one on every page with a knowledge file on `*`. Wrap the click in `tryTo` so it does nothing when the bar is absent:
44
+
45
+ `knowledge/cookies.md`:
46
+
47
+ ```markdown
48
+ ---
49
+ url: *
50
+ code: |
51
+ await tryTo(() => I.click('Accept all'));
52
+ ---
53
+
54
+ A cookie banner appears on first load. Accept it before interacting.
55
+ ```
56
+
57
+ ## Close modals and popups
58
+
59
+ A modal can cover the page right after it loads. Close it with a `code` block that runs only if the modal is there:
60
+
61
+ ```markdown
62
+ ---
63
+ url: /checkout
64
+ code: |
65
+ await tryTo(() => I.click('[aria-label="Close"]'));
66
+ ---
67
+ ```
68
+
69
+ To close a popup for one agent only — say, before research but not during a test — use a [hook](./hooks.md) instead.
70
+
71
+ ## Wait for slow or single-page apps
72
+
73
+ Some pages show a spinner before the real content loads. Tell Explorbot to wait:
74
+
75
+ ```markdown
76
+ ---
77
+ url: /dashboard
78
+ wait: 2
79
+ waitForElement: '.dashboard-ready'
80
+ ---
81
+ ```
82
+
83
+ `wait` pauses for the given seconds. `waitForElement` waits for a selector to appear. For single-page apps where a full reload breaks state, add `statePush: true` so Explorbot navigates without reloading.
84
+
85
+ ## Set up and restore test data
86
+
87
+ To seed data before tests and clean it up after, use agent hooks. `tester.beforeHook` runs before the test loop; `afterHook` runs after it:
88
+
89
+ ```javascript
90
+ ai: {
91
+ agents: {
92
+ tester: {
93
+ beforeHook: {
94
+ type: 'codeceptjs',
95
+ hook: async ({ I }) => {
96
+ await I.executeScript(() => localStorage.setItem('cart', '[]'));
97
+ },
98
+ },
99
+ afterHook: {
100
+ type: 'playwright',
101
+ hook: async ({ page }) => {
102
+ await page.evaluate(() => localStorage.clear());
103
+ },
104
+ },
105
+ },
106
+ },
107
+ }
108
+ ```
109
+
110
+ See [Hooks](./hooks.md) for every agent and hook type.
111
+
112
+ ## Avoid fragile locators
113
+
114
+ Some frameworks generate random IDs that change on every load — for example Ember's `#ember123`. Tell Explorbot to ignore them, and it will prefer stable locators like ARIA labels and visible text:
115
+
116
+ ```markdown
117
+ ---
118
+ url: /projects/*
119
+ ---
120
+
121
+ ## Framework
122
+
123
+ This app is built with Ember. Do not use auto-generated IDs like #ember123 in locators.
124
+ Prefer ARIA labels and visible text.
125
+ ```
126
+
127
+ ## Knowledge or hooks?
128
+
129
+ Reach for a knowledge file first. It is markdown, lives beside your other knowledge, and applies to every agent on matching pages. Use a hook when you need code to run for one agent only, or different behavior for navigation versus testing. For a case-by-case comparison, see the decision table in [Hooks](./hooks.md#when-to-use-hooks-vs-knowledge).
130
+
131
+ Learn more in [Knowledge](../workflow/knowledge.md) and [Hooks](./hooks.md).
@@ -0,0 +1,238 @@
1
+ # Agent Hooks
2
+
3
+ Hooks run custom code before or after a specific agent. Use them to prepare and clean up the page per agent.
4
+
5
+ > [!NOTE]
6
+ > For simple page automation such as waiting or clicking cookie banners, use [Knowledge Files](../workflow/knowledge.md) with the `wait`, `waitForElement`, or `code` fields. Reach for hooks when you need different behavior for different agents.
7
+
8
+ ## When to Use Hooks vs Knowledge
9
+
10
+ | Use Case | Solution |
11
+ |----------|----------|
12
+ | Wait for element on all page visits | Knowledge: `waitForElement` |
13
+ | Dismiss cookie banner on page load | Knowledge: `code` |
14
+ | Wait for network idle only during research | Hook: `researcher.beforeHook` |
15
+ | Clean up test data after each test | Hook: `tester.afterHook` |
16
+ | Different waits for navigation vs testing | Hooks for each agent |
17
+
18
+ ## Configuration
19
+
20
+ Hooks are configured per-agent in `explorbot.config.js`:
21
+
22
+ ```javascript
23
+ export default {
24
+ ai: {
25
+ model: myProvider('gpt-4o'),
26
+ agents: {
27
+ navigator: {
28
+ beforeHook: {
29
+ type: 'playwright',
30
+ hook: async ({ page, url }) => {
31
+ await page.waitForLoadState('networkidle');
32
+ }
33
+ }
34
+ },
35
+ tester: {
36
+ afterHook: {
37
+ type: 'codeceptjs',
38
+ hook: async ({ I, url }) => {
39
+ await I.executeScript(() => localStorage.clear());
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ ## Hook Types
49
+
50
+ ### Playwright Hooks
51
+
52
+ Get direct access to the Playwright page object:
53
+
54
+ ```javascript
55
+ beforeHook: {
56
+ type: 'playwright',
57
+ hook: async ({ page, url }) => {
58
+ await page.waitForLoadState('networkidle');
59
+ await page.locator('.loading').waitFor({ state: 'hidden' });
60
+ }
61
+ }
62
+ ```
63
+
64
+ ### CodeceptJS Hooks
65
+
66
+ Use the CodeceptJS `I` actor:
67
+
68
+ ```javascript
69
+ beforeHook: {
70
+ type: 'codeceptjs',
71
+ hook: async ({ I, url }) => {
72
+ await I.waitForElement('.page-ready');
73
+ await I.wait(1);
74
+ }
75
+ }
76
+ ```
77
+
78
+ ## URL Pattern Matching
79
+
80
+ Run different hooks for different URL patterns:
81
+
82
+ ```javascript
83
+ researcher: {
84
+ beforeHook: {
85
+ '/login': {
86
+ type: 'codeceptjs',
87
+ hook: async ({ I }) => await I.waitForElement('#login-form')
88
+ },
89
+ '/admin/*': {
90
+ type: 'playwright',
91
+ hook: async ({ page }) => await page.waitForLoadState('networkidle')
92
+ },
93
+ '/api/*': {
94
+ type: 'codeceptjs',
95
+ hook: async ({ I }) => await I.wait(2)
96
+ }
97
+ }
98
+ }
99
+ ```
100
+
101
+ ### Pattern Syntax
102
+
103
+ | Pattern | Matches |
104
+ |---------|---------|
105
+ | `/login` | Exact path `/login` |
106
+ | `/admin/*` | `/admin` and any path starting with `/admin/` |
107
+ | `*` | All URLs (fallback) |
108
+ | `^/users/\d+$` | Regex: `/users/` followed by digits |
109
+ | `**/*.html` | Glob: any `.html` file |
110
+
111
+ ## Supported Agents
112
+
113
+ | Agent | beforeHook | afterHook | Description |
114
+ |-------|------------|-----------|-------------|
115
+ | `navigator` | After navigation | After page capture | Browser navigation |
116
+ | `researcher` | After navigation | After research complete | Page analysis |
117
+ | `tester` | Before test loop | After test loop | Test execution |
118
+ | `driller` | Before drilling starts | After drilling completes | Component drilling |
119
+ | `captain` | Before handling command | After command complete | User commands |
120
+
121
+ > [!WARNING]
122
+ > The `planner` agent does not support hooks as it doesn't interact with the browser.
123
+
124
+ ## Examples
125
+
126
+ ### Wait for SPA to Load
127
+
128
+ ```javascript
129
+ navigator: {
130
+ beforeHook: {
131
+ type: 'playwright',
132
+ hook: async ({ page }) => {
133
+ await page.waitForFunction(() => {
134
+ return window.__APP_READY__ === true;
135
+ });
136
+ }
137
+ }
138
+ }
139
+ ```
140
+
141
+ ### Dismiss Modals Before Research
142
+
143
+ ```javascript
144
+ researcher: {
145
+ beforeHook: {
146
+ type: 'codeceptjs',
147
+ hook: async ({ I }) => {
148
+ const modalVisible = await I.grabNumberOfVisibleElements('.modal-overlay');
149
+ if (modalVisible > 0) {
150
+ await I.click('.modal-close');
151
+ await I.wait(0.5);
152
+ }
153
+ }
154
+ }
155
+ }
156
+ ```
157
+
158
+ ### Clean Up After Tests
159
+
160
+ ```javascript
161
+ tester: {
162
+ afterHook: {
163
+ type: 'playwright',
164
+ hook: async ({ page }) => {
165
+ await page.evaluate(() => {
166
+ localStorage.clear();
167
+ sessionStorage.clear();
168
+ });
169
+ }
170
+ }
171
+ }
172
+ ```
173
+
174
+ ### Different Behavior per URL
175
+
176
+ ```javascript
177
+ tester: {
178
+ beforeHook: {
179
+ '/checkout': {
180
+ type: 'codeceptjs',
181
+ hook: async ({ I }) => {
182
+ // Ensure cart has items before checkout tests
183
+ await I.executeScript(() => {
184
+ if (!localStorage.getItem('cart')) {
185
+ localStorage.setItem('cart', JSON.stringify([{ id: 1, qty: 1 }]));
186
+ }
187
+ });
188
+ }
189
+ },
190
+ '/admin/*': {
191
+ type: 'codeceptjs',
192
+ hook: async ({ I }) => {
193
+ // Ensure admin session
194
+ await I.waitForElement('.admin-header', 5);
195
+ }
196
+ }
197
+ }
198
+ }
199
+ ```
200
+
201
+ ## Error Handling
202
+
203
+ A hook error is logged but does not stop the agent:
204
+
205
+ ```javascript
206
+ beforeHook: {
207
+ type: 'codeceptjs',
208
+ hook: async ({ I }) => {
209
+ try {
210
+ await I.waitForElement('.optional-banner', 2);
211
+ await I.click('.dismiss');
212
+ } catch {
213
+ // Banner not present, continue
214
+ }
215
+ }
216
+ }
217
+ ```
218
+
219
+ ## Execution Flow
220
+
221
+ ```
222
+ ┌─────────────────────────────────────────────────────────┐
223
+ │ Agent Execution │
224
+ ├─────────────────────────────────────────────────────────┤
225
+ │ 1. Agent starts │
226
+ │ 2. Navigate to URL (if applicable) │
227
+ │ 3. ▶ beforeHook executes │
228
+ │ 4. Agent performs main work │
229
+ │ 5. ▶ afterHook executes │
230
+ │ 6. Agent completes │
231
+ └─────────────────────────────────────────────────────────┘
232
+ ```
233
+
234
+ ## See Also
235
+
236
+ - [Knowledge Files](../workflow/knowledge.md) — page-level automation with `wait`, `waitForElement`, `code`
237
+ - [Configuration](../reference/configuration.md) — full configuration reference
238
+ - [Agents](./agents.md) — agent descriptions and workflows
@@ -0,0 +1,84 @@
1
+ # Page Interaction
2
+
3
+ This page explains how Explorbot agents read a web page and act on it — and the two things you can change to help them: filtering noisy HTML and marking custom components.
4
+
5
+ ## How agents see a page
6
+
7
+ Agents read each page three ways at once:
8
+
9
+ | Source | What it gives | Used for |
10
+ |--------|---------------|----------|
11
+ | **ARIA snapshot** | Roles, labels, states, hierarchy | Understanding structure, building locators |
12
+ | **HTML** | Classes, IDs, data attributes, form fields | Precise locators, reading field values |
13
+ | **Screenshot** | Layout, colors, icons, coordinates | Visual checks, click fallbacks |
14
+
15
+ The accessibility tree is the primary source. HTML adds detail. The screenshot is a fallback when the first two aren't enough.
16
+
17
+ ## Filter noisy HTML
18
+
19
+ Agents work from the `combined` HTML snapshot. Cookie banners, chat widgets, ads, and analytics tags add noise and burn tokens. Exclude them in your config:
20
+
21
+ ```javascript
22
+ // explorbot.config.js
23
+ html: {
24
+ combined: {
25
+ include: ['*'],
26
+ exclude: ['script', 'style', 'svg', '.cookie-banner', '.analytics-tracker'],
27
+ },
28
+ }
29
+ ```
30
+
31
+ Three snapshots exist, each configurable:
32
+
33
+ | Snapshot | Purpose | Config key |
34
+ |----------|---------|------------|
35
+ | `combined` | Main HTML for agents | `html.combined` |
36
+ | `minimal` | Interactive elements only | `html.minimal` |
37
+ | `text` | Text content only | `html.text` |
38
+
39
+ ## Mark custom components
40
+
41
+ Some components are interactive but have no ARIA role or semantic HTML, so agents miss them. Mark them with a `data-explorbot-*` attribute:
42
+
43
+ ```html
44
+ <div data-explorbot-role="button" data-explorbot-label="Save Draft">
45
+ <svg>...</svg>
46
+ Save
47
+ </div>
48
+ ```
49
+
50
+ A marked element is always kept in snapshots, treated as interactive, and shown to agents. During processing, `data-explorbot-role="button"` becomes `role="button"`, so you add a hint without changing how your component behaves.
51
+
52
+ Use this when standard locators fail to find an element, or when a custom control isn't detected as interactive.
53
+
54
+ ## Locator priority
55
+
56
+ When an agent picks a locator, it prefers the most stable option first:
57
+
58
+ ```mermaid
59
+ flowchart LR
60
+ A[ARIA, semantic text, and role] --> B[Scope with a container]
61
+ B --> C[HTML attributes, CSS, or XPath]
62
+ C --> D[Screenshot and visual coordinates]
63
+ ```
64
+
65
+ The agent starts with short semantic locators from ARIA or visible text. When a match is ambiguous, it scopes that locator to a container before moving to HTML-based selectors and, finally, visual coordinates.
66
+
67
+ 1. Short ARIA or text — `I.click({ role: 'button', text: 'Save' })` or `I.click('Save')` when it is unique
68
+ 2. Text with a container — `I.click('Save', '.modal')` — simplest and preferred when a container is known
69
+ 3. ARIA with a container — `I.click({ role: 'button', text: 'Save' }, '.modal')` — for semantic disambiguation
70
+ 4. CSS or XPath — `I.click('#save-btn')`
71
+ 5. Coordinates — `I.clickXY(400, 300)` (last resort)
72
+
73
+ When a locator fails, the agent tries the next strategy, then a visual click. Locators that worked are saved to experience and preferred on the next run.
74
+
75
+ ## What happens after each action
76
+
77
+ After every action, Explorbot captures the new page state and compares it with the previous one. The resulting diff tells the agent what changed — the URL, the accessibility tree, or the HTML — so it can confirm the action worked and decide what to do next. The Researcher turns a page into a structured UI map of sections and elements; see [Researcher](./researcher.md).
78
+
79
+ ## See also
80
+
81
+ - [Knowledge files](../workflow/knowledge.md) — teach Explorbot about your app
82
+ - [Agent hooks](./hooks.md) — run code before or after an agent
83
+ - [Configuration](../reference/configuration.md) — full configuration reference
84
+ - [Researcher](./researcher.md) — how pages become UI maps