@orkestrel/scaffold 0.0.90 → 0.0.92

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 (32) hide show
  1. package/dist/agents/templates/brief.md +2 -0
  2. package/dist/bin/main.js +3 -3
  3. package/dist/bin/main.js.map +1 -1
  4. package/dist/host/AGENTS.md +3 -3
  5. package/dist/host/agents/orchestration.md +1 -1
  6. package/dist/host/agents/skills/orkestrel-falsify/SKILL.md +3 -3
  7. package/dist/host/agents/skills/orkestrel-publish/references/window.md +3 -4
  8. package/dist/host/agents/skills/orkestrel-scout/SKILL.md +1 -1
  9. package/dist/host/agents/templates/brief.md +2 -0
  10. package/dist/host/agents/transports/cursor.md +1 -1
  11. package/dist/host/claude/agents/analyst.md +1 -1
  12. package/dist/host/claude/agents/grok.md +1 -1
  13. package/dist/host/claude/agents/orkestrel.md +16 -16
  14. package/dist/host/claude/agents/planner.md +1 -1
  15. package/dist/host/claude/agents/researcher.md +1 -1
  16. package/dist/host/claude/agents/scout.md +1 -1
  17. package/dist/host/claude/rules/names.md +1 -1
  18. package/dist/host/claude/rules/patterns.md +1 -1
  19. package/dist/host/claude/rules/quality.md +11 -0
  20. package/dist/host/claude/rules/styles.md +3 -1
  21. package/dist/host/claude/rules/tests.md +7 -8
  22. package/dist/host/claude/rules/writing.md +2 -1
  23. package/dist/host/codex/agents/researcher.toml +2 -2
  24. package/dist/host/codex/agents/scout.toml +1 -1
  25. package/dist/host/guides/browser.md +822 -609
  26. package/dist/host/guides/pool.md +154 -58
  27. package/dist/host/manifest.json +24 -24
  28. package/dist/src/core/index.cjs +4 -3
  29. package/dist/src/core/index.cjs.map +1 -1
  30. package/dist/src/core/index.js +4 -3
  31. package/dist/src/core/index.js.map +1 -1
  32. package/package.json +3 -3
@@ -7,10 +7,10 @@
7
7
 
8
8
  The package has three library faces, each with one import specifier, and the `browse` binary.
9
9
 
10
- - The core, `@orkestrel/browser`, compiles against `ESNext` and `WebWorker` with no DOM and no Node. `CDPClient` frames CDP messages over an injected `CDPTransportInterface`; `BrowserContext`, `BrowserPage`, and `BrowserFrame` model a browser context, its tabs, and their documents; `page.elements` outlines a page from its accessibility tree and acts on stable element references with trusted input; `frame.read()` captures a document as a `BrowserReadingInterface` value; `page.registry` mirrors the experimental `WebMCP` protocol domain; and `BrowserToolset` publishes all of it as `@orkestrel/tool` tools that an agent calls. The core also records, edits, replays, and compiles journeys, which [Journeys](#journeys) describes: `BrowserRecorder` and `page.codegen()` record steps, `BrowserReplay` replays them, `BrowserJourneyToolset` gives a model the six journey tools, `compileBrowserJourney` emits a module a developer runs, and two memory stores keep journeys and runs.
10
+ - The core, `@orkestrel/browser`, compiles against `ESNext` and `WebWorker` with no DOM and no Node. `CDPClient` frames CDP messages over an injected `CDPTransportInterface`; `BrowserContext`, `BrowserPage`, and `BrowserFrame` model a browser context, its tabs, and their documents; `page.elements` outlines a page from its accessibility tree and acts on stable element references with trusted input; `frame.read()` captures a document as a `BrowserReadingInterface` value; `page.registry` mirrors the experimental `WebMCP` protocol domain; and `BrowserToolset` publishes all of it as `@orkestrel/tool` tools that an agent calls. The core also records, edits, replays, and compiles journeys, which [Journeys](#journeys) describes: `BrowserRecorder` and `page.codegen()` record steps, `BrowserReplay` replays them, `BrowserJourneyToolset` gives a model the journey tools, `compileBrowserJourney` emits a module a developer runs, and two memory stores keep journeys and runs.
11
11
  - The in-page face, `@orkestrel/browser/browser`, adds the DOM. `BrowserDOMView` drives a document with `HTMLElement.click()`, native value setters, `form.requestSubmit()`, and `MutationObserver`, and reports what an untrusted event cannot do. `createDocumentToolset` publishes the same vocabulary over that view, and `SocketCDPTransport` carries the core client over the browser's own `WebSocket`, so a worker or an extension page drives a browser over CDP.
12
12
  - The Node runtime, `@orkestrel/browser/server`, adds `Browser`, which discovers a browser listening on a CDP port, attaches to it, or launches one and reads its endpoint from standard error; `WebSocketCDPTransport`; a filesystem-backed browser writer; the file journey and run stores; and `BrowserMCPServer`, which serves the vocabulary and the journey tools over MCP on stdio.
13
- - The `browse` binary, `src/bin`, reads four environment variables and starts a `BrowserMCPServer`; see [Register the browse binary with Claude Code](#register-the-browse-binary-with-claude-code) for its hookup.
13
+ - The `browse` binary, `src/bin`, reads its environment variables and starts a `BrowserMCPServer`, which starts Chromium before the client's first request; see [Register the browse binary with Claude Code](#register-the-browse-binary-with-claude-code) for its hookup.
14
14
 
15
15
  The in-page face and the Node runtime each import the core, and neither imports the other; the binary imports the core and the Node runtime. Source: [`src/core`](../src/core), [`src/browser`](../src/browser), [`src/server`](../src/server), and [`src/bin`](../src/bin).
16
16
 
@@ -33,7 +33,7 @@ await browser.destroy()
33
33
 
34
34
  ### Drive a page with a small model
35
35
 
36
- The following fence registers the browser vocabulary in a tool manager, seeds the first message with the page as `look` returns it, and hands that manager to an `@orkestrel/agent` loop over a local model. The system prompt is the one the store proof in `@orkestrel/ollama` runs with, using `qwen3.5:2b-q4_K_M` at temperature 0; see [Drive a page with a small model](#drive-a-page-with-a-small-model-1) under Patterns for the sentences it carries and which tasks it passed.
36
+ The following fence registers the browser vocabulary in a tool manager, seeds the first message with the page as `look` returns it, and hands that manager to an `@orkestrel/agent` loop over a local model. The system prompt follows the reading vocabulary. The recorded store proof in `@orkestrel/ollama`, using `qwen3.5:2b-q4_K_M` at temperature 0, used the earlier prompt; see [Drive a page with a small model](#drive-a-page-with-a-small-model-1) under Patterns for the sentences it carries and which tasks it passed.
37
37
 
38
38
  ```ts
39
39
  import { createAgent } from '@orkestrel/agent'
@@ -45,8 +45,8 @@ import { createToolManager } from '@orkestrel/tool'
45
45
  const system =
46
46
  'You control a web browser with tools and must call a tool before you answer. ' +
47
47
  'The first message shows the page as look returns it; references such as e4 name its elements. ' +
48
- 'To learn a fact, call read with what set to your question; when its result ends by naming an offset, call read again with that offset. ' +
49
- 'To search, call type with the search box reference, the words, and submit true. ' +
48
+ 'To learn a fact, call read with search set to words from your question; when its result ends by naming an offset, call read again with that offset. ' +
49
+ "To use the site's search box, call type with its reference, the words, and submit true. " +
50
50
  'To press a button or follow a link, call click with its reference from the latest result. Never invent a reference. ' +
51
51
  'If text you expect has not appeared, call wait once. ' +
52
52
  'When the task is done, answer in one short sentence.'
@@ -56,11 +56,11 @@ await browser.connect()
56
56
  const page = await browser.create({ url: 'https://shop.example.test/' })
57
57
  const toolset = createBrowserToolset(page, { tools: createToolManager() })
58
58
  await toolset.start()
59
- toolset.tools.tools().map((tool) => tool.name) // ['look', 'read', 'click', 'type', 'press', 'navigate', 'wait']
59
+ toolset.tools.tools().map((tool) => tool.name) // ['look', 'read', 'plain', 'click', 'type', 'press', 'navigate', 'wait']
60
60
  const seeded = await toolset.tools.execute({
61
61
  id: 'seed',
62
62
  name: 'look',
63
- arguments: { what: 'the page' },
63
+ arguments: { search: '' },
64
64
  })
65
65
  const view = seeded.success ? String(seeded.value) : seeded.error
66
66
  const agent = createAgent(createOllama({ model: 'qwen3.5:2b-q4_K_M' }), {
@@ -122,7 +122,7 @@ const reading = createBrowserReading({
122
122
  title: 'Example',
123
123
  html: '<nav>Menu</nav><main><p>Body</p></main>',
124
124
  })
125
- reading.markdown() // { text: 'Body', offset: 0, total: 4 }
125
+ reading.markdown({ distill: true }) // { text: 'Body', offset: 0, total: 4 }
126
126
  const snapshot = createBrowserSnapshot(await page.snapshot()) // navigable again from plain data
127
127
  const store = createMemoryBrowserJourneyStore()
128
128
  const runs = createMemoryBrowserRunStore()
@@ -140,43 +140,43 @@ const run = await createBrowserReplay(toolset, { journey }, { runs }).execute()
140
140
 
141
141
  The following table lists the core classes. Each implements the behavioral interface of the same name plus `Interface`, which [Methods](#methods) documents.
142
142
 
143
- | API | Kind | Summary |
144
- | --------------------------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
145
- | `BrowserAccessibility` | class | Captures Chromium Accessibility-domain snapshots for one page. |
146
- | `BrowserClock` | class | Controls the Chromium virtual-time budget for deterministic page timers. |
147
- | `BrowserCodegen` | class | Records semantic page gestures and compiles them into a journey module. |
148
- | `BrowserContext` | class | Owns pages and shared state inside one Chromium browser context. |
149
- | `BrowserCookieManager` | class | Performs cookie operations isolated to one browser context. |
150
- | `BrowserCoverage` | class | Collects JavaScript precise coverage and CSS rule usage for one page target. |
151
- | `BrowserDiagnostics` | class | Groups the tracing, coverage, performance, and profiler classes beneath one page. |
152
- | `BrowserEmulationManager` | class | Applies rendering, identity, location, and network emulation for context pages. |
153
- | `BrowserFrame` | class | Represents one attached document frame, evaluated through its own CDP execution world. |
154
- | `BrowserHARManager` | class | Records and replays HTTP archives over one page network manager. |
155
- | `BrowserKeyboard` | class | Sends trusted keyboard input through Chromium's CDP Input domain. |
156
- | `BrowserMouse` | class | Sends trusted mouse input through Chromium's CDP Input domain. |
157
- | `BrowserNavigationManager` | class | Parks URL-pattern and network-idle waits on page events and abort signals, and opens the records that settle the navigation an input starts. |
158
- | `BrowserNetworkManager` | class | Drives the page-scoped Network and Fetch domain lifecycle. |
159
- | `BrowserPage` | class | Represents a top-level browser page, including its target lifecycle and child frames. |
160
- | `BrowserPerformance` | class | Reads Performance-domain metrics for one frame. |
161
- | `BrowserPermissionManager` | class | Applies permission overrides isolated to one browser context. |
162
- | `BrowserProfiler` | class | Records sampled JavaScript CPU profiles over one frame's Profiler domain. |
163
- | `BrowserReading` | class | Represents one captured document, parsed one time and projected to Markdown or plain text in bounded slices. |
164
- | `BrowserScriptManager` | class | Installs new-document scripts and promise-based host functions for one page. |
165
- | `BrowserSnapshot` | class | Represents a navigable, serializable browser DOM snapshot. |
166
- | `BrowserStorageManager` | class | Imports, exports, and clears cookie and web-storage state for one browser context. |
167
- | `BrowserToolset` | class | Publishes the browser vocabulary as `@orkestrel/tool` tools over one view and adopts the view's own tools beside them. |
168
- | `BrowserTouch` | class | Sends trusted touch input through Chromium's CDP Input domain. |
169
- | `BrowserTracing` | class | Captures Chromium traces streamed through the IO domain. |
170
- | `BrowserTransition` | class | Runs one asynchronous transition at a time, shared by every caller that joins it. |
171
- | `BrowserWebSocket` | class | Represents an observable WebSocket connection reconstructed from Network-domain events. |
172
- | `CDPClient` | class | Provides a lightweight Chrome DevTools Protocol client over a `CDPTransportInterface`. |
173
- | `BrowserPageElement` | class | Drives a referenced DOM element through its document's isolated world and the page input stream. |
174
- | `BrowserElementManager` | class | Captures accessibility trees and binds stable references to their owning frame sessions. |
175
- | `BrowserRecorder` | class | Records semantic steps from completed toolset actions and omits refused or timed-out actions. |
176
- | `BrowserReplay` | class | Prepares and replays a journey under a toolset hold, retaining its executed prefix. |
177
- | `BrowserJourneyToolset` | class | Registers the journey tools `record`, `save`, `journeys`, `edit`, `replay`, and `forget` over a toolset and owns the recording and the active replay. |
178
- | `MemoryBrowserJourneyStore` | class | Keeps owned journey snapshots and revision counters across deletion. |
179
- | `MemoryBrowserRunStore` | class | Keeps owned runs under their journey names and producer ids without directories. |
143
+ | API | Kind | Summary |
144
+ | --------------------------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
145
+ | `BrowserAccessibility` | class | Captures Chromium Accessibility-domain snapshots for one page. |
146
+ | `BrowserClock` | class | Controls the Chromium virtual-time budget for deterministic page timers. |
147
+ | `BrowserCodegen` | class | Records semantic page gestures and compiles them into a journey module. |
148
+ | `BrowserContext` | class | Owns pages and shared state inside one Chromium browser context. |
149
+ | `BrowserCookieManager` | class | Performs cookie operations isolated to one browser context. |
150
+ | `BrowserCoverage` | class | Collects JavaScript precise coverage and CSS rule usage for one page target. |
151
+ | `BrowserDiagnostics` | class | Groups the tracing, coverage, performance, and profiler classes beneath one page. |
152
+ | `BrowserEmulationManager` | class | Applies rendering, identity, location, and network emulation for context pages. |
153
+ | `BrowserFrame` | class | Represents one attached document frame, evaluated through its own CDP execution world. |
154
+ | `BrowserHARManager` | class | Records and replays HTTP archives over one page network manager. |
155
+ | `BrowserKeyboard` | class | Sends trusted keyboard input through Chromium's CDP Input domain. |
156
+ | `BrowserMouse` | class | Sends trusted mouse input through Chromium's CDP Input domain. |
157
+ | `BrowserNavigationManager` | class | Parks URL-pattern and network-idle waits on page events and abort signals, and opens the records that settle the navigation an input starts. |
158
+ | `BrowserNetworkManager` | class | Drives the page-scoped Network and Fetch domain lifecycle. |
159
+ | `BrowserPage` | class | Represents a top-level browser page, including its target lifecycle and child frames. |
160
+ | `BrowserPerformance` | class | Reads Performance-domain metrics for one frame. |
161
+ | `BrowserPermissionManager` | class | Applies permission overrides isolated to one browser context. |
162
+ | `BrowserProfiler` | class | Records sampled JavaScript CPU profiles over one frame's Profiler domain. |
163
+ | `BrowserReading` | class | Represents one captured document, parsed one time and projected to Markdown or plain text in bounded slices. |
164
+ | `BrowserScriptManager` | class | Installs new-document scripts and promise-based host functions for one page. |
165
+ | `BrowserSnapshot` | class | Represents a navigable, serializable browser DOM snapshot. |
166
+ | `BrowserStorageManager` | class | Imports, exports, and clears cookie and web-storage state for one browser context. |
167
+ | `BrowserToolset` | class | Publishes the browser vocabulary as `@orkestrel/tool` tools over one view and adopts the view's own tools beside them. |
168
+ | `BrowserTouch` | class | Sends trusted touch input through Chromium's CDP Input domain. |
169
+ | `BrowserTracing` | class | Captures Chromium traces streamed through the IO domain. |
170
+ | `BrowserTransition` | class | Runs one asynchronous transition at a time, shared by every caller that joins it. |
171
+ | `BrowserWebSocket` | class | Represents an observable WebSocket connection reconstructed from Network-domain events. |
172
+ | `CDPClient` | class | Provides a lightweight Chrome DevTools Protocol client over a `CDPTransportInterface`. |
173
+ | `BrowserPageElement` | class | Drives a referenced DOM element through its document's isolated world and the page input stream. |
174
+ | `BrowserElementManager` | class | Captures accessibility trees and binds stable references to their owning frame sessions. |
175
+ | `BrowserRecorder` | class | Records semantic steps from completed toolset actions and omits refused or timed-out actions. |
176
+ | `BrowserReplay` | class | Prepares and replays a journey under a toolset hold, retaining its executed prefix. |
177
+ | `BrowserJourneyToolset` | class | Registers the journey tools `record`, `save`, `journeys`, `edit`, `replay`, `forget`, and `capture` over a toolset and owns the recording and the active replay. |
178
+ | `MemoryBrowserJourneyStore` | class | Keeps owned journey snapshots and revision counters across deletion. |
179
+ | `MemoryBrowserRunStore` | class | Keeps owned runs under their journey names and producer ids without directories. |
180
180
 
181
181
  #### Constants
182
182
 
@@ -193,6 +193,8 @@ The following table lists the core constants.
193
193
  | `BROWSER_SNAPSHOT_NODE_LIMIT` | const | Sets the default maximum node count accepted from a decoded CDP DOM snapshot, `100_000`. |
194
194
  | `BROWSER_FRAME_WORLD_NAME` | const | Names the isolated world used for iframe evaluation, `'__orkestrelBrowserFrame'`. |
195
195
  | `BROWSER_STABLE_FRAME_COUNT` | const | Sets the number of animation frames whose element bounds must agree before trusted input. |
196
+ | `BROWSER_CONTEXT_LOSS_PATTERN` | const | Matches protocol errors caused by replacement or closure of an execution context. |
197
+ | `BROWSER_WAIT_EVENTS` | const | Names the finished transitions and animations that wake a parked wait. |
196
198
  | `BROWSER_KEY_MODIFIERS` | const | Maps a canonical modifier name to its CDP Input modifier bit value. |
197
199
  | `BROWSER_MOUSE_BUTTON_MASKS` | const | Maps each public mouse button to its CDP Input pressed-button bit value. |
198
200
  | `BROWSER_HAR_CREATOR` | const | Names the tool identity embedded in HAR 1.2 documents. |
@@ -209,6 +211,7 @@ The following table lists the core constants.
209
211
  | `BROWSER_REGISTRY_OUTPUT_LIMIT` | const | Bounds adopted tool JSON output and error messages to 4096 UTF-16 code units. |
210
212
  | `BROWSER_REFERENCE_PREFIX` | const | Prefixes stable element references within a browser context. |
211
213
  | `BROWSER_OUTLINE_LIMIT` | const | Bounds the default number of actionable elements in an outline. |
214
+ | `BROWSER_SEARCH_PATTERN` | const | Matches one word of an outline search and of a row's role and name: a run of at least 3 letters or digits. |
212
215
  | `BROWSER_INTERACTIVE_ROLES` | const | Names accessibility roles that receive actionable outline references. |
213
216
  | `BROWSER_ELEMENT_REFUSALS` | const | Maps the first line of each refusal the compiled element functions throw, without its `Error: ` prefix, to the reason and the one-line detail an element action reports it with. |
214
217
  | `BROWSER_OUTLINE_OMITTED_ROLES` | const | Names accessibility roles whose own rows add no outline content. |
@@ -221,15 +224,15 @@ The following table lists the core constants.
221
224
  | `BROWSER_TOOL_HANDLED_STATUS` | const | Holds the status an action receipt carries after a submission a page listener prevented, with no navigation after it, naming `wait` as the next call because the page's outcome can arrive later. |
222
225
  | `BROWSER_TOOL_PENDING_NOTE` | const | Holds the refusal for a hold requested while an earlier input remains pending. |
223
226
  | `BROWSER_OBSERVATION_TOOL_NAMES` | const | Names the tools that observe the view without recording an action. |
224
- | `BROWSER_TOOL_CUT_FOOTER` | const | Holds the clause that ends the footer of a cut result that carries no view: a read note, a tab list, a wait, a page tool's output, or an error message. |
225
- | `BROWSER_TOOL_VIEW_FOOTER` | const | Holds the clause that ends the footer of a cut result that carries a view, the result of `look` and of every action, and names `read` as the call that returns the page's text. |
227
+ | `BROWSER_TOOL_CUT_FOOTER` | const | Holds the clause that ends the footer of a cut result other than an action or `dialog` receipt that carries a view, including `look` and `read` results. |
228
+ | `BROWSER_TOOL_VIEW_FOOTER` | const | Holds the clause that ends the footer of a cut action or `dialog` receipt that carries a view, and names `look` as the call that finds an element the cut view leaves out. |
226
229
  | `BROWSER_TYPED_ROLES` | const | Names the accessibility roles the `type` tool writes to: `textbox`, `searchbox`, and `spinbutton` take typed text, and `combobox` and `listbox` take a select control's option or, for a text input with suggestions, typed text. |
227
230
  | `BROWSER_TOOL_TIMEOUT_LIMIT_MS` | const | Caps the `wait` tool's `timeout` parameter at `30_000` milliseconds. |
228
- | `BROWSER_TOOL_NAMES` | const | Names every tool the browser toolset reserves: `look`, `read`, `click`, `type`, `press`, `navigate`, `wait`, `dialog`, `tabs`, and `switch`. |
231
+ | `BROWSER_TOOL_NAMES` | const | Names every tool the browser toolset reserves: `look`, `read`, `plain`, `click`, `type`, `press`, `navigate`, `wait`, `dialog`, `tabs`, and `switch`. |
229
232
  | `BROWSER_TOOL_NAME_PATTERN` | const | Matches a page tool name the toolset can advertise: 1 to 64 ASCII letters, digits, underscores, and hyphens. |
230
233
  | `BROWSER_SCHEMES` | const | Names the URL schemes the `navigate` tool accepts by default: `http:` and `https:`. |
231
234
  | `BROWSER_TOOL_COPY` | const | Holds the advertised definition of each reserved tool: its description, its JSON Schema parameters, and its annotations. |
232
- | `BROWSER_JOURNEY_TOOL_NAMES` | const | Names the journey tools a toolset constructed with `journeys` registers and reserves: `record`, `save`, `journeys`, `edit`, `replay`, and `forget`. |
235
+ | `BROWSER_JOURNEY_TOOL_NAMES` | const | Names the journey tools a toolset constructed with `journeys` registers and reserves: `record`, `save`, `journeys`, `edit`, `replay`, `forget`, and `capture`. |
233
236
  | `BROWSER_JOURNEY_ACTIONS` | const | Names the native actions a journey step can hold: `click`, `type`, `press`, `navigate`, `wait`, `dialog`, and `switch`. |
234
237
  | `BROWSER_ACTION_OUTCOMES` | const | Lists every outcome a `BrowserAction` and a run step carry: `done`, `refused`, `timeout`, and `interrupted`. |
235
238
  | `BROWSER_ACTION_STAGES` | const | Lists every navigation stage a `BrowserAction` and a run step carry: `requested`, `committed`, and `loaded`. |
@@ -284,7 +287,7 @@ An error names its refusal in `code`. The following table lists every code that
284
287
  | `BROWSER_CONTEXT_CLOSED` | `BrowserError` | `BrowserContext.create()` and `BrowserContext.sync()` | The context is closed, or it closed while `create()` was building the page. |
285
288
  | `BROWSER_PAGE_CLOSED` | `BrowserError` | `BrowserContext.create()` | The page it created or joined closed before it could return that page. |
286
289
  | `BROWSER_TARGET_HELD` | `BrowserError` | a page constructed through a context | Another live page holds the page's target. |
287
- | `BROWSER_WAIT_TIMEOUT` | `BrowserError` | `wait` on a page or view, `elements.wait`, the outline's wait for DOM readiness, and `BrowserDOMWait` | The text, the element, or the readiness does not arrive before the deadline. |
290
+ | `BROWSER_WAIT_TIMEOUT` | `BrowserError` | `wait` on a page or view, `elements.wait`, the outline's wait for DOM readiness, and `BrowserDOMWait` | The text or the element does not arrive, or with `absent` does not leave, or the readiness does not arrive before the deadline. |
288
291
  | `BROWSER_NAVIGATION_TIMEOUT` | `BrowserError` | `navigation.wait`, `navigation.idle`, and a record's `wait` | No matching navigation, network idle, or navigation start arrives before the timeout. |
289
292
  | `BROWSER_JSON_ERROR` | `BrowserError` | `network.json` | A response body is not valid JSON. |
290
293
  | `BROWSER_HAR_ERROR` | `BrowserError` | `har.stop` | The recording failed while it ran. |
@@ -299,11 +302,11 @@ An error names its refusal in `code`. The following table lists every code that
299
302
  | `BROWSER_TOOLSET_TAB` | `BrowserError` | `switch` | The named tab is not open. |
300
303
  | `BROWSER_TOOLSET_DIALOG` | `BrowserError` | every toolset tool, `hold()`, and `tabs()` | A dialog is open and the tool is not `dialog`, an action waits behind an earlier action whose dialog is still open, `dialog` runs with no dialog open, `hold()` is requested while a dialog is open or an earlier input is pending, or `tabs()` is called while a dialog is open. |
301
304
  | `BROWSER_TOOLSET_OBSERVE` | `BrowserError` | `click`, `type` with `submit`, and `press` | The document that receives the input could not be observed for a form submission; the action sends no input, and `context.frame` names that document's frame. |
302
- | `BROWSER_TOOLSET_LIMIT` | `BrowserError` | `read` and `journeys` | The respective toolset or journeys limit cannot hold the next character at the requested offset. |
305
+ | `BROWSER_TOOLSET_LIMIT` | `BrowserError` | `look`, `read`, `plain`, and `journeys` | The respective toolset or journeys limit cannot hold the next character at the requested offset. |
303
306
  | `BROWSER_TOOLSET_RESERVED` | `BrowserError` | `start()` | The manager holds a reserved name under a tool the toolset did not add. |
304
307
  | `BROWSER_TOOLSET_CONTEXT` | `BrowserError` | the toolset constructor | The options carry `context` without `page`. |
305
308
  | `BROWSER_TOOLSET_ENDED` | `BrowserError` | every toolset tool, `start()`, `tabs()`, and a queued action | The toolset was destroyed, or `destroy()` ran before startup finished or while the action waited in the queue. |
306
- | `BROWSER_TOOLSET_BUSY` | `BrowserError` | every action tool, `perform`, `record`, `replay`, and `hold()` | A replay holds or reserves the toolset and the call lacks its token. `look`, `read`, `tabs`, and `wait` pass. |
309
+ | `BROWSER_TOOLSET_BUSY` | `BrowserError` | every action tool, `perform`, `record`, `replay`, and `hold()` | A replay holds or reserves the toolset and the call lacks its token. `look`, `read`, `plain`, `tabs`, and `wait` pass. |
307
310
  | `BROWSER_JOURNEY_FORMAT` | `BrowserError` | `validateBrowserJourney`, `validateBrowserRun`, `compileBrowserJourney`, a replay's preparation, and the stores | A journey or run carries a `format` other than `BROWSER_JOURNEY_FORMAT_VERSION`. |
308
311
  | `BROWSER_JOURNEY_INVALID` | `BrowserError` | `validateBrowserJourney`, the step, parameter, and run validators, `compileBrowserJourney`, `recorder.journey()`, a replay's preparation, and the memory stores' `set` | A journey breaks an invariant that the message names, or a run's fields are malformed; see [Journeys](#journeys) for the invariants. |
309
312
  | `BROWSER_JOURNEY_EMPTY` | `BrowserError` | `save` | The recording has no step; the recorder keeps recording so an action can precede the next save. |
@@ -317,6 +320,8 @@ An error names its refusal in `code`. The following table lists every code that
317
320
  | `BROWSER_JOURNEY_LOCKED` | `BrowserError` | the file journey store's `set` and `delete`, the file run store's `open` and `clear`, `save`, `edit`, and `forget` | Another write holds the journey's `journey.lock`; the store refuses at once and never waits. |
318
321
  | `BROWSER_JOURNEY_FILE` | `BrowserError` | the file stores' `get` and `list`, `save`, `edit`, and `forget` for a store failure with no code, and a replay's run write | A stored file is empty, truncated, malformed, or names another journey or run, or the run write passed its bound. |
319
322
  | `BROWSER_JOURNEY_ACCESS` | `BrowserError` | the file stores | The filesystem refused permission; the message names the path. |
323
+ | `BROWSER_CAPTURE_UNTRUSTED` | `BrowserError` | `capture` | The current view is untrusted. |
324
+ | `BROWSER_CAPTURE_UNAVAILABLE` | `BrowserError` | `capture` | The view has no screenshot capability, or the runs store has no standalone file storage. |
320
325
  | `BROWSER_JOURNEY_PATH` | `BrowserError` | the file stores and their constructors, the memory stores' name checks, and the memory run store's `capture` | A journey name is invalid, an id or path escapes the root, a path component is a symbolic link, the root is missing, or a capture names a slot the store did not open. |
321
326
  | `BROWSER_JOURNEY_ARGUMENT` | `BrowserError` | the stores' `list`, the file stores' constructors, `BrowserJourneyToolset` construction, and `journeys` | A listing limit is not a positive safe integer, or an offset is not a nonnegative integer; store page offsets must also be safe integers. |
322
327
  | `BROWSER_JOURNEY_READONLY` | `BrowserError` | `record`, `save`, `edit`, and `forget` | The toolset was constructed with `journeys.readonly`. |
@@ -360,8 +365,8 @@ The helpers are pure: they decode protocol payloads, validate options, compile i
360
365
 
361
366
  | API | Kind | Summary |
362
367
  | ---------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
363
- | `compileQueryWaitExpression` | function | Compiles a mutation-driven wait with one deadline and explicit disconnect ownership. |
364
- | `compileTextWaitExpression` | function | Compiles a visible-text wait coalesced by animation frames. |
368
+ | `compileQueryWaitExpression` | function | Compiles a wait woken by mutations and finished transitions and animations, with one deadline and explicit disconnect ownership. |
369
+ | `compileTextWaitExpression` | function | Compiles a wait for the presence or absence of visible text, coalesced by tasks. |
365
370
  | `compileSelectFunction` | function | Compiles text selection or select-option assignment against the resolved element. |
366
371
  | `compileHitFunction` | function | Compiles the descendant hit check for a resolved element. |
367
372
  | `compileSubmitObserverExpression` | function | Compiles the installation of a capture-phase `submit` observer owned by `token` on the window of the world it runs in. |
@@ -375,15 +380,20 @@ The helpers are pure: they decode protocol payloads, validate options, compile i
375
380
  | `compileStorageRestoreExpression` | function | Compiles an expression that restores one origin's web storage. |
376
381
  | `compileStorageClearExpression` | function | Compiles an expression that clears local and session storage. |
377
382
  | `compileGuardedEvaluateExpression` | function | Compiles a `Runtime.evaluate` expression so the in-page code stringifies its own result and throws a recognizable sentinel error before an oversized result would overflow the CDP transport frame. |
378
- | `compileReadFunction` | function | Compiles the in-page function that reads the document's URL, title, and serialized HTML. |
383
+ | `compileReadFunction` | function | Compiles the in-page function that reads the document's URL, title, and rendered HTML. |
379
384
  | `compileActionabilityFunction` | function | Compiles the element-side actionability pass used before trusted input. |
380
385
  | `normalizeBrowserName` | function | Normalizes an accessible name for display and matching. |
381
386
  | `filterBrowserOutline` | function | Filters document-order outline rows by accessibility role and name. |
382
387
  | `renderBrowserOutline` | function | Renders document-order text and referenced elements with a bounded element count. |
388
+ | `renderBrowserOutlineRow` | function | Renders one outline row: the node's reference, its role, its quoted accessible name, and the states it carries. |
389
+ | `scanBrowserOutline` | function | Returns the referenced outline nodes whose role and accessible name share the most words with a search, in document order. |
390
+ | `collectBrowserWords` | function | Collects distinct lowercase words of at least 3 letters or digits. |
391
+ | `scanBrowserText` | function | Matches the lines sharing the most distinct search words, in document order. |
392
+ | `renderBrowserMatches` | function | Renders matching rows in at most half the available reply room. |
383
393
  | `composeBrowserPoint` | function | Composes a frame-local point with its ancestor frame offsets. |
384
394
  | `normalizeBrowserKey` | function | Normalizes named keys and modifier aliases before trusted keyboard input. |
385
395
  | `renderBrowserToolOutput` | function | Renders tool strings unchanged, content-array text blocks joined, and other values as bounded JSON. |
386
- | `deriveBrowserToolSchema` | function | Derives the advertised input schema from an authored one, adding a required `what` parameter when the schema requires nothing. |
396
+ | `deriveBrowserToolSchema` | function | Derives the advertised input schema from an authored one, adding a required `purpose` parameter when the schema requires nothing. |
387
397
  | `boundBrowserText` | function | Bounds a tool string at a character limit, appending a footer that names the cut and the caller's closing clause. |
388
398
  | `validateBrowserToolArguments` | function | Refuses a tool call that carries a parameter its definition does not advertise, naming the parameters the tool takes. |
389
399
  | `renderBrowserElement` | function | Renders an element as its outline row reads: reference, role, and quoted name. |
@@ -684,14 +694,14 @@ normalizeBrowserName(' Place order ') // 'Place order'
684
694
  composeBrowserPoint({ x: 10, y: 10 }, [{ x: 100, y: 50 }]) // { x: 110, y: 60 }
685
695
  extractBrowserSlice('one\ntwo\nthree', 0, 8) // { text: 'one\ntwo\n', offset: 0, total: 13 }
686
696
  boundBrowserText('x'.repeat(5_000), 4_000, BROWSER_TOOL_CUT_FOOTER) // 4 000 characters, then '\n[characters 0–4000 of 5000; the rest was cut]'
687
- validateBrowserToolArguments(BROWSER_TOOL_COPY.look, { what: 'cart', ref: 'e1' }) // throws BROWSER_TOOLSET_ARGUMENT: 'The look tool takes no ref parameter; call look with what.'
697
+ validateBrowserToolArguments(BROWSER_TOOL_COPY.look, { search: 'cart', ref: 'e1' }) // throws BROWSER_TOOLSET_ARGUMENT: 'The look tool takes no ref parameter; call look with search and offset.'
688
698
  renderBrowserElement(element) // 'e4 button "Place order"'
689
699
  const rows = filterBrowserOutline(nodes, { role: 'button', name: 'place' })
690
- renderBrowserOutline('https://example.test/cart', 'Cart', rows, 150) // { url, title, text, count, total }
700
+ renderBrowserOutline('https://example.test/cart', 'Cart', rows, 150) // { url, title, text, count, total, matches, focus }
691
701
  renderBrowserReceipt({ action: 'Clicked e4 button "Place order"', view }) // the receipt line, then the view
692
702
  renderBrowserToolOutput([{ type: 'text', text: 'Found 3 cars' }]) // 'Found 3 cars'
693
- readBrowserToolString({ what: 'cart' }, 'what') // 'cart'
694
- deriveBrowserToolSchema(undefined) // a schema requiring a what string
703
+ readBrowserToolString({ search: 'cart' }, 'search') // 'cart'
704
+ deriveBrowserToolSchema(undefined) // a schema requiring a purpose string
695
705
  const tool = parseBrowserTool(toolsAdded.tools[0]) // BrowserTool | undefined
696
706
  const removal = parseBrowserRemoval(toolsRemoved.tools[0]) // BrowserToolRemoval | undefined
697
707
  const invocation = parseBrowserInvocation(toolInvoked) // BrowserInvocation | undefined
@@ -895,259 +905,260 @@ validateBrowserViewport({ width: 1280, height: 720 })
895
905
 
896
906
  The following table lists the core types.
897
907
 
898
- | API | Kind | Summary |
899
- | ----------------------------------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
900
- | `CDPTransportEventMap` | type | Maps the events emitted by a `CDPTransportInterface` — the raw text pipe a `CDPClientInterface` sends and receives JSON-RPC frames over. |
901
- | `CDPTransportInterface` | interface | Represents the text pipe a `CDPClient` sends and receives JSON-RPC frames over. |
902
- | `CDPClientEventMap` | type | Maps the events a `CDPClientInterface` emits. |
903
- | `CDPClientOptions` | interface | Describes the options for creating a `CDPClient` instance. |
904
- | `CDPSendOptions` | interface | Describes the options for one CDP method call. |
905
- | `CDPHandler` | type | Receives a subscribed CDP event with its params record. |
906
- | `CDPTarget` | interface | Represents one entry of the CDP `Target.getTargets` result. |
907
- | `CDPClientInterface` | interface | Provides a lightweight Chrome DevTools Protocol client over a `CDPTransportInterface`. |
908
- | `BrowserTransitionFunction` | type | Runs the work one `BrowserTransitionInterface` transition performs. |
909
- | `BrowserTransitionInterface` | interface | Represents one asynchronous transition shared by every caller that arrives while it runs. |
910
- | `BrowserWriterInterface` | interface | Provides a pluggable sink for persisting captured browser bytes to a path. |
911
- | `BrowserViewport` | interface | Describes the viewport dimensions for a browser page. |
912
- | `BrowserWaitUntil` | type | Names the page load condition for navigation — the CDP load event awaited by `navigate()`. |
913
- | `BrowserPageOptions` | interface | Describes the options for creating a `BrowserPage` instance. |
914
- | `BrowserNavigationOptions` | interface | Describes the options for page navigation. |
915
- | `BrowserNavigationResult` | interface | Describes the outcome of a top-level navigation command. |
916
- | `BrowserNavigationWatch` | interface | Holds the state retained while correlating navigation with Network events. |
917
- | `BrowserNavigationWait` | interface | Represents one pending navigation or network-idle wait. |
918
- | `BrowserLoaderFunction` | type | Reads the loader id of the page's current document, undefined before the first commit. |
919
- | `BrowserNavigationManagerInterface` | interface | Provides URL and network-idle waits associated with one page. |
920
- | `BrowserNavigationRecordInterface` | interface | Settles the navigation an input into one frame started, from the steps the page accepted after the record opened. |
921
- | `BrowserPopupManagerInterface` | interface | Opens the records that settle the popups an input into a page opens. |
922
- | `BrowserPopupRecordInterface` | interface | Settles the popups an input opened, from the `Page.windowOpen` reports the page's own session sends after the record opened. |
923
- | `BrowserDestinationRelationship` | type | Names the frame a submission targets relative to the frame whose document submitted, mirroring the HTML `_self`, `_parent`, and `_top` keywords. |
924
- | `BrowserDestination` | interface | Pairs a document that recorded a surviving submission with the submission's destination. |
925
- | `BrowserSettlementOptions` | interface | Configures a record's settlement. |
926
- | `BrowserNavigationStage` | type | Names how far a settled navigation got: requested, committed, or loaded. |
927
- | `BrowserNavigationReason` | type | Names why a frame requested a navigation, mirroring the CDP `Page.ClientNavigationReason` values that `Page.frameRequestedNavigation` carries as of Chromium 141. |
928
- | `BrowserSettlementResult` | interface | Describes the navigation a record settled. |
929
- | `BrowserNavigationEventMap` | type | Maps the navigation steps a page accepts from the session that owns each frame, which it hands to its navigation and element managers. |
930
- | `BrowserInputOptions` | interface | Describes the options shared by every trusted input operation. |
931
- | `BrowserClickOptions` | interface | Describes the options for a trusted mouse click. |
932
- | `BrowserDragOptions` | interface | Describes the options for a trusted mouse drag. |
933
- | `BrowserScreenshotOptions` | interface | Describes the options for taking a page screenshot. |
934
- | `BrowserScreenshotResult` | interface | Describes the result of a page screenshot. |
935
- | `BrowserTeardownFunction` | type | Runs one teardown step to settlement while the first failure is retained. |
936
- | `BrowserHandleInterface` | interface | Represents a remote JavaScript object retained in one frame execution context. |
937
- | `BrowserBindingHandler` | type | Runs a host function exposed into page JavaScript. |
938
- | `BrowserBindingCall` | interface | Describes a decoded page-to-host binding call. |
939
- | `BrowserScriptManagerInterface` | interface | Manages initialization scripts and host bindings for one page. |
940
- | `BrowserScriptEntry` | interface | Represents one installed new-document script and its optional host binding owner. |
941
- | `BrowserAXNode` | interface | Represents one decoded Chromium accessibility node. |
942
- | `BrowserAccessibilitySnapshot` | interface | Describes a serializable accessibility-tree snapshot. |
943
- | `BrowserAccessibilityOptions` | interface | Describes the options for an accessibility snapshot. |
944
- | `BrowserAccessibilityInterface` | interface | Inspects the accessibility tree. |
945
- | `BrowserTracingOptions` | interface | Describes the options for a Chromium trace capture. |
946
- | `BrowserTracingResult` | interface | Describes the result of a trace capture. |
947
- | `BrowserStreamChunk` | interface | Represents one decoded IO stream read. |
948
- | `BrowserTracingInterface` | interface | Drives the trace capture lifecycle. |
949
- | `BrowserCoverageRange` | interface | Describes a source range reported by JavaScript or CSS coverage. |
950
- | `BrowserFunctionCoverage` | interface | Describes function coverage inside one script. |
951
- | `BrowserScriptCoverage` | interface | Describes JavaScript script coverage. |
952
- | `BrowserStyleCoverage` | interface | Describes CSS stylesheet coverage. |
953
- | `BrowserCoverageOptions` | interface | Describes the options for a coverage capture. |
954
- | `BrowserCoverageResult` | interface | Describes combined JavaScript and CSS usage. |
955
- | `BrowserCoverageInterface` | interface | Drives the coverage capture lifecycle. |
956
- | `BrowserMetric` | interface | Represents one Performance-domain metric. |
957
- | `BrowserProfileFrame` | interface | Describes a JavaScript call frame from a CPU profile. |
958
- | `BrowserProfileNode` | interface | Represents one node in a sampled CPU profile. |
959
- | `BrowserProfile` | interface | Describes a sampled CPU profile. |
960
- | `BrowserPerformanceInterface` | interface | Reads Performance-domain metrics. |
961
- | `BrowserProfilerInterface` | interface | Drives the sampled CPU profile lifecycle. |
962
- | `BrowserDiagnosticsInterface` | interface | Groups the diagnostics by capability. |
963
- | `BrowserClockInterface` | interface | Controls Chromium virtual time for deterministic page timers. |
964
- | `BrowserPoint` | interface | Describes a point in viewport CSS pixels. |
965
- | `BrowserMouseButton` | type | Names a mouse button understood by Chromium's Input domain. |
966
- | `BrowserScreenshotScale` | type | Names a screenshot coordinate scale. |
967
- | `BrowserKey` | interface | Describes normalized CDP keyboard key data. |
968
- | `BrowserChord` | interface | Describes a parsed keyboard chord. |
969
- | `BrowserOperationOptions` | type | Collects every option a trusted-input operation can carry. |
970
- | `BrowserKeyboardInterface` | interface | Provides keyboard input operations bound to one frame target session. |
971
- | `BrowserMouseInterface` | interface | Provides mouse input operations bound to one frame target session. |
972
- | `BrowserTouchInterface` | interface | Provides touch input operations bound to one frame target session. |
973
- | `BrowserActionabilityOptions` | interface | Describes the actionability checks performed before element input. |
974
- | `BrowserQuad` | interface | Describes a decoded content quad and its actionable center. |
975
- | `BrowserMargin` | interface | Describes the paper margin lengths accepted by Chromium print-to-PDF. |
976
- | `BrowserPDFOptions` | interface | Describes the options for printing a Chromium page to PDF. |
977
- | `BrowserPDFResult` | interface | Describes the result of printing a page to PDF. |
978
- | `BrowserDialogCategory` | type | Names a JavaScript dialog category reported by Chromium. |
979
- | `BrowserDialogInterface` | interface | Represents one active JavaScript dialog. |
980
- | `BrowserFileChooserInterface` | interface | Represents one intercepted file chooser. |
981
- | `BrowserDownloadStatus` | type | Names a download lifecycle phase. |
982
- | `BrowserDownloadEventMap` | type | Maps the download progress events. |
983
- | `BrowserDownloadProgress` | interface | Describes a protocol-neutral download progress update. |
984
- | `BrowserDownloadStart` | interface | Describes a decoded `Browser.downloadWillBegin` event. |
985
- | `BrowserDownloadInterface` | interface | Represents one context download tracked through Chromium's Browser domain. |
986
- | `BrowserConsoleMessage` | interface | Represents one console API call. |
987
- | `BrowserStackFrame` | interface | Represents one browser-side stack frame. |
988
- | `BrowserPageError` | interface | Represents one uncaught page exception. |
989
- | `BrowserWorkerCategory` | type | Names a worker target category. |
990
- | `BrowserWorkerInterface` | interface | Represents a script worker attached to a page target. |
991
- | `BrowserPageEventMap` | type | Maps the typed page, frame, target, and user-visible browser events. |
992
- | `BrowserRequest` | interface | Represents one observed browser request. |
993
- | `BrowserSecurity` | interface | Describes the TLS details supplied with a browser response. |
994
- | `BrowserTimingRange` | interface | Describes the start/end pair for one network timing phase. |
995
- | `BrowserTiming` | interface | Holds network timing values in milliseconds relative to request time. |
996
- | `BrowserResponse` | interface | Represents one observed browser response. |
997
- | `BrowserRequestFailure` | interface | Represents one failed browser request. |
998
- | `BrowserWebSocketFrame` | interface | Describes a WebSocket frame payload. |
999
- | `BrowserWebSocketEventMap` | type | Maps the WebSocket lifecycle events. |
1000
- | `BrowserWebSocketInterface` | interface | Represents one observed WebSocket connection. |
1001
- | `BrowserNetworkEventMap` | type | Maps the network events a page's network manager emits. |
1002
- | `BrowserRouteQuery` | interface | Describes route matching criteria. Omitted fields match all values. |
1003
- | `BrowserRouteContinueOptions` | interface | Describes the overrides supplied when continuing an intercepted request. |
1004
- | `BrowserRouteFulfillOptions` | interface | Describes the synthetic response supplied when fulfilling an intercepted request. |
1005
- | `BrowserRouteInterface` | interface | Represents one paused Fetch-domain request. |
1006
- | `BrowserRouteHandler` | type | Runs for a matching intercepted request. |
1007
- | `BrowserRouteDefinition` | interface | Represents one installed network route. |
1008
- | `BrowserHAROptions` | interface | Describes the options for a HAR recording. |
1009
- | `BrowserHARValue` | interface | Represents one name/value pair in an HTTP archive. |
1010
- | `BrowserHARCookie` | interface | Represents one cookie in an HTTP archive. |
1011
- | `BrowserHARPost` | interface | Describes request body metadata in an HTTP archive. |
1012
- | `BrowserHARContent` | interface | Describes response body metadata in an HTTP archive. |
1013
- | `BrowserHARRequest` | interface | Describes a HAR 1.2 request entry. |
1014
- | `BrowserHARResponse` | interface | Describes a HAR 1.2 response entry. |
1015
- | `BrowserHARTimings` | interface | Holds HAR 1.2 phase timings in milliseconds. |
1016
- | `BrowserHAREntry` | interface | Represents one completed HTTP exchange in a HAR recording. |
1017
- | `BrowserHARPending` | interface | Holds recording state until a request finishes; a new value replaces it on each update. |
1018
- | `BrowserHARCreator` | interface | Describes the tool identity embedded in an HTTP archive. |
1019
- | `BrowserHARLog` | interface | Describes the HAR 1.2 log object. |
1020
- | `BrowserHAR` | interface | Describes the standards-shaped HAR 1.2 document produced by the network manager. |
1021
- | `BrowserHARReplayOptions` | interface | Describes HAR replay behavior. |
1022
- | `BrowserHARManagerInterface` | interface | Provides HAR recording and replay operations. |
1023
- | `BrowserNetworkManagerInterface` | interface | Provides page-scoped network observation and interception. |
1024
- | `BrowserSameSite` | type | Names a cookie same-site policy understood by Chromium. |
1025
- | `BrowserCookiePartition` | interface | Describes a cookie partition key used by CHIPS-partitioned cookies. |
1026
- | `BrowserCookie` | interface | Represents one cookie returned from a browser context. |
1027
- | `BrowserCookieInput` | interface | Describes the input used to create or replace a browser cookie. |
1028
- | `BrowserCookieFilter` | interface | Describes optional narrowing criteria for clearing context cookies. |
1029
- | `BrowserCookieManagerInterface` | interface | Provides cookie operations scoped to one browser context. |
1030
- | `BrowserPermissionManagerInterface` | interface | Provides permission override operations scoped to one browser context. |
1031
- | `BrowserStorageEntry` | interface | Represents one key/value pair from web storage. |
1032
- | `BrowserStorageOrigin` | interface | Describes an origin-scoped local and session storage snapshot. |
1033
- | `BrowserStorageState` | interface | Describes a portable browser authentication and storage snapshot. |
1034
- | `BrowserStorageOptions` | interface | Describes the options for collecting storage state from selected origins. |
1035
- | `BrowserStorageManagerInterface` | interface | Provides storage-state import, export, and clearing operations. |
1036
- | `BrowserCredentials` | interface | Describes the HTTP basic-auth credentials applied to context pages. |
1037
- | `BrowserGeolocation` | interface | Describes a geographic location override. |
1038
- | `BrowserMedia` | interface | Describes browser color and media feature overrides. |
1039
- | `BrowserUserAgent` | interface | Describes user-agent metadata accepted by Chromium emulation. |
1040
- | `BrowserEmulationOptions` | interface | Describes network and rendering overrides inherited by context pages. |
1041
- | `BrowserPagesFunction` | type | Returns the context's live pages at call time. |
1042
- | `BrowserEmulationManagerInterface` | interface | Configures context-scoped emulation. |
1043
- | `BrowserProxy` | interface | Describes proxy settings used when creating an isolated browser context. |
1044
- | `BrowserDownloadOptions` | interface | Describes the download policy for a browser context. |
1045
- | `BrowserContextOptions` | interface | Describes the options for creating and configuring an isolated browser context. |
1046
- | `BrowserContextEventMap` | type | Maps the browser-context lifecycle events. |
1047
- | `BrowserJourneyBinding` | type | Binds a native action's string argument to a literal or to one declared parameter by name. |
1048
- | `BrowserJourneyParameter` | interface | Declares one parameter a journey takes: its default, or none when it is a secret. |
1049
- | `BrowserJourneyTarget` | interface | Names the element an acting step acts on the way a receipt names it, with the record-time evidence a developer reads when a resolution is refused. |
1050
- | `BrowserJourneyTab` | interface | Names the tab a `switch` step moves to, portably. |
1051
- | `BrowserJourneyStepInput` | interface | Describes one step before it holds an id: a call of a toolset tool with its element or tab named as data. |
1052
- | `BrowserJourneyStep` | interface | Describes a step with its identity: `s` followed by a positive integer, stable across edits and never reused. |
1053
- | `BrowserJourney` | interface | Describes one user intent as data; `next` is the number the next added step takes. |
1054
- | `BrowserJourneyRevision` | interface | Carries a journey with the revision the store assigned; `revision` is absent for a journey the store never held. |
1055
- | `BrowserJourneyEdit` | type | Describes one change to a journey; `editBrowserJourney` applies a batch to a copy, in order, and refuses it whole on the first invalid edit. |
1056
- | `BrowserJourneyEditRequest` | type | Describes an edit as the `edit` tool receives it over the wire: an added or updated step can name `ref` instead of a target, converted from the current view before the pure editor runs. |
1057
- | `BrowserRecorderEventMap` | type | Maps the events a recorder emits. |
1058
- | `BrowserRecorderInterface` | interface | Records the steps of a journey from one source as they happen and turns them into a journey. |
1059
- | `BrowserRecorderOptions` | interface | Configures a recorder. |
1060
- | `BrowserAction` | interface | Describes what became of one action the toolset performed. |
1061
- | `BrowserStepOutcome` | type | Names how one step ended. |
1062
- | `BrowserRunOutcome` | type | Names how a run ended. |
1063
- | `BrowserToolsetResult` | interface | Carries a performed call's tool result beside its structured action, present when the call reached a handler, and the value a failed handler threw. |
1064
- | `BrowserHoldInterface` | interface | Owns the toolset while a replay runs; `destroy` releases it. |
1065
- | `BrowserRunStep` | interface | Describes one replayed step; `action`, `trigger`, and `result` carry the meaning of the skill's `JournalStep` fields. |
1066
- | `BrowserRun` | interface | Describes one run of a journey; `inputs` omits secret values; `fault` carries the run file's write failure. |
1067
- | `BrowserReplayOptions` | interface | Configures one replay. |
1068
- | `BrowserReplayEventMap` | type | Maps the events a replay emits. |
1069
- | `BrowserReplayInterface` | interface | Replays one journey over a toolset. |
1070
- | `BrowserStoreOptions` | interface | Carries the signal a store call honours. |
1071
- | `BrowserJourneyValidationContext` | interface | Identifies the parameter binding that failed journey validation. |
1072
- | `BrowserStoreFault` | interface | Names one entry a listing could not read. |
1073
- | `BrowserStorePage` | interface | Carries one page of a listing with the entries it could not read. |
1074
- | `BrowserJourneyStoreInterface` | interface | Keeps journeys by name with a revision per write. |
1075
- | `BrowserRunSlot` | interface | Names the run directory a store opened, as data. |
1076
- | `BrowserRunStoreInterface` | interface | Keeps runs by the journey name and run id the run carries. |
1077
- | `BrowserJourneyOptions` | interface | Configures the journey toolset a toolset constructs. |
1078
- | `BrowserJourneyToolsetInterface` | interface | Registers the six journey tools over a toolset and owns the recording and the active replay. |
1079
- | `BrowserCodegenLanguage` | type | Names the target language for a compiled codegen script. |
1080
- | `BrowserCodegenInterface` | interface | Records semantic page gestures and compiles the resulting journey. |
1081
- | `BrowserCodegenScript` | interface | Carries the module `compileBrowserJourney` emits with the gap steps that refuse it. |
1082
- | `BrowserCodegenGesture` | interface | Carries a sanitized gesture from the page listener without password values. |
1083
- | `BrowserReadOptions` | interface | Describes the options for one slice of a reading's Markdown or plain-text projection. |
1084
- | `BrowserReadResult` | interface | Describes one slice of a reading's projection. |
1085
- | `BrowserEpochFunction` | type | Reads the navigation epoch of the frame a reading was captured from. |
1086
- | `BrowserReadingInput` | interface | Describes the captured document a reading is built from. |
1087
- | `BrowserReadingInterface` | interface | Represents one captured document, parsed one time and projected to Markdown or plain text in bounded slices. |
1088
- | `BrowserSessionFunction` | type | Resolves the current CDP session for a frame id. |
1089
- | `BrowserWorldFunction` | type | Resolves the isolated-world execution context a page caches for one frame document, creating the world on the given session when none is cached. |
1090
- | `BrowserElementQuery` | interface | Describes an accessibility or CSS query within an optional element reference. |
1091
- | `BrowserElementWaitOptions` | interface | Configures an element wait, including whether absence satisfies it. |
1092
- | `BrowserOutlineOptions` | interface | Configures an outline's element limit and optional subtree. |
1093
- | `BrowserOutline` | interface | Carries a document-order outline and its included and available element counts. |
1094
- | `BrowserOutlineNode` | interface | Associates an outline row with its frame, session, and optional actionable reference. |
1095
- | `BrowserElementGeometry` | interface | Retains both session-local and page-composed element geometry. |
1096
- | `BrowserElementSubject` | interface | Identifies a manager failure without inventing an element reference. |
1097
- | `BrowserElementReason` | type | Identifies the refusal an element action reports. |
1098
- | `BrowserElementRefusal` | interface | Describes how an element action reports one refusal its compiled in-page check throws: the reason, and the detail that follows the element's name, or `undefined` for the reason's own wording. |
1099
- | `BrowserReferenceFunction` | type | Allocates the next reference from the owning browser context. |
1100
- | `BrowserElementWorldFunction` | type | Resolves the page-owned isolated world for a particular frame and session. |
1101
- | `BrowserReadinessFunction` | type | Waits for the current document's DOM readiness. |
1102
- | `BrowserElementPointFunction` | type | Composes a frame-local point into page coordinates. |
1103
- | `BrowserElementManagerInput` | interface | Provides the protocol and ownership boundaries used by a page element manager. |
1104
- | `BrowserElementInput` | interface | Binds an element to its document identity and the page's shared protocol resources. |
1105
- | `BrowserReadinessWait` | interface | Holds the resources of one lifecycle-event readiness wait. |
1106
- | `BrowserElementInterface` | interface | Provides actions and reading through a stable document element reference. |
1107
- | `BrowserPageElementInterface` | interface | Provides trusted page input and capture for a referenced element. |
1108
- | `BrowserElementManagerInterface` | interface | Captures, queries, and retains references to a view's elements. |
1109
- | `BrowserViewEventMap` | type | Maps the `console` and `error` events of a view that observes its document's output. |
1110
- | `BrowserViewInterface` | interface | Provides the document operations shared by remote and DOM-native views. |
1111
- | `BrowserCallOptions` | interface | Describes the options every asynchronous page, frame, handle, and worker call accepts. |
1112
- | `BrowserToolAnnotation` | interface | Transliterates the WebMCP protocol's `Annotation` type, retaining its wire spelling. |
1113
- | `BrowserTool` | interface | Describes a registered WebMCP tool and its owning document. |
1114
- | `BrowserToolRemoval` | interface | Identifies a removed WebMCP tool by document and name. |
1115
- | `BrowserInvocation` | interface | Describes a WebMCP invocation observed on the protocol. |
1116
- | `BrowserInvocationResult` | interface | Carries a terminal WebMCP status and its untrusted output or error. |
1117
- | `BrowserRegistryEventMap` | type | Maps registry changes and observed WebMCP invocation events. |
1118
- | `BrowserRegistryOptions` | interface | Configures registry listeners and listener-error handling. |
1119
- | `BrowserRegistryInterface` | interface | Mirrors the experimental WebMCP protocol domain for a page. |
1120
- | `BrowserRegistryPending` | interface | Holds one unsettled registry execution and its resource cleanup. |
1121
- | `BrowserToolName` | type | Names a tool the browser toolset reserves: the seven generic tools, the staged `dialog`, the opt-in `tabs` and `switch`, and the journey tools `record`, `save`, `journeys`, `edit`, `replay`, and `forget`, which a toolset constructed with `journeys` reserves. |
1122
- | `BrowserToolsetReason` | type | Names why a toolset declined a page tool. |
1123
- | `BrowserToolSourceEventMap` | type | Maps the signal a tool source emits when its page's tools change. |
1124
- | `BrowserToolSourceInterface` | interface | Supplies page-registered tools to a toolset through a contract free of protocol types. |
1125
- | `BrowserToolsetEventMap` | type | Maps the events a toolset emits. |
1126
- | `BrowserToolsetOptions` | interface | Configures a browser toolset. |
1127
- | `BrowserFollowOptions` | interface | Configures one step a toolset follows. |
1128
- | `BrowserTab` | interface | Describes one open tab of a toolset's context, which the `tabs` tool lists one per line. |
1129
- | `BrowserToolsetInterface` | interface | Publishes the browser vocabulary as tools over one current view and adopts the page's own tools beside them. |
1130
- | `BrowserToolsetHandler` | type | Runs one toolset tool inside the toolset's boundary. |
1131
- | `BrowserToolsetWatch` | interface | Holds the listeners a toolset attaches to one followed page. |
1132
- | `BrowserReceipt` | interface | Describes one tool receipt before rendering. |
1133
- | `BrowserFrameInfo` | interface | Describes serializable frame metadata decoded from CDP `Page.getFrameTree`. |
1134
- | `BrowserFrameInterface` | interface | Provides the operations shared by a top-level page and an iframe document. |
1135
- | `BrowserRect` | type | Represents a rectangle in CSS pixels: x, y, width, height. |
1136
- | `BrowserLayout` | interface | Describes layout data associated with one captured DOM node. |
1137
- | `BrowserNode` | interface | Represents one serializable DOM node decoded from a CDP DOM snapshot. |
1138
- | `BrowserDocument` | interface | Represents one document captured in a CDP DOM snapshot. |
1139
- | `BrowserSnapshotInput` | interface | Describes the serializable input for a navigable browser snapshot — the form a `BrowserSnapshot` is built from and serializes back to. |
1140
- | `BrowserWalkOrder` | type | Names the structural ordering for a browser snapshot walk. |
1141
- | `BrowserWalkOptions` | interface | Describes the options for walking a browser snapshot. |
1142
- | `BrowserSiblingRelation` | type | Names a structural sibling relationship relative to a browser node. |
1143
- | `BrowserSnapshotInterface` | interface | Represents a navigable, serializable snapshot of every document attached to a page, extending `BrowserSnapshotInput` with walking, structural relationships, search, and path derivation over plain `BrowserNode` values. |
1144
- | `BrowserSnapshotOptions` | interface | Describes the options configuring capture through `BrowserPageInterface` `snapshot()`. The snapshot entity's creation input is `BrowserSnapshotInput`. |
1145
- | `BrowserNodePredicate` | type | Names the predicate form accepted by `BrowserSnapshotInterface` find, filter, and closest methods. |
1146
- | `BrowserNodeQuery` | interface | Describes a declarative browser-node matcher used by `matchesBrowserNode`. |
1147
- | `BrowserPageInterface` | interface | Abstracts a single top-level browser page, extending `BrowserFrameInterface` with navigation, screenshots, frame discovery, DOM snapshots, codegen, and target teardown. |
1148
- | `BrowserContextInterface` | interface | Represents an isolated browser session over a CDP browser context. |
1149
-
1150
- A page hands the navigation steps it accepts, typed by `BrowserNavigationEventMap`, to its element manager as `BrowserElementManagerInput.steps`, and the manager drops a child frame's references on that frame's cross-document `commit` and on its `detach`. The same emitter reaches the navigation manager through its constructor; see [`BrowserNavigationManagerInterface`](#browsernavigationmanagerinterface). `BrowserToolsetWatch` holds a toolset's `dialog`, `popup`, `close`, and `closed` listeners and no navigation listener, because a toolset follows a navigation through the page's record.
908
+ | API | Kind | Summary |
909
+ | ----------------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
910
+ | `CDPTransportEventMap` | type | Maps the events emitted by a `CDPTransportInterface` — the raw text pipe a `CDPClientInterface` sends and receives JSON-RPC frames over. |
911
+ | `CDPTransportInterface` | interface | Represents the text pipe a `CDPClient` sends and receives JSON-RPC frames over. |
912
+ | `CDPClientEventMap` | type | Maps the events a `CDPClientInterface` emits. |
913
+ | `CDPClientOptions` | interface | Describes the options for creating a `CDPClient` instance. |
914
+ | `CDPSendOptions` | interface | Describes the options for one CDP method call. |
915
+ | `CDPHandler` | type | Receives a subscribed CDP event with its params record. |
916
+ | `CDPTarget` | interface | Represents one entry of the CDP `Target.getTargets` result. |
917
+ | `CDPClientInterface` | interface | Provides a lightweight Chrome DevTools Protocol client over a `CDPTransportInterface`. |
918
+ | `BrowserTransitionFunction` | type | Runs the work one `BrowserTransitionInterface` transition performs. |
919
+ | `BrowserTransitionInterface` | interface | Represents one asynchronous transition shared by every caller that arrives while it runs. |
920
+ | `BrowserWriterInterface` | interface | Provides a pluggable sink for persisting captured browser bytes to a path. |
921
+ | `BrowserViewport` | interface | Describes the viewport dimensions for a browser page. |
922
+ | `BrowserWaitUntil` | type | Names the page load condition for navigation — the CDP load event awaited by `navigate()`. |
923
+ | `BrowserPageOptions` | interface | Describes the options for creating a `BrowserPage` instance. |
924
+ | `BrowserNavigationOptions` | interface | Describes the options for page navigation. |
925
+ | `BrowserNavigationResult` | interface | Describes the outcome of a top-level navigation command. |
926
+ | `BrowserNavigationWatch` | interface | Holds the state retained while correlating navigation with Network events. |
927
+ | `BrowserNavigationWait` | interface | Represents one pending navigation or network-idle wait. |
928
+ | `BrowserLoaderFunction` | type | Reads the loader id of the page's current document, undefined before the first commit. |
929
+ | `BrowserNavigationManagerInterface` | interface | Provides URL and network-idle waits associated with one page. |
930
+ | `BrowserNavigationRecordInterface` | interface | Settles the navigation an input into one frame started, from the steps the page accepted after the record opened. |
931
+ | `BrowserPopupManagerInterface` | interface | Opens the records that settle the popups an input into a page opens. |
932
+ | `BrowserPopupRecordInterface` | interface | Settles the popups an input opened, from the `Page.windowOpen` reports the page's own session sends after the record opened. |
933
+ | `BrowserDestinationRelationship` | type | Names the frame a submission targets relative to the frame whose document submitted, mirroring the HTML `_self`, `_parent`, and `_top` keywords. |
934
+ | `BrowserDestination` | interface | Pairs a document that recorded a surviving submission with the submission's destination. |
935
+ | `BrowserSettlementOptions` | interface | Configures a record's settlement. |
936
+ | `BrowserNavigationStage` | type | Names how far a settled navigation got: requested, committed, or loaded. |
937
+ | `BrowserNavigationReason` | type | Names why a frame requested a navigation, mirroring the CDP `Page.ClientNavigationReason` values that `Page.frameRequestedNavigation` carries as of Chromium 141. |
938
+ | `BrowserSettlementResult` | interface | Describes the navigation a record settled. |
939
+ | `BrowserNavigationEventMap` | type | Maps the navigation steps a page accepts from the session that owns each frame, which it hands to its navigation and element managers. |
940
+ | `BrowserInputOptions` | interface | Describes the options shared by every trusted input operation. |
941
+ | `BrowserClickOptions` | interface | Describes the options for a trusted mouse click. |
942
+ | `BrowserDragOptions` | interface | Describes the options for a trusted mouse drag. |
943
+ | `BrowserScreenshotOptions` | interface | Describes the options for taking a page screenshot. |
944
+ | `BrowserScreenshotResult` | interface | Describes the result of a page screenshot. |
945
+ | `BrowserTeardownFunction` | type | Runs one teardown step to settlement while the first failure is retained. |
946
+ | `BrowserHandleInterface` | interface | Represents a remote JavaScript object retained in one frame execution context. |
947
+ | `BrowserBindingHandler` | type | Runs a host function exposed into page JavaScript. |
948
+ | `BrowserBindingCall` | interface | Describes a decoded page-to-host binding call. |
949
+ | `BrowserScriptManagerInterface` | interface | Manages initialization scripts and host bindings for one page. |
950
+ | `BrowserScriptEntry` | interface | Represents one installed new-document script and its optional host binding owner. |
951
+ | `BrowserAXNode` | interface | Represents one decoded Chromium accessibility node. |
952
+ | `BrowserAccessibilitySnapshot` | interface | Describes a serializable accessibility-tree snapshot. |
953
+ | `BrowserAccessibilityOptions` | interface | Describes the options for an accessibility snapshot. |
954
+ | `BrowserAccessibilityInterface` | interface | Inspects the accessibility tree. |
955
+ | `BrowserTracingOptions` | interface | Describes the options for a Chromium trace capture. |
956
+ | `BrowserTracingResult` | interface | Describes the result of a trace capture. |
957
+ | `BrowserStreamChunk` | interface | Represents one decoded IO stream read. |
958
+ | `BrowserTracingInterface` | interface | Drives the trace capture lifecycle. |
959
+ | `BrowserCoverageRange` | interface | Describes a source range reported by JavaScript or CSS coverage. |
960
+ | `BrowserFunctionCoverage` | interface | Describes function coverage inside one script. |
961
+ | `BrowserScriptCoverage` | interface | Describes JavaScript script coverage. |
962
+ | `BrowserStyleCoverage` | interface | Describes CSS stylesheet coverage. |
963
+ | `BrowserCoverageOptions` | interface | Describes the options for a coverage capture. |
964
+ | `BrowserCoverageResult` | interface | Describes combined JavaScript and CSS usage. |
965
+ | `BrowserCoverageInterface` | interface | Drives the coverage capture lifecycle. |
966
+ | `BrowserMetric` | interface | Represents one Performance-domain metric. |
967
+ | `BrowserProfileFrame` | interface | Describes a JavaScript call frame from a CPU profile. |
968
+ | `BrowserProfileNode` | interface | Represents one node in a sampled CPU profile. |
969
+ | `BrowserProfile` | interface | Describes a sampled CPU profile. |
970
+ | `BrowserPerformanceInterface` | interface | Reads Performance-domain metrics. |
971
+ | `BrowserProfilerInterface` | interface | Drives the sampled CPU profile lifecycle. |
972
+ | `BrowserDiagnosticsInterface` | interface | Groups the diagnostics by capability. |
973
+ | `BrowserClockInterface` | interface | Controls Chromium virtual time for deterministic page timers. |
974
+ | `BrowserPoint` | interface | Describes a point in viewport CSS pixels. |
975
+ | `BrowserMouseButton` | type | Names a mouse button understood by Chromium's Input domain. |
976
+ | `BrowserScreenshotScale` | type | Names a screenshot coordinate scale. |
977
+ | `BrowserKey` | interface | Describes normalized CDP keyboard key data. |
978
+ | `BrowserChord` | interface | Describes a parsed keyboard chord. |
979
+ | `BrowserOperationOptions` | type | Collects every option a trusted-input operation can carry. |
980
+ | `BrowserKeyboardInterface` | interface | Provides keyboard input operations bound to one frame target session. |
981
+ | `BrowserMouseInterface` | interface | Provides mouse input operations bound to one frame target session. |
982
+ | `BrowserTouchInterface` | interface | Provides touch input operations bound to one frame target session. |
983
+ | `BrowserActionabilityOptions` | interface | Describes the actionability checks performed before element input. |
984
+ | `BrowserQuad` | interface | Describes a decoded content quad and its actionable center. |
985
+ | `BrowserMargin` | interface | Describes the paper margin lengths accepted by Chromium print-to-PDF. |
986
+ | `BrowserPDFOptions` | interface | Describes the options for printing a Chromium page to PDF. |
987
+ | `BrowserPDFResult` | interface | Describes the result of printing a page to PDF. |
988
+ | `BrowserDialogCategory` | type | Names a JavaScript dialog category reported by Chromium. |
989
+ | `BrowserDialogInterface` | interface | Represents one active JavaScript dialog. |
990
+ | `BrowserFileChooserInterface` | interface | Represents one intercepted file chooser. |
991
+ | `BrowserDownloadStatus` | type | Names a download lifecycle phase. |
992
+ | `BrowserDownloadEventMap` | type | Maps the download progress events. |
993
+ | `BrowserDownloadProgress` | interface | Describes a protocol-neutral download progress update. |
994
+ | `BrowserDownloadStart` | interface | Describes a decoded `Browser.downloadWillBegin` event. |
995
+ | `BrowserDownloadInterface` | interface | Represents one context download tracked through Chromium's Browser domain. |
996
+ | `BrowserConsoleMessage` | interface | Represents one console API call. |
997
+ | `BrowserStackFrame` | interface | Represents one browser-side stack frame. |
998
+ | `BrowserPageError` | interface | Represents one uncaught page exception. |
999
+ | `BrowserWorkerCategory` | type | Names a worker target category. |
1000
+ | `BrowserWorkerInterface` | interface | Represents a script worker attached to a page target. |
1001
+ | `BrowserPageEventMap` | type | Maps the typed page, frame, target, and user-visible browser events. |
1002
+ | `BrowserRequest` | interface | Represents one observed browser request. |
1003
+ | `BrowserSecurity` | interface | Describes the TLS details supplied with a browser response. |
1004
+ | `BrowserTimingRange` | interface | Describes the start/end pair for one network timing phase. |
1005
+ | `BrowserTiming` | interface | Holds network timing values in milliseconds relative to request time. |
1006
+ | `BrowserResponse` | interface | Represents one observed browser response. |
1007
+ | `BrowserRequestFailure` | interface | Represents one failed browser request. |
1008
+ | `BrowserWebSocketFrame` | interface | Describes a WebSocket frame payload. |
1009
+ | `BrowserWebSocketEventMap` | type | Maps the WebSocket lifecycle events. |
1010
+ | `BrowserWebSocketInterface` | interface | Represents one observed WebSocket connection. |
1011
+ | `BrowserNetworkEventMap` | type | Maps the network events a page's network manager emits. |
1012
+ | `BrowserRouteQuery` | interface | Describes route matching criteria. Omitted fields match all values. |
1013
+ | `BrowserRouteContinueOptions` | interface | Describes the overrides supplied when continuing an intercepted request. |
1014
+ | `BrowserRouteFulfillOptions` | interface | Describes the synthetic response supplied when fulfilling an intercepted request. |
1015
+ | `BrowserRouteInterface` | interface | Represents one paused Fetch-domain request. |
1016
+ | `BrowserRouteHandler` | type | Runs for a matching intercepted request. |
1017
+ | `BrowserRouteDefinition` | interface | Represents one installed network route. |
1018
+ | `BrowserHAROptions` | interface | Describes the options for a HAR recording. |
1019
+ | `BrowserHARValue` | interface | Represents one name/value pair in an HTTP archive. |
1020
+ | `BrowserHARCookie` | interface | Represents one cookie in an HTTP archive. |
1021
+ | `BrowserHARPost` | interface | Describes request body metadata in an HTTP archive. |
1022
+ | `BrowserHARContent` | interface | Describes response body metadata in an HTTP archive. |
1023
+ | `BrowserHARRequest` | interface | Describes a HAR 1.2 request entry. |
1024
+ | `BrowserHARResponse` | interface | Describes a HAR 1.2 response entry. |
1025
+ | `BrowserHARTimings` | interface | Holds HAR 1.2 phase timings in milliseconds. |
1026
+ | `BrowserHAREntry` | interface | Represents one completed HTTP exchange in a HAR recording. |
1027
+ | `BrowserHARPending` | interface | Holds recording state until a request finishes; a new value replaces it on each update. |
1028
+ | `BrowserHARCreator` | interface | Describes the tool identity embedded in an HTTP archive. |
1029
+ | `BrowserHARLog` | interface | Describes the HAR 1.2 log object. |
1030
+ | `BrowserHAR` | interface | Describes the standards-shaped HAR 1.2 document produced by the network manager. |
1031
+ | `BrowserHARReplayOptions` | interface | Describes HAR replay behavior. |
1032
+ | `BrowserHARManagerInterface` | interface | Provides HAR recording and replay operations. |
1033
+ | `BrowserNetworkManagerInterface` | interface | Provides page-scoped network observation and interception. |
1034
+ | `BrowserSameSite` | type | Names a cookie same-site policy understood by Chromium. |
1035
+ | `BrowserCookiePartition` | interface | Describes a cookie partition key used by CHIPS-partitioned cookies. |
1036
+ | `BrowserCookie` | interface | Represents one cookie returned from a browser context. |
1037
+ | `BrowserCookieInput` | interface | Describes the input used to create or replace a browser cookie. |
1038
+ | `BrowserCookieFilter` | interface | Describes optional narrowing criteria for clearing context cookies. |
1039
+ | `BrowserCookieManagerInterface` | interface | Provides cookie operations scoped to one browser context. |
1040
+ | `BrowserPermissionManagerInterface` | interface | Provides permission override operations scoped to one browser context. |
1041
+ | `BrowserStorageEntry` | interface | Represents one key/value pair from web storage. |
1042
+ | `BrowserStorageOrigin` | interface | Describes an origin-scoped local and session storage snapshot. |
1043
+ | `BrowserStorageState` | interface | Describes a portable browser authentication and storage snapshot. |
1044
+ | `BrowserStorageOptions` | interface | Describes the options for collecting storage state from selected origins. |
1045
+ | `BrowserStorageManagerInterface` | interface | Provides storage-state import, export, and clearing operations. |
1046
+ | `BrowserCredentials` | interface | Describes the HTTP basic-auth credentials applied to context pages. |
1047
+ | `BrowserGeolocation` | interface | Describes a geographic location override. |
1048
+ | `BrowserMedia` | interface | Describes browser color and media feature overrides. |
1049
+ | `BrowserUserAgent` | interface | Describes user-agent metadata accepted by Chromium emulation. |
1050
+ | `BrowserEmulationOptions` | interface | Describes network and rendering overrides inherited by context pages. |
1051
+ | `BrowserPagesFunction` | type | Returns the context's live pages at call time. |
1052
+ | `BrowserEmulationManagerInterface` | interface | Configures context-scoped emulation. |
1053
+ | `BrowserProxy` | interface | Describes proxy settings used when creating an isolated browser context. |
1054
+ | `BrowserDownloadOptions` | interface | Describes the download policy for a browser context. |
1055
+ | `BrowserContextOptions` | interface | Describes the options for creating and configuring an isolated browser context. |
1056
+ | `BrowserContextEventMap` | type | Maps the browser-context lifecycle events. |
1057
+ | `BrowserJourneyBinding` | type | Binds a native action's string argument to a literal or to one declared parameter by name. |
1058
+ | `BrowserJourneyParameter` | interface | Declares one parameter a journey takes: its default, or none when it is a secret. |
1059
+ | `BrowserJourneyTarget` | interface | Names the element an acting step acts on the way a receipt names it, with the record-time evidence a developer reads when a resolution is refused. |
1060
+ | `BrowserJourneyTab` | interface | Names the tab a `switch` step moves to, portably. |
1061
+ | `BrowserJourneyStepInput` | interface | Describes one step before it holds an id: a call of a toolset tool with its element or tab named as data. |
1062
+ | `BrowserJourneyStep` | interface | Describes a step with its identity: `s` followed by a positive integer, stable across edits and never reused. |
1063
+ | `BrowserJourney` | interface | Describes one user intent as data; `next` is the number the next added step takes. |
1064
+ | `BrowserJourneyRevision` | interface | Carries a journey with the revision the store assigned; `revision` is absent for a journey the store never held. |
1065
+ | `BrowserJourneyEdit` | type | Describes one change to a journey; `editBrowserJourney` applies a batch to a copy, in order, and refuses it whole on the first invalid edit. |
1066
+ | `BrowserJourneyEditRequest` | type | Describes an edit as the `edit` tool receives it over the wire: an added or updated step can name `ref` instead of a target, converted from the current view before the pure editor runs. |
1067
+ | `BrowserRecorderEventMap` | type | Maps the events a recorder emits. |
1068
+ | `BrowserRecorderInterface` | interface | Records the steps of a journey from one source as they happen and turns them into a journey. |
1069
+ | `BrowserRecorderOptions` | interface | Configures a recorder. |
1070
+ | `BrowserAction` | interface | Describes what became of one action the toolset performed. |
1071
+ | `BrowserStepOutcome` | type | Names how one step ended. |
1072
+ | `BrowserRunOutcome` | type | Names how a run ended. |
1073
+ | `BrowserToolsetResult` | interface | Carries a performed call's tool result beside its structured action, present when the call reached a handler, and the value a failed handler threw. |
1074
+ | `BrowserHoldInterface` | interface | Owns the toolset while a replay runs; `destroy` releases it. |
1075
+ | `BrowserRunStep` | interface | Describes one replayed step; `action`, `trigger`, and `result` carry the meaning of the skill's `JournalStep` fields. |
1076
+ | `BrowserRun` | interface | Describes one run of a journey; `inputs` omits secret values; `fault` carries the run file's write failure. |
1077
+ | `BrowserReplayOptions` | interface | Configures one replay. |
1078
+ | `BrowserReplayEventMap` | type | Maps the events a replay emits. |
1079
+ | `BrowserReplayInterface` | interface | Replays one journey over a toolset. |
1080
+ | `BrowserStoreOptions` | interface | Carries the signal a store call honours. |
1081
+ | `BrowserJourneyValidationContext` | interface | Identifies the parameter binding that failed journey validation. |
1082
+ | `BrowserStoreFault` | interface | Names one entry a listing could not read. |
1083
+ | `BrowserStorePage` | interface | Carries one page of a listing with the entries it could not read. |
1084
+ | `BrowserJourneyStoreInterface` | interface | Keeps journeys by name with a revision per write. |
1085
+ | `BrowserRunSlot` | interface | Names the run directory a store opened, as data. |
1086
+ | `BrowserRunStoreInterface` | interface | Keeps runs by the journey name and run id the run carries. |
1087
+ | `BrowserJourneyOptions` | interface | Configures the journey toolset a toolset constructs. |
1088
+ | `BrowserJourneyToolsetInterface` | interface | Registers the journey tools over a toolset and owns the recording and the active replay. |
1089
+ | `BrowserCodegenLanguage` | type | Names the target language for a compiled codegen script. |
1090
+ | `BrowserCodegenInterface` | interface | Records semantic page gestures and compiles the resulting journey. |
1091
+ | `BrowserCodegenScript` | interface | Carries the module `compileBrowserJourney` emits with the gap steps that refuse it. |
1092
+ | `BrowserCodegenGesture` | interface | Carries a sanitized gesture from the page listener without password values. |
1093
+ | `BrowserReadOptions` | interface | Describes the options for one slice of a reading's Markdown or plain-text projection. |
1094
+ | `BrowserReadResult` | interface | Describes one slice of a reading's projection. |
1095
+ | `BrowserReadMatch` | interface | Describes a matching line and its character offset in a reading's projection. |
1096
+ | `BrowserEpochFunction` | type | Reads the navigation epoch of the frame a reading was captured from. |
1097
+ | `BrowserReadingInput` | interface | Describes the captured document a reading is built from. |
1098
+ | `BrowserReadingInterface` | interface | Represents one captured document, parsed one time and projected to Markdown or plain text in bounded slices. |
1099
+ | `BrowserSessionFunction` | type | Resolves the current CDP session for a frame id. |
1100
+ | `BrowserWorldFunction` | type | Resolves the isolated-world execution context a page caches for one frame document, creating the world on the given session when none is cached. |
1101
+ | `BrowserElementQuery` | interface | Describes an accessibility or CSS query within an optional element reference. |
1102
+ | `BrowserWaitOptions` | interface | Configures a text or element wait, including whether absence satisfies it. |
1103
+ | `BrowserOutlineOptions` | interface | Configures an outline's element limit, optional subtree, and search. |
1104
+ | `BrowserOutline` | interface | Carries a document-order outline and its included and available element counts. |
1105
+ | `BrowserOutlineNode` | interface | Associates an outline row with its frame, session, and optional actionable reference. |
1106
+ | `BrowserElementGeometry` | interface | Retains both session-local and page-composed element geometry. |
1107
+ | `BrowserElementSubject` | interface | Identifies a manager failure without inventing an element reference. |
1108
+ | `BrowserElementReason` | type | Identifies the refusal an element action reports. |
1109
+ | `BrowserElementRefusal` | interface | Describes how an element action reports one refusal its compiled in-page check throws: the reason, and the detail that follows the element's name, or `undefined` for the reason's own wording. |
1110
+ | `BrowserReferenceFunction` | type | Allocates the next reference from the owning browser context. |
1111
+ | `BrowserElementWorldFunction` | type | Resolves the page-owned isolated world for a particular frame and session. |
1112
+ | `BrowserReadinessFunction` | type | Waits for the current document's DOM readiness. |
1113
+ | `BrowserElementPointFunction` | type | Composes a frame-local point into page coordinates. |
1114
+ | `BrowserElementManagerInput` | interface | Provides the protocol and ownership boundaries used by a page element manager. |
1115
+ | `BrowserElementInput` | interface | Binds an element to its document identity and the page's shared protocol resources. |
1116
+ | `BrowserReadinessWait` | interface | Holds the resources of one lifecycle-event readiness wait. |
1117
+ | `BrowserElementInterface` | interface | Provides actions and reading through a stable document element reference. |
1118
+ | `BrowserPageElementInterface` | interface | Provides trusted page input and capture for a referenced element. |
1119
+ | `BrowserElementManagerInterface` | interface | Captures, queries, and retains references to a view's elements. |
1120
+ | `BrowserViewEventMap` | type | Maps the `console` and `error` events of a view that observes its document's output. |
1121
+ | `BrowserViewInterface` | interface | Provides the document operations shared by remote and DOM-native views. |
1122
+ | `BrowserCallOptions` | interface | Describes the options every asynchronous page, frame, handle, and worker call accepts. |
1123
+ | `BrowserToolAnnotation` | interface | Transliterates the WebMCP protocol's `Annotation` type, retaining its wire spelling. |
1124
+ | `BrowserTool` | interface | Describes a registered WebMCP tool and its owning document. |
1125
+ | `BrowserToolRemoval` | interface | Identifies a removed WebMCP tool by document and name. |
1126
+ | `BrowserInvocation` | interface | Describes a WebMCP invocation observed on the protocol. |
1127
+ | `BrowserInvocationResult` | interface | Carries a terminal WebMCP status and its untrusted output or error. |
1128
+ | `BrowserRegistryEventMap` | type | Maps registry changes and observed WebMCP invocation events. |
1129
+ | `BrowserRegistryOptions` | interface | Configures registry listeners and listener-error handling. |
1130
+ | `BrowserRegistryInterface` | interface | Mirrors the experimental WebMCP protocol domain for a page. |
1131
+ | `BrowserRegistryPending` | interface | Holds one unsettled registry execution and its resource cleanup. |
1132
+ | `BrowserToolName` | type | Names a tool the browser toolset reserves: the generic tools, the staged `dialog`, the opt-in `tabs` and `switch`, and the journey tools `record`, `save`, `journeys`, `edit`, `replay`, `forget`, and `capture`, which a toolset constructed with `journeys` reserves. |
1133
+ | `BrowserToolsetReason` | type | Names why a toolset declined a page tool. |
1134
+ | `BrowserToolSourceEventMap` | type | Maps the signal a tool source emits when its page's tools change. |
1135
+ | `BrowserToolSourceInterface` | interface | Supplies page-registered tools to a toolset through a contract free of protocol types. |
1136
+ | `BrowserToolsetEventMap` | type | Maps the events a toolset emits. |
1137
+ | `BrowserToolsetOptions` | interface | Configures a browser toolset. |
1138
+ | `BrowserFollowOptions` | interface | Configures one step a toolset follows. |
1139
+ | `BrowserTab` | interface | Describes one open tab of a toolset's context, which the `tabs` tool lists one per line. |
1140
+ | `BrowserToolsetInterface` | interface | Publishes the browser vocabulary as tools over one current view and adopts the page's own tools beside them. |
1141
+ | `BrowserToolsetHandler` | type | Runs one toolset tool inside the toolset's boundary. |
1142
+ | `BrowserToolsetWatch` | interface | Holds the listeners a toolset attaches to one followed page. |
1143
+ | `BrowserReceipt` | interface | Describes one tool receipt before rendering. |
1144
+ | `BrowserFrameInfo` | interface | Describes serializable frame metadata decoded from CDP `Page.getFrameTree`. |
1145
+ | `BrowserFrameInterface` | interface | Provides the operations shared by a top-level page and an iframe document. |
1146
+ | `BrowserRect` | type | Represents a rectangle in CSS pixels: x, y, width, height. |
1147
+ | `BrowserLayout` | interface | Describes layout data associated with one captured DOM node. |
1148
+ | `BrowserNode` | interface | Represents one serializable DOM node decoded from a CDP DOM snapshot. |
1149
+ | `BrowserDocument` | interface | Represents one document captured in a CDP DOM snapshot. |
1150
+ | `BrowserSnapshotInput` | interface | Describes the serializable input for a navigable browser snapshot — the form a `BrowserSnapshot` is built from and serializes back to. |
1151
+ | `BrowserWalkOrder` | type | Names the structural ordering for a browser snapshot walk. |
1152
+ | `BrowserWalkOptions` | interface | Describes the options for walking a browser snapshot. |
1153
+ | `BrowserSiblingRelation` | type | Names a structural sibling relationship relative to a browser node. |
1154
+ | `BrowserSnapshotInterface` | interface | Represents a navigable, serializable snapshot of every document attached to a page, extending `BrowserSnapshotInput` with walking, structural relationships, search, and path derivation over plain `BrowserNode` values. |
1155
+ | `BrowserSnapshotOptions` | interface | Describes the options configuring capture through `BrowserPageInterface` `snapshot()`. The snapshot entity's creation input is `BrowserSnapshotInput`. |
1156
+ | `BrowserNodePredicate` | type | Names the predicate form accepted by `BrowserSnapshotInterface` find, filter, and closest methods. |
1157
+ | `BrowserNodeQuery` | interface | Describes a declarative browser-node matcher used by `matchesBrowserNode`. |
1158
+ | `BrowserPageInterface` | interface | Abstracts a single top-level browser page, extending `BrowserFrameInterface` with navigation, screenshots, frame discovery, DOM snapshots, codegen, and target teardown. |
1159
+ | `BrowserContextInterface` | interface | Represents an isolated browser session over a CDP browser context. |
1160
+
1161
+ A page hands the navigation steps it accepts, typed by `BrowserNavigationEventMap`, to its element manager as `BrowserElementManagerInput.steps`, and the manager drops a child frame's references on that frame's cross-document `commit` and on its `detach`. The input’s `recover` callback discards cached DOM readiness after context loss and parks until the destination document is ready. The same emitter reaches the navigation manager through its constructor; see [`BrowserNavigationManagerInterface`](#browsernavigationmanagerinterface). `BrowserToolsetWatch` holds a toolset's `dialog`, `popup`, `close`, and `closed` listeners and no navigation listener, because a toolset follows a navigation through the page's record.
1151
1162
 
1152
1163
  ### Server
1153
1164
 
@@ -1167,14 +1178,14 @@ await browser.destroy() // closes the process and releases resources
1167
1178
 
1168
1179
  The following table lists the server factories.
1169
1180
 
1170
- | API | Kind | Summary |
1171
- | ------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1172
- | `createBrowser` | function | Creates a raw-CDP `BrowserInterface` façade with discovery, connection, and lifecycle management. |
1173
- | `createCDPTransport` | function | Creates a Node `WebSocket`-backed `CDPTransportInterface` for the given CDP debugger URL. |
1174
- | `createBrowserWriter` | function | Creates a filesystem-backed `BrowserWriterInterface` that persists bytes through `node:fs/promises`. |
1175
- | `createFileBrowserJourneyStore` | function | Creates a journey store over an existing filesystem root. |
1176
- | `createFileBrowserRunStore` | function | Creates a run store over an existing filesystem root. |
1177
- | `createBrowserMCPServer` | function | Creates the browse server, which serves the browser vocabulary and the journey tools over the Model Context Protocol on stdio and launches Chromium on the first tool call. |
1181
+ | API | Kind | Summary |
1182
+ | ------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1183
+ | `createBrowser` | function | Creates a raw-CDP `BrowserInterface` façade with discovery, connection, and lifecycle management. |
1184
+ | `createCDPTransport` | function | Creates a Node `WebSocket`-backed `CDPTransportInterface` for the given CDP debugger URL. |
1185
+ | `createBrowserWriter` | function | Creates a filesystem-backed `BrowserWriterInterface` that persists bytes through `node:fs/promises`. |
1186
+ | `createFileBrowserJourneyStore` | function | Creates a journey store over an existing filesystem root. |
1187
+ | `createFileBrowserRunStore` | function | Creates a run store over an existing filesystem root. |
1188
+ | `createBrowserMCPServer` | function | Creates the browse server, which serves the browser vocabulary and the journey tools over the Model Context Protocol on stdio and warms Chromium at server start. |
1178
1189
 
1179
1190
  The following fence builds the Node transport and the filesystem writer that `Browser` composes.
1180
1191
 
@@ -1190,14 +1201,14 @@ await writer.write('shots/hero.png', new Uint8Array([137, 80, 78, 71]))
1190
1201
 
1191
1202
  The following table lists the server classes.
1192
1203
 
1193
- | API | Kind | Summary |
1194
- | ------------------------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1195
- | `Browser` | class | Discovers, launches, connects to, and owns Chromium-family browser sessions. |
1196
- | `WebSocketCDPTransport` | class | Provides a raw CDP text transport backed by `@orkestrel/websocket`. |
1197
- | `FileBrowserWriter` | class | Persists captured browser bytes to the filesystem through `node:fs/promises`. |
1198
- | `FileBrowserJourneyStore` | class | Persists journeys with exclusive writes and revision counters retained across deletion. |
1199
- | `FileBrowserRunStore` | class | Persists runs and captures only in directories allocated by this instance. |
1200
- | `BrowserMCPServer` | class | Implements `BrowserMCPServerInterface`: serves the browser vocabulary and the journey tools over the Model Context Protocol on stdio, and launches Chromium on the first tool call. |
1204
+ | API | Kind | Summary |
1205
+ | ------------------------- | ----- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1206
+ | `Browser` | class | Discovers, launches, connects to, and owns Chromium-family browser sessions. |
1207
+ | `WebSocketCDPTransport` | class | Provides a raw CDP text transport backed by `@orkestrel/websocket`. |
1208
+ | `FileBrowserWriter` | class | Persists captured browser bytes to the filesystem through `node:fs/promises`. |
1209
+ | `FileBrowserJourneyStore` | class | Persists journeys with exclusive writes and revision counters retained across deletion. |
1210
+ | `FileBrowserRunStore` | class | Persists runs and captures only in directories allocated by this instance. |
1211
+ | `BrowserMCPServer` | class | Implements `BrowserMCPServerInterface`: serves the browser vocabulary and the journey tools over the Model Context Protocol on stdio, and warms Chromium at server start. |
1201
1212
 
1202
1213
  #### Constants
1203
1214
 
@@ -1237,6 +1248,21 @@ The following table lists the server constants.
1237
1248
  | `BROWSER_JOURNEY_LOCK_DIRECTORY` | const | Names the exclusive journey write lock directory. |
1238
1249
  | `BROWSER_RUN_FILE` | const | Names the persisted run snapshot. |
1239
1250
  | `BROWSER_RUN_DIRECTORY` | const | Names the journey directory holding its runs. |
1251
+ | `BROWSER_SERVER_POOL_SIZE` | const | Sets the default number of warm browsers to 1. |
1252
+ | `BROWSER_SERVER_POOL_LIMIT` | const | Limits the number of warm browsers to 3. |
1253
+ | `BROWSER_SERVER_RESTARTS` | const | Permits one failed refill before the next failure spends the bound. |
1254
+ | `BROWSER_SERVER_RECORD` | const | Names the browser process record in each profile. |
1255
+ | `BROWSER_SERVER_EXHAUSTED` | const | Names the diagnostic when the warm floor spends its restart bound. |
1256
+ | `BROWSER_SERVER_LAUNCH` | const | Names a failed attempt to warm a browser. |
1257
+ | `BROWSER_SERVER_TEARDOWN` | const | Names a failed browser server teardown. |
1258
+ | `BROWSER_SERVER_SWEEP` | const | Names a failed profile sweep. |
1259
+ | `BROWSER_SERVER_OPTIONS` | const | Names a refused browser server option. |
1260
+ | `BROWSER_SERVER_UNAVAILABLE` | const | Names the refusal when no browser can serve a call. |
1261
+ | `BROWSER_SERVER_CRASH` | const | Names the notice that a browser and its session state were lost. |
1262
+ | `BROWSER_SERVER_UNRESOLVED` | const | Names an interrupted call whose outcome is unknown. |
1263
+ | `BROWSER_SERVER_BUSY` | const | Names the refusal when every browser is admitted to a holder. |
1264
+ | `BROWSER_SERVER_HOLDER` | const | Names the refusal for an unknown or ended holder. |
1265
+ | `BROWSER_SERVER_COPY` | const | Defines the holder tools independently of the shared browser's vocabulary. |
1240
1266
  | `BROWSER_FILE_STORE_LIMIT` | const | Bounds a file-store listing page by default. |
1241
1267
 
1242
1268
  #### Errors
@@ -1269,28 +1295,32 @@ try {
1269
1295
 
1270
1296
  The following table lists the server helpers.
1271
1297
 
1272
- | API | Kind | Summary |
1273
- | ------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
1274
- | `findSystemBrowsers` | function | Enumerates every Chrome/Chromium/Edge executable discoverable on this machine, deduplicated by normalized absolute path. |
1275
- | `findSystemBrowser` | function | Locates a Chrome/Chromium/Edge executable on this machine — the first entry of `findSystemBrowsers`. |
1276
- | `formatBrowserLockEntry` | function | Formats a process identifier and UUID token as a lock entry name. |
1277
- | `parseBrowserLockEntry` | function | Parses the holder process identifier from a lock entry name. |
1278
- | `parseBrowserEngine` | function | Classifies an executable path/name into a `BrowserEngine` by case-insensitive hint, checked in the order edge → chromium → chrome. |
1279
- | `normalizeExecutablePath` | function | Normalizes an executable path for cross-source deduplication (case-insensitive on Windows). |
1280
- | `browserToEngine` | function | Classifies a `/json/version` `Browser` string into a `BrowserEngine` (`Edg/` → edge, `Chrome/` → chrome, else chromium). |
1281
- | `createBrowserProfile` | function | Resolves a persistent caller profile or creates an isolated temporary one. |
1282
- | `removeBrowserProfile` | function | Removes a library-owned isolated browser profile. |
1283
- | `findEnvOverrides` | function | Checks the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order and returns every one that exists. |
1284
- | `buildInstallPaths` | function | Builds the default well-known install-path candidates for a platform, deriving Windows roots from env vars. |
1285
- | `buildWindowsRoots` | function | Derives Windows install roots from env vars, falling back to well-known literals when absent. |
1286
- | `findInstallPaths` | function | Returns every candidate path that exists on disk, in the given order. |
1287
- | `probePathNames` | function | Probes PATH (`which`/`where`) for every resolvable command name, in the given order. |
1288
- | `readFirstLine` | function | Returns the first non-empty line of a command's output, without its surrounding whitespace. |
1289
- | `buildStoreBases` | function | Builds the default Playwright browser store base directories to search for a managed Chromium. |
1290
- | `findStorePaths` | function | Searches one store base for the top-level `chromium` link and every `chromium-*` install, highest revision first. |
1291
- | `launchBrowserProcess` | function | Launches a browser process with raw-CDP debugging flags. |
1292
- | `readBrowserEndpoint` | function | Reads the CDP endpoint a launched browser announces on its standard error. |
1293
- | `fetchCDPTargets` | function | Fetches the current CDP target list from a browser's `/json/list` endpoint, as a `Result` carrying either the targets or a coded `BrowserConnectionError`. |
1298
+ | API | Kind | Summary |
1299
+ | --------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
1300
+ | `findSystemBrowsers` | function | Enumerates every Chrome/Chromium/Edge executable discoverable on this machine, deduplicated by normalized absolute path. |
1301
+ | `findSystemBrowser` | function | Locates a Chrome/Chromium/Edge executable on this machine — the first entry of `findSystemBrowsers`. |
1302
+ | `formatBrowserLockEntry` | function | Formats a process identifier and UUID token as a lock entry name. |
1303
+ | `probeProcess` | function | Probes whether a process has not been confirmed absent. |
1304
+ | `parseBrowserProfileRecord` | function | Parses a profile record naming a positive process identifier and a loopback DevTools endpoint. |
1305
+ | `parseBrowserViewport` | function | Parses positive integer viewport dimensions in WIDTHxHEIGHT form. |
1306
+ | `describeBrowserServerLoss` | function | Describes a browser loss with its code, cause, and the session state it invalidates. |
1307
+ | `parseBrowserLockEntry` | function | Parses the holder process identifier from a lock entry name. |
1308
+ | `parseBrowserEngine` | function | Classifies an executable path/name into a `BrowserEngine` by case-insensitive hint, checked in the order edge → chromium → chrome. |
1309
+ | `normalizeExecutablePath` | function | Normalizes an executable path for cross-source deduplication (case-insensitive on Windows). |
1310
+ | `browserToEngine` | function | Classifies a `/json/version` `Browser` string into a `BrowserEngine` (`Edg/` → edge, `Chrome/` → chrome, else chromium). |
1311
+ | `createBrowserProfile` | function | Resolves a persistent caller profile or creates an isolated temporary one. |
1312
+ | `removeBrowserProfile` | function | Removes a library-owned isolated browser profile. |
1313
+ | `findEnvOverrides` | function | Checks the env-override keys (`PLAYWRIGHT_EXECUTABLE_PATH`, `CHROME_PATH`) in order and returns every one that exists. |
1314
+ | `buildInstallPaths` | function | Builds the default well-known install-path candidates for a platform, deriving Windows roots from env vars. |
1315
+ | `buildWindowsRoots` | function | Derives Windows install roots from env vars, falling back to well-known literals when absent. |
1316
+ | `findInstallPaths` | function | Returns every candidate path that exists on disk, in the given order. |
1317
+ | `probePathNames` | function | Probes PATH (`which`/`where`) for every resolvable command name, in the given order. |
1318
+ | `readFirstLine` | function | Returns the first non-empty line of a command's output, without its surrounding whitespace. |
1319
+ | `buildStoreBases` | function | Builds the default Playwright browser store base directories to search for a managed Chromium. |
1320
+ | `findStorePaths` | function | Searches one store base for the top-level `chromium` link and every `chromium-*` install, highest revision first. |
1321
+ | `launchBrowserProcess` | function | Launches a browser process with raw-CDP debugging flags. |
1322
+ | `readBrowserEndpoint` | function | Reads the CDP endpoint a launched browser announces on its standard error. |
1323
+ | `fetchCDPTargets` | function | Fetches the current CDP target list from a browser's `/json/list` endpoint, as a `Result` carrying either the targets or a coded `BrowserConnectionError`. |
1294
1324
 
1295
1325
  The following fence composes system-browser discovery, a launch, and the endpoint read that replaces HTTP readiness polling.
1296
1326
 
@@ -1347,24 +1377,31 @@ if (found !== undefined) {
1347
1377
 
1348
1378
  The following table lists the server types.
1349
1379
 
1350
- | API | Kind | Summary |
1351
- | ------------------------------ | --------- | ----------------------------------------------------------------------------------------------- |
1352
- | `BrowserEngine` | type | Names a supported browser engine (raw CDP targets Chromium-family browsers only). |
1353
- | `BrowserConnection` | type | Names how the browser connection was established. |
1354
- | `BrowserStatus` | type | Names the lifecycle status of a browser wrapper. |
1355
- | `BrowserDiscoveryResult` | interface | Describes the result of passive browser discovery. |
1356
- | `SystemBrowserOptions` | interface | Describes the options overriding `findSystemBrowsers`'/`findSystemBrowser`'s candidate sources. |
1357
- | `SystemBrowser` | type | Represents one discovered browser executable on this machine. |
1358
- | `BrowserProfileResult` | interface | Describes the resolved browser profile directory used for a Chromium-family launch. |
1359
- | `BrowserCDPOptions` | interface | Configures the CDP (Chrome DevTools Protocol) connection. |
1360
- | `BrowserEventMap` | type | Maps the events a `BrowserInterface` emits. |
1361
- | `BrowserOptions` | interface | Describes the options for creating a `Browser` instance. |
1362
- | `BrowserInterface` | interface | Wraps a browser with discovery, connection management, and lifecycle control. |
1363
- | `WebSocketCDPTransportOptions` | interface | Describes the options for creating a `WebSocketCDPTransport` instance. |
1364
- | `FileBrowserStoreOptions` | interface | Configures a file store: its root under the checkout and the listing cap. |
1365
- | `BrowserLaunchFunction` | type | Creates the browser a browse server connects on its first tool call. |
1366
- | `BrowserMCPServerOptions` | interface | Configures the browse server. |
1367
- | `BrowserMCPServerInterface` | interface | Serves the browser vocabulary and the journey tools over MCP on stdio. |
1380
+ | API | Kind | Summary |
1381
+ | ------------------------------ | --------- | --------------------------------------------------------------------------------------------------------------------- |
1382
+ | `BrowserEngine` | type | Names a supported browser engine (raw CDP targets Chromium-family browsers only). |
1383
+ | `BrowserConnection` | type | Names how the browser connection was established. |
1384
+ | `BrowserStatus` | type | Names the lifecycle status of a browser wrapper. |
1385
+ | `BrowserDiscoveryResult` | interface | Describes the result of passive browser discovery. |
1386
+ | `SystemBrowserOptions` | interface | Describes the options overriding `findSystemBrowsers`'/`findSystemBrowser`'s candidate sources. |
1387
+ | `SystemBrowser` | type | Represents one discovered browser executable on this machine. |
1388
+ | `BrowserProfileRecord` | interface | Names the browser a browse profile serves, which a later start's sweep reads. |
1389
+ | `BrowserProfileResult` | interface | Describes the resolved browser profile directory used for a Chromium-family launch. |
1390
+ | `BrowserCDPOptions` | interface | Configures the CDP (Chrome DevTools Protocol) connection. |
1391
+ | `BrowserEventMap` | type | Maps the events a `BrowserInterface` emits. |
1392
+ | `BrowserOptions` | interface | Describes the options for creating a `Browser` instance. |
1393
+ | `BrowserInterface` | interface | Wraps a browser with discovery, connection management, and lifecycle control. |
1394
+ | `WebSocketCDPTransportOptions` | interface | Describes the options for creating a `WebSocketCDPTransport` instance. |
1395
+ | `FileBrowserStoreOptions` | interface | Configures a file store: its root under the checkout and the listing cap. |
1396
+ | `BrowserLaunchFunction` | type | Creates a browser a browse server connects while warming its pool. |
1397
+ | `BrowserSlot` | interface | Holds one warm browser a browse server owns: the browser, its profile, its isolated context, and its started toolset. |
1398
+ | `BrowserSlotWatch` | interface | Holds the listeners and resolver of one browser slot's loss watch. |
1399
+ | `BrowserMCPServerOptions` | interface | Configures the browse server. |
1400
+ | `BrowserServerToolName` | type | Names the server tools that manage independent browser holders. |
1401
+ | `BrowserServerHolder` | interface | Identifies one admitted browser lifetime independently of its current pool token. |
1402
+ | `BrowserServerCatalog` | interface | Describes the JSON catalog returned by the holder tools. |
1403
+ | `BrowserServerMirror` | interface | Binds shared catalog subscriptions to the exact token that published them. |
1404
+ | `BrowserMCPServerInterface` | interface | Serves the browser vocabulary and the journey tools over MCP on stdio. |
1368
1405
 
1369
1406
  ### Browser
1370
1407
 
@@ -1386,7 +1423,7 @@ view.destroy()
1386
1423
 
1387
1424
  const toolset = createDocumentToolset({ document: frame.contentDocument })
1388
1425
  await toolset.start()
1389
- toolset.tools.tools().map((tool) => tool.name) // ['look', 'read', 'click', 'type', 'wait']
1426
+ toolset.tools.tools().map((tool) => tool.name) // ['look', 'read', 'plain', 'click', 'type', 'wait']
1390
1427
 
1391
1428
  const client = createCDPClient({
1392
1429
  transport: createSocketCDPTransport({ url: 'ws://127.0.0.1:9222/devtools/browser/abc' }),
@@ -1408,13 +1445,13 @@ The following table lists the in-page factories.
1408
1445
 
1409
1446
  The following table lists the in-page classes. `BrowserDOMView` implements `BrowserDOMViewInterface`, `BrowserDOMElement` implements `BrowserDOMElementInterface`, `BrowserDOMElementManager` implements `BrowserElementManagerInterface`, `BrowserDOMWait` implements `BrowserDOMWaitInterface`, and `SocketCDPTransport` implements `CDPTransportInterface`.
1410
1447
 
1411
- | API | Kind | Summary |
1412
- | -------------------------- | ----- | ---------------------------------------------------------------------------------------------- |
1413
- | `BrowserDOMView` | class | Reads and drives a DOM document from a realm that can reach it, without trusted input. |
1414
- | `BrowserDOMWait` | class | Parks one condition on DOM mutations until it holds, with one deadline and no other timer. |
1415
- | `BrowserDOMElement` | class | Drives a referenced element of a DOM document without trusted input. |
1416
- | `BrowserDOMElementManager` | class | Outlines a DOM document from its elements and binds stable references to the interactive ones. |
1417
- | `SocketCDPTransport` | class | Provides a raw CDP text transport over the browser's native `WebSocket`. |
1448
+ | API | Kind | Summary |
1449
+ | -------------------------- | ----- | ---------------------------------------------------------------------------------------------------------------------------------------- |
1450
+ | `BrowserDOMView` | class | Reads and drives a DOM document from a realm that can reach it, without trusted input. |
1451
+ | `BrowserDOMWait` | class | Parks one condition on DOM mutations and finished transitions and animations until it holds, with one deadline and coalesced wake tasks. |
1452
+ | `BrowserDOMElement` | class | Drives a referenced element of a DOM document without trusted input. |
1453
+ | `BrowserDOMElementManager` | class | Outlines a DOM document from its elements and binds stable references to the interactive ones. |
1454
+ | `SocketCDPTransport` | class | Provides a raw CDP text transport over the browser's native `WebSocket`. |
1418
1455
 
1419
1456
  #### Constants
1420
1457
 
@@ -1426,6 +1463,8 @@ The following table lists the in-page constants.
1426
1463
  | `BROWSER_IMPLICIT_ROLES` | const | Maps an HTML element to the ARIA role the HTML Accessibility API Mappings specification gives it when it carries no `role` attribute. |
1427
1464
  | `BROWSER_CONTENT_NAMED_ROLES` | const | Names the ARIA roles whose accessible name the accessible-name computation takes from the element's content when no attribute or label names it. |
1428
1465
  | `BROWSER_CONTEXT_TARGETS` | const | Names the link and form targets that navigate the current browsing context or one of its ancestors. `_blank` opens another browsing context, and any other name targets the browsing context carrying that name, which `matchesBrowserPopup` resolves. |
1466
+ | `BROWSER_EXPANDED_ROLES` | const | Names the roles whose ARIA expansion state the DOM outline reads. |
1467
+ | `BROWSER_SELECTED_ROLES` | const | Names the roles whose selection state the DOM outline reads. |
1429
1468
  | `BROWSER_TYPED_INPUTS` | const | Names the `input` type states whose value an untrusted `fill` sets as typed text. |
1430
1469
  | `BROWSER_INTERACTIVE_CONTENT` | const | Selects the HTML interactive content a click inside a `label` can land on without activating the label, as the HTML interactive-content category lists it: `a` with `href`, `audio` and `video` with `controls`, `button`, `details`, `embed`, `iframe`, `img` with `usemap` or `controls`, `input` other than `hidden`, `label`, `select`, and `textarea`. |
1431
1470
 
@@ -1439,7 +1478,7 @@ The helpers compute the accessible role, name, and text of an element and the vi
1439
1478
 
1440
1479
  | API | Kind | Summary |
1441
1480
  | --------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1442
- | `readBrowserCapture` | function | Reads the URL, title, and serialized markup a DOM reading is built from, refusing a capture over the result limit before any parse. |
1481
+ | `readBrowserCapture` | function | Reads the URL, title, and rendered markup a DOM reading is built from, refusing a capture over the result limit before any parse. |
1443
1482
  | `isBrowserDocument` | function | Narrows a value to a `Document` attached to a window. |
1444
1483
  | `computeBrowserRole` | function | Computes the ARIA role of an element from its `role` attribute or its implicit mapping. |
1445
1484
  | `computeBrowserName` | function | Computes the accessible name of an element, trimmed and whitespace-collapsed. |
@@ -1457,6 +1496,8 @@ The helpers compute the accessible role, name, and text of an element and the vi
1457
1496
  | `skipBrowserSubtree` | function | Moves a tree walker past the subtree of its current node. |
1458
1497
  | `readBrowserBlock` | function | Reads the nearest block container of an element, the unit that separates runs of text. |
1459
1498
  | `listenBrowserNavigation` | function | Subscribes one listener to a window's navigation events until a signal aborts. |
1499
+ | `readBrowserToken` | function | Reads a lowercased ARIA token, preserving whitespace and treating empty or undefined tokens as absent. |
1500
+ | `readBrowserStates` | function | Reads the pressed, expanded, and selected states the DOM outline assigns to an element's role. |
1460
1501
 
1461
1502
  The following fence reads one button the page appends to its own document.
1462
1503
 
@@ -1522,8 +1563,8 @@ The following table lists the in-page types.
1522
1563
  | `BrowserDOMViewInterface` | interface | Provides the document operations of a view that drives a DOM document in its own realm. |
1523
1564
  | `BrowserDOMElementManagerInput` | interface | Binds a DOM element manager to the view that owns it. |
1524
1565
  | `BrowserDOMElementInput` | interface | Binds a DOM element to its reference and the manager that minted it. |
1525
- | `BrowserMutationWait` | interface | Describes one wait parked on DOM mutations. |
1526
- | `BrowserDOMWaitInterface` | interface | Settles one wait parked on DOM mutations. |
1566
+ | `BrowserMutationWait` | interface | Describes one wait parked on DOM mutations and finished transitions and animations. |
1567
+ | `BrowserDOMWaitInterface` | interface | Settles one wait parked on DOM mutations and finished transitions and animations. |
1527
1568
  | `SocketCDPTransportOptions` | interface | Configures a CDP transport over the browser's `WebSocket`. |
1528
1569
 
1529
1570
  ## Methods
@@ -1603,6 +1644,8 @@ await client.close()
1603
1644
 
1604
1645
  #### `BrowserContextInterface`
1605
1646
 
1647
+ `BrowserContextOptions.reference` supplies the allocator every page in the context uses, including pages attached by `sync()`. Share one allocator across contexts to keep their references distinct. Without it, each context starts its own counter at `e1`.
1648
+
1606
1649
  An isolated browser session over a CDP browser context; follows the manager
1607
1650
  accessor pattern (`page(index?)` / `pages()`).
1608
1651
 
@@ -1629,18 +1672,18 @@ Operations shared by a top-level page and an iframe document. Every asynchronous
1629
1672
 
1630
1673
  A child target runs only after the page has instrumented it. A context configures each page session's auto-attach with `waitForDebuggerOnStart: true`, and the page does the same on each out-of-process frame session, with an `iframe` filter, and on each popup it opens, so every target the page's auto-attach reaches attaches paused. For a frame session the page sends `Page.enable`, `Runtime.enable`, `Page.setLifecycleEventsEnabled`, and `Target.setAutoAttach` and then resumes the target with `Runtime.runIfWaitingForDebugger`; it resumes a worker after `Runtime.enable`, a popup after the popup's domains and network manager start, and any other target at once. The first commit and load of a frame that moved into another process therefore arrive on its new session and carry the loader of the navigation that moved it: on Chromium 141, the new session reports `Page.frameNavigated` with that loader after the resume, the page session then reports the swap, and the new session reports `load` with the same loader. A target the page cannot enable is resumed and then detached, because on Chromium 141 a paused target stays paused after a detach without a resume, so it does not run and its parent document does not reach `load`; the detach waits until the resume attempt settles through a reply, a refusal, the client's timeout, or the connection's close. The page reads a frame session's frame tree only when the attach named no `parentFrameId`, and then only for the frame's parent, URL, and name. [`tests/src/core/BrowserPage.test.ts`](../tests/src/core/BrowserPage.test.ts) pins the order of each step.
1631
1674
 
1632
- | Method | Returns | Summary |
1633
- | ------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1634
- | `title` | `Promise<string>` | Resolves the frame document title. |
1635
- | `read` | `Promise<BrowserReadingInterface>` | Captures the document URL, title, and HTML in one size-guarded evaluation in the frame's isolated world and returns them as a reading whose `stale` flag tracks later navigations. A frame constructed without an epoch source (a standalone `BrowserFrame` with no `epoch` argument) returns readings whose `stale` stays `false`, because no navigation counter is available to it. |
1636
- | `evaluate` | `Promise<unknown>` | Evaluates an expression in the frame execution world under the result-size guard. |
1637
- | `handle` | `Promise<BrowserHandleInterface>` | Evaluates an expression by reference and returns a disposable remote object handle. |
1638
- | `send` | `Promise<unknown>` | Issues a raw CDP method in the frame's current target session, with a trailing `BrowserCallOptions` carrying a per-call `timeout` overriding the client-wide default and a `signal` that aborts the call. |
1639
- | `subscribe` | `Promise<void>` | Subscribes to a CDP event in the frame's current target session. |
1640
- | `unsubscribe` | `Promise<void>` | Removes a frame-session CDP event subscription. |
1641
- | `save` | `Promise<void>` | Persists bytes through a page writer; a child frame rejects because it owns no writer. |
1642
- | `assert` | `void` | Throws a coded `BrowserError` when the frame can no longer accept protocol work: a frame throws after the CDP client disconnects, and a page also throws after it closes. Every other member here calls it first. |
1643
- | `update` | `void` | Records an externally observed URL as the frame's current `url`, which a page calls from its own `Page.frameNavigated` handler. |
1675
+ | Method | Returns | Summary |
1676
+ | ------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1677
+ | `title` | `Promise<string>` | Resolves the frame document title. |
1678
+ | `read` | `Promise<BrowserReadingInterface>` | Captures the document URL, title, and rendered HTML in one size-guarded evaluation in the frame's isolated world and returns them as a reading whose `stale` flag tracks later navigations. A frame constructed without an epoch source (a standalone `BrowserFrame` with no `epoch` argument) returns readings whose `stale` stays `false`, because no navigation counter is available to it. `BrowserReadingInput` defines the rendered markup. |
1679
+ | `evaluate` | `Promise<unknown>` | Evaluates an expression in the frame execution world under the result-size guard. |
1680
+ | `handle` | `Promise<BrowserHandleInterface>` | Evaluates an expression by reference and returns a disposable remote object handle. |
1681
+ | `send` | `Promise<unknown>` | Issues a raw CDP method in the frame's current target session, with a trailing `BrowserCallOptions` carrying a per-call `timeout` overriding the client-wide default and a `signal` that aborts the call. |
1682
+ | `subscribe` | `Promise<void>` | Subscribes to a CDP event in the frame's current target session. |
1683
+ | `unsubscribe` | `Promise<void>` | Removes a frame-session CDP event subscription. |
1684
+ | `save` | `Promise<void>` | Persists bytes through a page writer; a child frame rejects because it owns no writer. |
1685
+ | `assert` | `void` | Throws a coded `BrowserError` when the frame can no longer accept protocol work: a frame throws after the CDP client disconnects, and a page also throws after it closes. Every other member here calls it first. |
1686
+ | `update` | `void` | Records an externally observed URL as the frame's current `url`, which a page calls from its own `Page.frameNavigated` handler. |
1644
1687
 
1645
1688
  ```ts
1646
1689
  const child = await page.frame('checkout')
@@ -1663,12 +1706,12 @@ child?.update('https://example.com/checkout') // record a URL observed elsewhere
1663
1706
 
1664
1707
  The document operations a remote page and a DOM view share, and the contract a `BrowserToolset` drives. `trusted` is `true` for a `BrowserPage` and `false` for a `BrowserDOMView`, and `elements` is the view's element manager. The capture capability is optional: `emitter` reports the document's output as `BrowserViewEventMap` `console` and `error` events, and `screenshot` captures the view's image bytes. A `BrowserPage` declares both, and a `BrowserDOMView` declares neither. A replay reads output and captures only from a view whose `trusted` is `true` and that declares the member.
1665
1708
 
1666
- | Method | Returns | Summary |
1667
- | ------------ | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1668
- | `screenshot` | `Promise<BrowserScreenshotResult>` | Captures PNG or JPEG bytes of the view. |
1669
- | `title` | `Promise<string>` | Resolves the document title. |
1670
- | `read` | `Promise<BrowserReadingInterface>` | Captures the document URL, title, and markup as a reading whose `stale` flag tracks later navigations. |
1671
- | `wait` | `Promise<void>` | Resolves when `text` is visible in the document; rejects with a `BrowserError` coded `BROWSER_WAIT_TIMEOUT` at the deadline, and with `signal.reason` on abort. |
1709
+ | Method | Returns | Summary |
1710
+ | ------------ | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1711
+ | `screenshot` | `Promise<BrowserScreenshotResult>` | Captures PNG or JPEG bytes of the view. |
1712
+ | `title` | `Promise<string>` | Resolves the document title. |
1713
+ | `read` | `Promise<BrowserReadingInterface>` | Captures the document URL, title, and rendered markup as a reading whose `stale` flag tracks later navigations; `BrowserReadingInput` defines the rendered markup. |
1714
+ | `wait` | `Promise<void>` | Resolves when the main document body’s `innerText` contains `text`, or lacks it with `absent`; rejects with a `BrowserError` coded `BROWSER_WAIT_TIMEOUT` at the deadline, and with `signal.reason` on abort. |
1672
1715
 
1673
1716
  The following fence drives a view without knowing its placement.
1674
1717
 
@@ -1686,35 +1729,35 @@ A top-level page. It extends `BrowserFrameInterface` and `BrowserViewInterface`,
1686
1729
 
1687
1730
  A page constructed through a context, which passes it a reference allocator, holds its target on the client's connection until it closes, that connection ends, or its setup fails, and the first such page on a connection enables target discovery for it through `Target.setDiscoverTargets`. A second live page for a target another page holds is refused with `BROWSER_TARGET_HELD`. A page constructed directly, as `new BrowserPage(client, target, session)`, holds no target, enables no discovery, and counts as published when its setup completes. A context's `create()` that meets a page another path published for its target joins that page: it applies its `on` hooks, `viewport`, and `url` to that page and resolves with it, and it rejects with `BROWSER_PAGE_CLOSED` when that page closed. A discovered popup is published one time, after its opener, through the opener's `popup`, the context's `page` event, and `pages()`. When the page holding a popup's target fails its setup, discovery publishes nothing and attaches nothing; a later `sync()` adds the target as a page, and the opener emits no `popup` for it.
1688
1731
 
1689
- | Method | Returns | Summary |
1690
- | ------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1691
- | `wait` | `Promise<void>` | Waits for visible text in the main document, rejecting at the deadline or on abort. |
1692
- | `navigate` | `Promise<BrowserNavigationResult>` | Goes to a URL, waits for the requested load condition, and returns the final URL with its response correlation. |
1693
- | `reload` | `Promise<BrowserNavigationResult>` | Reloads the page and returns the final URL with its response correlation. |
1694
- | `back` | `Promise<BrowserNavigationResult>` | Navigates to the previous history entry, or returns the unchanged URL when none exists. |
1695
- | `forward` | `Promise<BrowserNavigationResult>` | Navigates to the next history entry, or returns the unchanged URL when none exists. |
1696
- | `screenshot` | `Promise<BrowserScreenshotResult>` | Captures PNG or JPEG bytes, optionally full-page and persisted through an injected writer. |
1697
- | `pdf` | `Promise<BrowserPDFResult>` | Prints the page to PDF bytes, optionally persisted through the injected writer. |
1698
- | `frame` | `Promise<BrowserFrameInterface \| undefined>` | Looks up a first-class frame by name or URL. |
1699
- | `frames` | `Promise<readonly BrowserFrameInterface[]>` | Decodes the flattened frame tree, main frame first. |
1700
- | `snapshot` | `Promise<BrowserSnapshotInterface>` | Captures and decodes every attached document, shadow root, template content, layout box, and requested computed style. |
1701
- | `codegen` | `Promise<BrowserCodegenInterface>` | Starts the action recorder, or returns the running one. |
1702
- | `destroy` | `Promise<void>` | Releases local resources and detaches without closing the remote target. |
1703
- | `close` | `Promise<void>` | Closes the remote target and releases its resources. |
1704
- | `title` | `Promise<string>` | Resolves the frame document title. |
1705
- | `read` | `Promise<BrowserReadingInterface>` | Captures the document URL, title, and HTML in one size-guarded evaluation in the frame's isolated world and returns them as a reading whose `stale` flag tracks later navigations. A frame constructed without an epoch source (a standalone `BrowserFrame` with no `epoch` argument) returns readings whose `stale` stays `false`, because no navigation counter is available to it. |
1706
- | `evaluate` | `Promise<unknown>` | Evaluates an expression in the frame execution world under the result-size guard. |
1707
- | `handle` | `Promise<BrowserHandleInterface>` | Evaluates an expression by reference and returns a disposable remote object handle. |
1708
- | `send` | `Promise<unknown>` | Issues a raw CDP method in the frame's current target session, with a trailing `BrowserCallOptions` carrying a per-call `timeout` overriding the client-wide default and a `signal` that aborts the call. |
1709
- | `subscribe` | `Promise<void>` | Subscribes to a CDP event in the frame's current target session. |
1710
- | `unsubscribe` | `Promise<void>` | Removes a frame-session CDP event subscription. |
1711
- | `save` | `Promise<void>` | Persists bytes through a page writer; a child frame rejects because it owns no writer. |
1712
- | `assert` | `void` | Throws a coded `BrowserError` when the frame can no longer accept protocol work: a frame throws after the CDP client disconnects, and a page also throws after it closes. Every other member here calls it first. |
1713
- | `update` | `void` | Records an externally observed URL as the frame's current `url`, which a page calls from its own `Page.frameNavigated` handler. |
1732
+ | Method | Returns | Summary |
1733
+ | ------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1734
+ | `wait` | `Promise<void>` | Waits for text in the main document body’s `innerText`, or its absence with `absent`, rejecting at the deadline or on abort. |
1735
+ | `navigate` | `Promise<BrowserNavigationResult>` | Goes to a URL, waits for the requested load condition, and returns the final URL with its response correlation. |
1736
+ | `reload` | `Promise<BrowserNavigationResult>` | Reloads the page and returns the final URL with its response correlation. |
1737
+ | `back` | `Promise<BrowserNavigationResult>` | Navigates to the previous history entry, or returns the unchanged URL when none exists. |
1738
+ | `forward` | `Promise<BrowserNavigationResult>` | Navigates to the next history entry, or returns the unchanged URL when none exists. |
1739
+ | `screenshot` | `Promise<BrowserScreenshotResult>` | Captures PNG or JPEG bytes, optionally full-page and persisted through an injected writer. |
1740
+ | `pdf` | `Promise<BrowserPDFResult>` | Prints the page to PDF bytes, optionally persisted through the injected writer. |
1741
+ | `frame` | `Promise<BrowserFrameInterface \| undefined>` | Looks up a first-class frame by name or URL. |
1742
+ | `frames` | `Promise<readonly BrowserFrameInterface[]>` | Decodes the flattened frame tree, main frame first. |
1743
+ | `snapshot` | `Promise<BrowserSnapshotInterface>` | Captures and decodes every attached document, shadow root, template content, layout box, and requested computed style. |
1744
+ | `codegen` | `Promise<BrowserCodegenInterface>` | Starts the action recorder, or returns the running one. |
1745
+ | `destroy` | `Promise<void>` | Releases local resources and detaches without closing the remote target. |
1746
+ | `close` | `Promise<void>` | Closes the remote target and releases its resources. |
1747
+ | `title` | `Promise<string>` | Resolves the frame document title. |
1748
+ | `read` | `Promise<BrowserReadingInterface>` | Captures the document URL, title, and rendered HTML in one size-guarded evaluation in the frame's isolated world and returns them as a reading whose `stale` flag tracks later navigations. A frame constructed without an epoch source (a standalone `BrowserFrame` with no `epoch` argument) returns readings whose `stale` stays `false`, because no navigation counter is available to it. `BrowserReadingInput` defines the rendered markup. |
1749
+ | `evaluate` | `Promise<unknown>` | Evaluates an expression in the frame execution world under the result-size guard. |
1750
+ | `handle` | `Promise<BrowserHandleInterface>` | Evaluates an expression by reference and returns a disposable remote object handle. |
1751
+ | `send` | `Promise<unknown>` | Issues a raw CDP method in the frame's current target session, with a trailing `BrowserCallOptions` carrying a per-call `timeout` overriding the client-wide default and a `signal` that aborts the call. |
1752
+ | `subscribe` | `Promise<void>` | Subscribes to a CDP event in the frame's current target session. |
1753
+ | `unsubscribe` | `Promise<void>` | Removes a frame-session CDP event subscription. |
1754
+ | `save` | `Promise<void>` | Persists bytes through a page writer; a child frame rejects because it owns no writer. |
1755
+ | `assert` | `void` | Throws a coded `BrowserError` when the frame can no longer accept protocol work: a frame throws after the CDP client disconnects, and a page also throws after it closes. Every other member here calls it first. |
1756
+ | `update` | `void` | Records an externally observed URL as the frame's current `url`, which a page calls from its own `Page.frameNavigated` handler. |
1714
1757
 
1715
1758
  ```ts
1716
1759
  await page.navigate('https://example.com', { condition: 'idle' })
1717
- await page.wait('Welcome', { timeout: 5_000 }) // visible text, parked on a MutationObserver
1760
+ await page.wait('Welcome', { timeout: 5_000 }) // wakes on mutations, transitionend, and animationend
1718
1761
  const reading = await page.read()
1719
1762
  await page.reload()
1720
1763
  await page.back()
@@ -1733,19 +1776,19 @@ await page.close()
1733
1776
 
1734
1777
  Captures a view's document as an outline and binds a stable reference to each interactive element it lists. A reference is `e` followed by a positive integer, minted from one counter the browser context owns on CDP and the view owns in the DOM placement, so a number is never reused. A cross-document navigation of the main document drops every reference; a child frame's navigation or detachment drops that frame's references. On CDP the outline reads `Accessibility.getFullAXTree` on the page session and on each out-of-process frame session and waits for the current loader's `DOMContentLoaded`; in the DOM placement it walks the document through open shadow roots and same-origin frames and lists an `option` row under each `select`. A query with `exact: true` matches the whole accessible name after whitespace normalization, case-sensitively, which is how a journey step names its element; without it, `name` matches a case-insensitive substring.
1735
1778
 
1736
- | Method | Returns | Summary |
1737
- | ---------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1738
- | `outline` | `Promise<BrowserOutline>` | Captures the view's document as a document-order outline, binding a reference to each interactive element and bounding the referenced rows by `limit`. |
1739
- | `find` | `Promise<readonly TElement[]>` | Returns the elements matching `query` by role, case-insensitive accessible-name substring, or CSS selector, within an optional referenced element. |
1740
- | `wait` | `Promise<readonly TElement[]>` | Resolves with the elements matching `query` after a mutation produces a match, or after none matches when `absent` is set; rejects at the deadline or on abort. |
1741
- | `element` | `TElement \| undefined` | Returns the element a reference names, or `undefined` when the reference is unknown or was dropped. |
1742
- | `elements` | `readonly TElement[]` | Returns every element the manager holds a reference to. |
1743
- | `clear` | `void` | Drops every reference the manager holds. |
1779
+ | Method | Returns | Summary |
1780
+ | ---------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
1781
+ | `outline` | `Promise<BrowserOutline>` | Captures the view's document as a document-order outline, binding a reference to each interactive element and bounding the referenced rows by `limit`. The outline also lists the rows that best match `search` and names the focused referenced row, both past `limit`. |
1782
+ | `find` | `Promise<readonly TElement[]>` | Returns the elements matching `query` by role, case-insensitive accessible-name substring, or CSS selector, within an optional referenced element. |
1783
+ | `wait` | `Promise<readonly TElement[]>` | Resolves with the elements matching `query` after a mutation or a finished transition or animation produces a match, or after none matches when `absent` is set; rejects at the deadline or on abort. |
1784
+ | `element` | `TElement \| undefined` | Returns the element a reference names, or `undefined` when the reference is unknown or was dropped. |
1785
+ | `elements` | `readonly TElement[]` | Returns every element the manager holds a reference to. |
1786
+ | `clear` | `void` | Drops every reference the manager holds. |
1744
1787
 
1745
1788
  The following fence outlines a page, finds by role and name, and waits for an element a later mutation inserts.
1746
1789
 
1747
1790
  ```ts
1748
- const outline = await page.elements.outline({ limit: 150 }) // { url, title, text, count, total }
1791
+ const outline = await page.elements.outline({ limit: 150 }) // { url, title, text, count, total, matches, focus }
1749
1792
  log(outline.text) // page "Cart" https://example.test/cart\n# Your cart\ne1 link "Home"\n…
1750
1793
  const [save] = await page.elements.find({ role: 'button', name: 'sav' }) // matches "Save"
1751
1794
  const exact = await page.elements.find({ role: 'button', name: 'Save', exact: true }) // "Save" alone, not "save" or "Save draft"
@@ -1767,7 +1810,7 @@ The element contract both placements share: `BrowserPageElementInterface` extend
1767
1810
  | `fill` | `Promise<void>` | Replaces the value of a text control with `value`, dispatching the input events that typing fires. |
1768
1811
  | `select` | `Promise<void>` | Selects the options of a `select` element whose value or label matches `values`, dispatching `input` and `change`. |
1769
1812
  | `focus` | `Promise<void>` | Moves focus to the element. |
1770
- | `read` | `Promise<BrowserReadingInterface>` | Captures the element's markup with its document's URL and title as a reading whose `stale` flag tracks later navigations of that document. |
1813
+ | `read` | `Promise<BrowserReadingInterface>` | Captures the element's rendered markup with its document's URL and title as a reading whose `stale` flag tracks later navigations of that document; `BrowserReadingInput` defines the rendered markup. |
1771
1814
  | `submit` | `Promise<void>` | Submits the form the element belongs to. The CDP placement focuses the element and presses Enter through a trusted key pair, sending the release even after an abort; the DOM placement calls the form's `requestSubmit()` and reports the outcome through a `submit` listener. |
1772
1815
 
1773
1816
  The following fence fills and submits a form through a view's element manager without knowing its placement.
@@ -1788,7 +1831,13 @@ async function order(view: BrowserViewInterface): Promise<void> {
1788
1831
 
1789
1832
  #### `BrowserPageElementInterface`
1790
1833
 
1791
- One referenced element of a page, acted on through trusted input on the page session. `frame` is a Surface data member: the id of the frame whose document holds the element, which a toolset passes to `page.navigation.record`. A click scrolls the element into view, checks that it is visible, enabled, and stable across two animation frames, reads its content quad on its own session, hit-tests the quad center, and dispatches a pressed and released mouse event; each step refuses with a coded `BrowserElementError` whose `context.reason` is `GONE`, `HIDDEN`, `OCCLUDED`, `DISABLED`, `UNTRUSTED`, or `UNKNOWN`, and whose one-line message carries that reason and, for `GONE`, the refresh directive `; call look for fresh refs.` For an element inside an out-of-process frame the point is composed through each frame's content box.
1834
+ Filling and selecting check visibility and enabled state without waiting for animation frames;
1835
+ filling also checks editability. The actionability compiler samples frames only when its caller
1836
+ requests `stable: true`, so a hidden tab does not suspend a check that needs no paint.
1837
+ Pointer actions activate their owning page before sampling stability, because Chromium suspends
1838
+ animation frames in hidden tabs. The stability check still uses real animation frames.
1839
+
1840
+ One referenced element of a page, acted on through trusted input on the page session. `frame` is a Surface data member: the id of the frame whose document holds the element, which a toolset passes to `page.navigation.record`. A click scrolls the element into view, checks that it is visible, enabled, and stable across two animation frames, waits for consecutive rendering frames to report equal document scroll offsets, reads its content quad on its own session, hit-tests the quad center, and dispatches a pressed and released mouse event; each step refuses with a coded `BrowserElementError` whose `context.reason` is `GONE`, `HIDDEN`, `OCCLUDED`, `DISABLED`, `UNTRUSTED`, or `UNKNOWN`, and whose one-line message carries that reason and, for `GONE`, the refresh directive `; call look for fresh refs.` The scroll wait shares the actionability call's timeout and signal and uses no polling timer. Hover and the drag source share this wait. A protocol hit-test refusal because the location held no node reports `OCCLUDED`. For an element inside an out-of-process frame the point is composed through each frame's content box.
1792
1841
 
1793
1842
  | Method | Returns | Summary |
1794
1843
  | ------------ | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -1802,7 +1851,7 @@ One referenced element of a page, acted on through trusted input on the page ses
1802
1851
  | `fill` | `Promise<void>` | Replaces the value of a text control with `value`, dispatching the input events that typing fires. |
1803
1852
  | `select` | `Promise<void>` | Selects the options of a `select` element whose value or label matches `values`, dispatching `input` and `change`. |
1804
1853
  | `focus` | `Promise<void>` | Moves focus to the element. |
1805
- | `read` | `Promise<BrowserReadingInterface>` | Captures the element's markup with its document's URL and title as a reading whose `stale` flag tracks later navigations of that document. |
1854
+ | `read` | `Promise<BrowserReadingInterface>` | Captures the element's rendered markup with its document's URL and title as a reading whose `stale` flag tracks later navigations of that document; `BrowserReadingInput` defines the rendered markup. |
1806
1855
  | `submit` | `Promise<void>` | Submits the form the element belongs to. The CDP placement focuses the element and presses Enter through a trusted key pair, sending the release even after an abort; the DOM placement calls the form's `requestSubmit()` and reports the outcome through a `submit` listener. |
1807
1856
 
1808
1857
  The following fence acts on elements the manager found.
@@ -1829,7 +1878,15 @@ const shot = await save?.screenshot({ format: 'png' })
1829
1878
 
1830
1879
  #### `BrowserReadingInterface`
1831
1880
 
1832
- One captured document, parsed one time and projected to Markdown or to plain text. Each projection runs over `html.distill({ base: url })` by default and over the whole document with `distill: false`, is computed one time per reading and mode, and is cut into slices that share one `total`; the next slice starts at `offset + text.length`. `stale` is derived from the navigation epoch the frame had at capture, which a cross-document navigation, a same-document navigation, and a detachment each advance.
1881
+ Captures from a view, frame, or element import the root into an inert document and prune against live layout before projection. Stylesheet-hidden branches and invisible text are absent; a visible descendant of an invisible wrapper remains. Closed details keep their first summary. SVG `switch` keeps the child element with client rects, or its first child element when none has rects, including definitions referenced by `use`; other branches are absent. Canvas, video, and audio fallback text, active floor elements, and content hidden by `content-visibility: hidden` are absent. Assigned light content remains when its slot is displayed; shadow-root-owned text isn't captured. The live document isn't changed.
1882
+
1883
+ Forms, displayed dialogs, and buttons become neutral carriers. Text fields and textareas carry live values, with visible placeholders for empty text fields and textareas. A collapsed select carries its selected option's label; a listbox carries displayed option and group labels inside its client area, including unselected rows. Explicit graphic alternatives appear once, while printed button text takes precedence over an accessible name. Links carry their live resolved addresses. Carriers and block `div`, `summary`, and `details` elements receive `br` separators around their contents. The `html` handle contains this normalized capture; caller-supplied HTML remains as supplied. Direct element reads apply the same ancestor visibility and child-pruning rules.
1884
+
1885
+ Password and hidden inputs are absent from the capture and every projection, including the data-only fallback for detached roots and documents without a window. Checkbox, radio, range, and color submission values aren't printed text. Native control captions, localized dates, invalid or intermediate number edits, and MathML are omitted rather than guessed. A file input contributes its sole filename; native multiple-file summaries are omitted. Valid committed numbers use their live value. `look` still carries the controls.
1886
+
1887
+ Opacity, size, position, clipping outside listboxes, and `content-visibility: auto` don't exclude content. Generated content, text transformations, localized number formatting, textarea clipping, and significant spaces remain fidelity limits. The capture retains `nav`, `header`, `footer`, `aside`, and `menu`; `distill: true` still drops regions and might select a main article. The default `distill: false` keeps the whole captured document. `wait` uses `innerText`, so its text isn't an exact oracle for lowered controls or graphic alternatives.
1888
+
1889
+ One captured document, parsed one time and projected to Markdown or to plain text. Each projection runs over the whole document by default and over `html.distill({ base: url })` with `distill: true`, is computed one time per reading and mode, and is cut into slices that share one `total`; the next slice starts at `offset + text.length`. `stale` is derived from the navigation epoch the frame had at capture, which a cross-document navigation, a same-document navigation, and a detachment each advance.
1833
1890
 
1834
1891
  | Method | Returns | Summary |
1835
1892
  | ---------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
@@ -1843,19 +1900,48 @@ const reading = await page.read()
1843
1900
  let slice = reading.markdown({ limit: 4_000 })
1844
1901
  while (slice.offset + slice.text.length < slice.total && !reading.stale)
1845
1902
  slice = reading.markdown({ offset: slice.offset + slice.text.length, limit: 4_000 })
1846
- const whole = reading.text({ distill: false }) // navigation and footer included
1903
+ const whole = reading.text() // navigation and footer included
1904
+ const main = reading.text({ distill: true }) // main content without navigation or footer
1905
+ ```
1906
+
1907
+ The following fence finds matching lines in the whole-page plain-text projection. Match offsets count UTF-16 code units in that projection.
1908
+
1909
+ ```ts
1910
+ import {
1911
+ createBrowserReading,
1912
+ collectBrowserWords,
1913
+ scanBrowserText,
1914
+ renderBrowserMatches,
1915
+ } from '@orkestrel/browser'
1916
+
1917
+ const reading = createBrowserReading({
1918
+ url: 'https://example.test/',
1919
+ title: '',
1920
+ html: '<nav>Menu</nav><main><p>Blue kettle</p></main>',
1921
+ })
1922
+ reading.text().text // 'Menu\nBlue kettle'
1923
+ reading.text({ distill: true }).text // 'Blue kettle'
1924
+ const words = [...collectBrowserWords('Blue BLUE to 12')] // ['blue']
1925
+ const matches = scanBrowserText(reading.text().text, 'blue kettle')
1926
+ matches // [{ offset: 5, text: 'Blue kettle' }]
1927
+ renderBrowserMatches(
1928
+ 'Matches:',
1929
+ matches.map((match) => `[${match.offset}] ${match.text}`),
1930
+ 100,
1931
+ )
1932
+ // 'Matches:\n[5] Blue kettle\n\n'
1847
1933
  ```
1848
1934
 
1849
1935
  #### `BrowserRegistryInterface`
1850
1936
 
1851
- The adapter over the experimental `WebMCP` protocol domain, at `page.registry`. `start` subscribes the domain's four events on the page session and then sends `WebMCP.enable`, and resolves `false` when the browser answers `-32601` (method not found), which Chromium 141 does. The registry enables the domain on each out-of-process frame session the page reports, keys its mirror by frame and name, and emits `change`, `invoke`, and `respond`. `adopt` projects every tool as an untrusted `ToolInterface`: `readOnly` maps to `pure`, `consequential` to `consequential`, and a schema that requires nothing gains a required `what` string that is stripped before the invocation.
1937
+ The adapter over the experimental `WebMCP` protocol domain, at `page.registry`. `start` subscribes the domain's four events on the page session and then sends `WebMCP.enable`, and resolves `false` when the browser answers `-32601` (method not found), which Chromium 141 does. The registry enables the domain on each out-of-process frame session the page reports, keys its mirror by frame and name, and emits `change`, `invoke`, and `respond`. `adopt` projects every tool as an untrusted `ToolInterface`: `readOnly` maps to `pure`, `consequential` to `consequential`, and a schema that requires nothing gains a required `purpose` string that is stripped before the invocation.
1852
1938
 
1853
1939
  | Method | Returns | Summary |
1854
1940
  | --------- | ----------------------------------- | ----------------------------------------------------------------------------------------- |
1855
1941
  | `start` | `Promise<boolean>` | Enables observation; returns `false` only when the protocol domain is absent. |
1856
1942
  | `tool` | `BrowserTool \| undefined` | Finds a tool; an omitted frame prefers the main document, then registration order. |
1857
1943
  | `tools` | `readonly BrowserTool[]` | Returns every registered tool, including shadowed frame registrations. |
1858
- | `adopt` | `Promise<readonly ToolInterface[]>` | Projects tools as untrusted executable tools, omitting optional-what schemas. |
1944
+ | `adopt` | `Promise<readonly ToolInterface[]>` | Projects tools as untrusted executable tools, omitting optional-purpose schemas. |
1859
1945
  | `execute` | `Promise<BrowserInvocationResult>` | Invokes a tool and awaits its terminal event; rejects on abort, invalidation, or timeout. |
1860
1946
  | `destroy` | `Promise<void>` | Disables every enabled session, unsubscribes, and rejects pending invocations. |
1861
1947
 
@@ -1895,7 +1981,7 @@ source.emitter.on('change', async () => {
1895
1981
 
1896
1982
  #### `BrowserToolsetInterface`
1897
1983
 
1898
- Publishes the browser vocabulary as `@orkestrel/tool` tools over one current view and adopts the page's tools beside them. A page-backed toolset advertises `look`, `read`, `click`, `type`, `press`, `navigate`, and `wait`, stages `dialog` while a dialog is open, and with the `context` option adds `tabs` and `switch`; a view-backed toolset advertises `look`, `read`, `click`, `type`, and `wait`. Every tool declares at least one required parameter, every result and error message is cut at `limit` characters plus a footer, and actions run one at a time in first-in, first-out order. `native` holds the generic tools alone, which is what a consumer publishes to a built-in browser agent. [Toolset vocabulary](#toolset-vocabulary) lists each tool and the receipts it returns.
1984
+ Publishes the browser vocabulary as `@orkestrel/tool` tools over one current view and adopts the page's tools beside them. A page-backed toolset advertises `look`, `read`, `plain`, `click`, `type`, `press`, `navigate`, and `wait`, stages `dialog` while a dialog is open, and with the `context` option adds `tabs` and `switch`; a view-backed toolset advertises `look`, `read`, `plain`, `click`, `type`, and `wait`. Every tool declares at least one required parameter, `look`, `read`, and `plain` return pages of at most `limit` characters that name the offset of the next page, every other result and error message is cut at `limit` characters plus a footer, and actions run one at a time in first-in, first-out order. `native` holds the generic tools alone, which is what a consumer publishes to a built-in browser agent. [Toolset vocabulary](#toolset-vocabulary) lists each tool and the receipts it returns.
1899
1985
 
1900
1986
  A page-backed `click`, `type`, or `press` produces its receipt in six steps, and the toolset keeps no frame, session, or loader state between them.
1901
1987
 
@@ -1916,7 +2002,7 @@ A `click`, a `type` with `submit`, or a `press` of Enter also opens `page.popups
1916
2002
 
1917
2003
  `follow` performs one recorded step on the current view through `perform`. A `click` or `type` step with a target resolves the one element that carries the target's role and exact accessible name and sends its reference as `ref`, and a stored `reference` or `css` is never read; a `switch` step on a toolset with `context` resolves the one tab `tabs()` lists with the step's URL and title and sends the tab's id as `tab`; every other step sends its arguments unchanged, a page tool's included. Before any input, a missing target or tab refuses with `BROWSER_JOURNEY_TARGET`, several refuse with `BROWSER_JOURNEY_AMBIGUOUS`, and a target name that binds a parameter refuses with `BROWSER_JOURNEY_INPUT`, each naming the step. `follow` returns the `BrowserAction` of a `done` action and of an `interrupted` one, whose dialog a following `dialog` step answers, and throws a `BrowserStepError` whose `action` is the performed action for any other outcome and for a navigation that stopped at `requested` or `committed`. Its `caller` option carries a hold's token, and its `secret` option withholds a `type` step's text. A replay and the module `compileBrowserJourney` emits run every step through it.
1918
2004
 
1919
- `perform` runs the handler a manager call runs and returns the `BrowserAction` beside the tool result, and the toolset emits the same action as `action`; `tools.execute` and `perform` share one path, so a receipt is the same through either, including a secret call whose signal was aborted before the handler ran. A failed `perform` also returns the value its handler threw as `fault`, so a copy of the result keeps a coded `BrowserError`, and a tool's own `execute` rejects with that same value. `hold` takes a queue turn for a replay: until the hold is destroyed, an action whose `context.caller` is not the hold's `token` is refused at admission with `BROWSER_TOOLSET_BUSY`, `dialog` and adopted page tools included, while `look`, `read`, `tabs`, and `wait` pass; the toolset emits `hold` and `release` with the journey's name. With the `journeys` option, the toolset constructs a `BrowserJourneyToolset` that adds the six journey tools to the same manager, and destroys it first; see [Journeys](#journeys).
2005
+ `perform` runs the handler a manager call runs and returns the `BrowserAction` beside the tool result, and the toolset emits the same action as `action`; `tools.execute` and `perform` share one path, so a receipt is the same through either, including a secret call whose signal was aborted before the handler ran. A failed `perform` also returns the value its handler threw as `fault`, so a copy of the result keeps a coded `BrowserError`, and a tool's own `execute` rejects with that same value. `hold` takes a queue turn for a replay: until the hold is destroyed, an action whose `context.caller` is not the hold's `token` is refused at admission with `BROWSER_TOOLSET_BUSY`, `dialog` and adopted page tools included, while `look`, `read`, `plain`, `tabs`, and `wait` pass; the toolset emits `hold` and `release` with the journey's name. With the `journeys` option, the toolset constructs a `BrowserJourneyToolset` that adds the journey tools to the same manager, and destroys it first; see [Journeys](#journeys).
1920
2006
 
1921
2007
  | Method | Returns | Summary |
1922
2008
  | --------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -1940,7 +2026,7 @@ The following fence starts a toolset over a page and runs one tool through its m
1940
2026
  const toolset = createBrowserToolset(page, { context, limit: 4_000 }) // context: BrowserContextInterface
1941
2027
  toolset.emitter.on('skip', (name, reason) => log(name, reason)) // 'reserved' | 'held' | 'pattern' | 'schema' | 'debugging'
1942
2028
  await toolset.start()
1943
- const result = await toolset.tools.execute({ id: '1', name: 'look', arguments: { what: 'cart' } })
2029
+ const result = await toolset.tools.execute({ id: '1', name: 'look', arguments: { search: 'cart' } })
1944
2030
  const performed = await toolset.perform({ id: '2', name: 'click', arguments: { ref: 'e4' } })
1945
2031
  performed.action // { action: 'click', target: { role: 'button', name: 'Place order', reference: 'e4', frame }, outcome: 'done', receipt: 'Clicked e4 button "Place order".', … }
1946
2032
  const hold = await toolset.hold('add-kettle') // waits for its queue turn
@@ -2054,7 +2140,7 @@ await codegen.destroy()
2054
2140
 
2055
2141
  #### `BrowserRecorderInterface`
2056
2142
 
2057
- Records the steps of a journey from one source and turns them into a journey. `createBrowserRecorder(toolset)` records the toolset's own actions from its `action`, `hold`, and `release` events: an action whose outcome is `done` becomes its step with the target's role and exact name, and the reference kept as evidence; an `interrupted` action followed by a completed `dialog` becomes both steps, and followed by anything else a gap; a `switch` keeps the tab's URL and title; an action in a child frame becomes the gap `the element is in a child frame`; a secret `type` binds a secret parameter; and the actions between a `hold` and its `release` become one `unresolved` step, `replayed NAME`. `look`, `read`, `tabs`, the journey tools, and a refused action are never steps. `start` drops the steps of an earlier recording.
2143
+ Records the steps of a journey from one source and turns them into a journey. `createBrowserRecorder(toolset)` records the toolset's own actions from its `action`, `hold`, and `release` events: an action whose outcome is `done` becomes its step with the target's role and exact name, and the reference kept as evidence; an `interrupted` action followed by a completed `dialog` becomes both steps, and followed by anything else a gap; a `switch` keeps the tab's URL and title; an action in a child frame becomes the gap `the element is in a child frame`; a secret `type` binds a secret parameter; and the actions between a `hold` and its `release` become one `unresolved` step, `replayed NAME`. `look`, `read`, `plain`, `tabs`, the journey tools, and a refused action are never steps. `start` drops the steps of an earlier recording.
2058
2144
 
2059
2145
  | Method | Returns | Summary |
2060
2146
  | --------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -2156,15 +2242,18 @@ await store.delete('add-kettle')
2156
2242
 
2157
2243
  Keeps runs by the journey name and run id the run carries. A run id is the ISO time with `-` for `:`, followed by `-` and 4 hexadecimal digits, such as `2026-10-01T03-07-06.041Z-6d7e`. `FileBrowserRunStore` creates `ROOT/NAME/runs/ID/` exclusively in `open`, retrying with a fresh id on a collision, writes `run.json` there, and writes a capture only into a directory it opened, refusing a slot it did not open, a name outside `sN.png`, and a directory that is missing or a link; it creates no directory for a capture. `MemoryBrowserRunStore` has no directories: `open` mints an id, and `capture` resolves `undefined`, so a step carries no `capture`.
2158
2244
 
2159
- | Method | Returns | Summary |
2160
- | --------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2161
- | `open` | `Promise<BrowserRunSlot>` | Mints a run id for the journey and creates its run directory exclusively. |
2162
- | `get` | `Promise<BrowserRun \| undefined>` | Returns the run stored under the journey name and id, or `undefined` when none is stored. |
2163
- | `set` | `Promise<void>` | Writes the run under the journey name and the run id it carries. |
2164
- | `capture` | `Promise<string \| undefined>` | Writes capture bytes under the name into the run directory `open` created for the slot. |
2165
- | `delete` | `Promise<void>` | Removes the run stored under the journey name and id; a missing run is a no-op. |
2166
- | `clear` | `Promise<number>` | Removes every run and opened slot of a journey and returns their count, including unsaved slots; a missing name returns zero. File stores exclude concurrent allocation with the journey lock and refuse a held lock with `BROWSER_JOURNEY_LOCKED`. |
2167
- | `list` | `Promise<BrowserStorePage<BrowserRun>>` | Returns one page of the journey's runs, starting at `offset` and holding at most `limit` entries, with the entries it could not read in `faults`. |
2245
+ | Method | Returns | Summary |
2246
+ | ---------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2247
+ | `open` | `Promise<BrowserRunSlot>` | Mints a run id for the journey and creates its run directory exclusively. |
2248
+ | `get` | `Promise<BrowserRun \| undefined>` | Returns the run stored under the journey name and id, or `undefined` when none is stored. |
2249
+ | `set` | `Promise<void>` | Writes the run under the journey name and the run id it carries. |
2250
+ | `capture` | `Promise<string \| undefined>` | Writes capture bytes under the name into the run directory `open` created for the slot. |
2251
+ | `delete` | `Promise<void>` | Removes the run stored under the journey name and id; a missing run is a no-op. |
2252
+ | `clear` | `Promise<number>` | Removes every run and opened slot of a journey and returns their count, including unsaved slots; a missing name returns zero. File stores exclude concurrent allocation with the journey lock and refuse a held lock with `BROWSER_JOURNEY_LOCKED`. |
2253
+ | `list` | `Promise<BrowserStorePage<BrowserRun>>` | Returns one page of the journey's runs, starting at `offset` and holding at most `limit` entries, with the entries it could not read in `faults`. |
2254
+ | `snapshot` | `Promise<string>` | Saves a standalone PNG under the runs root without replacing an existing file. |
2255
+
2256
+ The optional `snapshot` method is implemented by `FileBrowserRunStore`. It allocates `ROOT/runs/ID/view.png` independently of a journey and returns its absolute path. It copies the input bytes before allocation and writes the file exclusively. Stores without standalone file storage omit it.
2168
2257
 
2169
2258
  The following fence opens a run slot, writes a capture and the run, and reads them back.
2170
2259
 
@@ -2180,11 +2269,11 @@ await runs.delete('add-kettle', slot.id)
2180
2269
 
2181
2270
  #### `BrowserJourneyToolsetInterface`
2182
2271
 
2183
- Registers the six journey tools on the toolset's manager and owns the recording and the active replay. `BrowserToolset` constructs it when given `journeys` and destroys it before its own teardown; it refuses construction with `BROWSER_TOOLSET_RESERVED` when the manager already holds a journey tool's name. See [Journeys](#journeys) for the tools.
2272
+ Registers the journey tools on the toolset's manager and owns the recording and the active replay. `BrowserToolset` constructs it when given `journeys` and destroys it before its own teardown; it refuses construction with `BROWSER_TOOLSET_RESERVED` when the manager already holds a journey tool's name. See [Journeys](#journeys) for the tools.
2184
2273
 
2185
- | Method | Returns | Summary |
2186
- | --------- | --------------- | ---------------------------------------------------------------------------- |
2187
- | `destroy` | `Promise<void>` | Aborts the active replay and removes the six journey tools from the manager. |
2274
+ | Method | Returns | Summary |
2275
+ | --------- | --------------- | ------------------------------------------------------------------------ |
2276
+ | `destroy` | `Promise<void>` | Aborts the active replay and removes the journey tools from the manager. |
2188
2277
 
2189
2278
  The following fence constructs the journey toolset through `BrowserToolset`, starts a recording, and destroys both.
2190
2279
 
@@ -2221,6 +2310,7 @@ Browser wrapper with discovery, connection management, and lifecycle control. `c
2221
2310
 
2222
2311
  | Method | Returns | Summary |
2223
2312
  | ------------ | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2313
+ | `ping` | `Promise<void>` | Sends CDP `Browser.getVersion` and resolves when the browser answers, changing no state. |
2224
2314
  | `discover` | `Promise<BrowserDiscoveryResult>` | Probes CDP passively, changing no connection state and neither launching nor attaching, and emits a `discover` event with the result. |
2225
2315
  | `connect` | `Promise<void>` | Establishes a connection through the endpoint, then discovery, then a launch. Idempotent. |
2226
2316
  | `adopt` | `void` | Assumes responsibility for terminating the connected browser. |
@@ -2251,12 +2341,22 @@ await browser.destroy() // terminates and awaits the owned process
2251
2341
 
2252
2342
  #### `BrowserMCPServerInterface`
2253
2343
 
2254
- Serves the 15-name vocabulary over MCP on stdio: `look`, `read`, `click`, `type`, `press`, `navigate`, `wait`, `dialog`, `tabs`, `switch`, `record`, `save`, `journeys`, `edit`, `replay`, and `forget`. `BrowserMCPServer` composes `@orkestrel/mcp`'s `createMCPServer`, `createMCPLegacy`, and `createStdioServer`. Its own manager holds one dispatcher per name with the description and parameters `BROWSER_TOOL_COPY` gives, so `tools/list` answers before Chromium starts and with no Chromium on the host. The first tool call launches Chromium one time, with later callers awaiting that launch and a failed launch retried on the next call, creates the profile `ROOT/.profiles/ID/` exclusively, opens one page in an isolated context, and constructs the page toolset with `context` and `journeys` over the file stores on a second manager the toolset owns, so the toolset's `start()` meets no foreign name. Every dispatcher forwards its call and its signal to the toolset's manager. While no dialog is open, the toolset's manager holds no `dialog`, and a `dialog` call is answered with that manager's `tool not found: dialog`. A page tool the toolset adopts is mirrored as a dispatcher and removed when the page withdraws it, and `@orkestrel/mcp` sends `notifications/tools/list_changed`; with `@orkestrel/mcp` 0.0.34, a client that subscribed through `subscriptions/listen` receives it, and a client of a dated revision that connected through `initialize` receives none and sees the change at its next `tools/list`. On Linux, when the process runs as root, the launch passes `--no-sandbox`, because Chromium refuses to start as root with its sandbox on; every other launch keeps the sandbox. The end of standard input, `SIGTERM`, and `SIGINT` stop admission and destroy the server. A second server in the same root launches its own browser with its own profile, and a server never attaches to another client's browser.
2344
+ Serves the browser vocabulary and the journey tools over MCP on stdio. The server warms its pool at start and holds one validated lease for the shared browser and one for each holder `acquire` admits. Initialization and tool calls await setup; a lost lease is replaced within the pool's restart bound. Each launch creates an exclusive `ROOT/.profiles/PID-UUID/` profile and an isolated context. `tools/list` answers while warming. Adopted page tools are mirrored until withdrawn or their lease is lost.
2345
+
2346
+ A disconnect or a crash of the current page retires its slot; a background-page crash leaves the lease intact. Hand-out, per-call, and post-failure pings detect browsers that stopped answering. An interrupted failure answers `BROWSER_SERVER_UNRESOLVED`, a known success remains successful, and pending loss notes prefix the next string outcome on a successor or a refusal. Every pending loss is reported. Calls are never repeated, and replacement pages start at `about:blank`.
2347
+
2348
+ The end of input, `SIGINT`, and `SIGTERM` stop admission and destroy the pool. Teardown releases watch listeners, destroys each toolset before its browser, and rechecks recorded folders. Unconfirmed termination retains its slot; a stranded launch prevents further launches. A timed-out ping forces termination before teardown. On Linux, a root process launches with `--no-sandbox`; other launches keep the sandbox.
2255
2349
 
2256
- | Method | Returns | Summary |
2257
- | --------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------- |
2258
- | `start` | `Promise<void>` | Serves the tool list over stdio before Chromium starts; the first tool call launches Chromium with a profile the server owns. |
2259
- | `destroy` | `Promise<void>` | Stops admission, aborts the active replay, destroys the toolset and the browser it launched, and removes its profile. |
2350
+ | Method | Returns | Summary |
2351
+ | --------- | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
2352
+ | `start` | `Promise<void>` | Serves stdio, sweeps the profiles ended servers left, warms the pool, and resolves after the shared holder leases a warm browser; the legacy handshake and every tool call await the same setup. Rejects with `BROWSER_SERVER_UNAVAILABLE` when no browser can serve and with `BROWSER_TOOLSET_ENDED` after `destroy()`, and resolves when `destroy()` interrupts setup. |
2353
+ | `destroy` | `Promise<void>` | Stops admission, tears down every browser, its toolset, and its profile, then rechecks the folders it answers for. |
2354
+
2355
+ The viewport option applies to every warmed browser, including spares and refills, and to every page and popup in its isolated context.
2356
+
2357
+ | Option | Type | Default | Behavior |
2358
+ | ---------- | ----------------- | ---------------------------- | -------------------------------------------------------------------------------------------- |
2359
+ | `viewport` | `BrowserViewport` | The browser's launch default | Sets the isolated context's page dimensions and emulation through `BrowserMCPServerOptions`. |
2260
2360
 
2261
2361
  The following fence serves the vocabulary on the process's standard streams, with the journeys under `tmp/browsers`.
2262
2362
 
@@ -2264,8 +2364,8 @@ The following fence serves the vocabulary on the process's standard streams, wit
2264
2364
  import { createBrowserMCPServer } from '@orkestrel/browser/server'
2265
2365
 
2266
2366
  const server = createBrowserMCPServer({ root: 'tmp/browsers', headless: true, readonly: false })
2267
- await server.start() // answers tools/list before Chromium starts
2268
- await server.destroy() // aborts a replay, destroys the browser it launched, and removes its profile
2367
+ await server.start() // resolves after the first warm browser is leased; tools/list answers meanwhile
2368
+ await server.destroy() // aborts a replay, destroys every browser it launched, and removes each profile
2269
2369
  ```
2270
2370
 
2271
2371
  #### `BrowserWebSocketInterface`
@@ -2810,27 +2910,27 @@ await context.emulation.clear()
2810
2910
 
2811
2911
  A view over one DOM document in the realm that runs it. The view follows its window, so a navigation of that window moves it to the window's next document and drops every reference. A reading goes stale on the Navigation API's `navigatesuccess` where the browser ships it, and on `popstate`, `hashchange`, and `pagehide` otherwise. `destroy` releases the listeners, fails pending waits, and makes every later call refuse with `BROWSER_DOCUMENT_DESTROYED`. The view declares neither `emitter` nor `screenshot`, so a replay over it collects no output and takes no capture.
2812
2912
 
2813
- | Method | Returns | Summary |
2814
- | ------------ | ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2815
- | `destroy` | `void` | Releases the navigation listeners and every element reference. |
2816
- | `screenshot` | `Promise<BrowserScreenshotResult>` | Captures PNG or JPEG bytes of the view. |
2817
- | `title` | `Promise<string>` | Resolves the document title. |
2818
- | `read` | `Promise<BrowserReadingInterface>` | Captures the document URL, title, and markup as a reading whose `stale` flag tracks later navigations. |
2819
- | `wait` | `Promise<void>` | Resolves when `text` is visible in the document; rejects with a `BrowserError` coded `BROWSER_WAIT_TIMEOUT` at the deadline, and with `signal.reason` on abort. |
2913
+ | Method | Returns | Summary |
2914
+ | ------------ | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2915
+ | `destroy` | `void` | Releases the navigation listeners and every element reference. |
2916
+ | `screenshot` | `Promise<BrowserScreenshotResult>` | Captures PNG or JPEG bytes of the view. |
2917
+ | `title` | `Promise<string>` | Resolves the document title. |
2918
+ | `read` | `Promise<BrowserReadingInterface>` | Captures the document URL, title, and rendered markup as a reading whose `stale` flag tracks later navigations; `BrowserReadingInput` defines the rendered markup. |
2919
+ | `wait` | `Promise<void>` | Resolves when the main document body’s `innerText` contains `text`, or lacks it with `absent`; rejects with a `BrowserError` coded `BROWSER_WAIT_TIMEOUT` at the deadline, and with `signal.reason` on abort. |
2820
2920
 
2821
2921
  The following fence reads and waits on a child document.
2822
2922
 
2823
2923
  ```ts
2824
2924
  const view = createBrowserDOMView({ document: frame.contentDocument })
2825
2925
  log(await view.title())
2826
- await view.wait('Saved', { timeout: 2_000 }) // a MutationObserver, never a poll
2926
+ await view.wait('Saved', { timeout: 2_000 }) // wakes on mutations, load, transitionend, and animationend
2827
2927
  const reading = await view.read()
2828
2928
  view.destroy()
2829
2929
  ```
2830
2930
 
2831
2931
  #### `BrowserDOMWaitInterface`
2832
2932
 
2833
- One wait parked on DOM mutations across a document, its open shadow roots, and its same-origin frame documents. It checks at once, re-checks after each mutation batch and each `load` in an observed root, and settles at its deadline with `BROWSER_WAIT_TIMEOUT`, on a `pagehide` with `GONE`, or on abort with the signal's reason. `roots` is a Surface data member.
2933
+ One wait parked on mutations and finished transitions and animations across a document, its open shadow roots, and its same-origin frame documents. It checks at once, re-checks after each mutation batch and each `load`, and on the task after a `BROWSER_WAIT_EVENTS` event in an observed root, and settles at its deadline with `BROWSER_WAIT_TIMEOUT`, on a `pagehide` with `GONE`, or on abort with the signal's reason. `roots` is a Surface data member. Text and element waits with `absent` that a navigation interrupts resume against the destination in the CDP placement and settle when the text or element is absent; the DOM placement rejects them with `GONE`. Closing a CDP page rejects pending waits without waiting for their deadlines. Destroying a page releases pending text observers before detaching its session. Concurrent waits share isolated-world creation, and aborting a caller abandons only that caller’s wait. Wake tasks run in hidden tabs, where animation frames pause, but browser timer throttling can delay them. Chromium can also withhold transition and animation finish events there: a CSS-only change with no delivered event or later mutation can still reach the deadline. The hidden-tab cases in `tests/service/document.test.ts` pin that limit, the mutation wake, and a delivered finish-event wake in both placements. The CDP document listener doesn’t observe mutations or non-composed transition and animation events inside shadow roots; the DOM placement listens on each observed root.
2834
2934
 
2835
2935
  | Method | Returns | Summary |
2836
2936
  | --------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
@@ -2855,114 +2955,137 @@ This section holds the words a model reads: the tools a toolset advertises and t
2855
2955
 
2856
2956
  ### Tools
2857
2957
 
2858
- A page-backed toolset advertises `look`, `read`, `click`, `type`, `press`, `navigate`, and `wait`, stages `dialog` while a dialog is open, and advertises `tabs` and `switch` when it is given a `context`; a view-backed toolset over a DOM document advertises `look`, `read`, `click`, `type`, and `wait`. Either toolset advertises `record`, `save`, `journeys`, `edit`, `replay`, and `forget` when it is given `journeys`. Every tool declares at least one required parameter, because the streamed tool-call parser of Ollama 0.34.4 rejects a call to a tool that declares no parameter. The following table lists each tool with its advertised description.
2859
-
2860
- | Tool | Parameters | Annotations | Placements | Description |
2861
- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
2862
- | `look` | `what` (string, required) | `pure`, `untrusted` | CDP and DOM | `Shows the page's text and the elements you can act on, each with a reference like e4. Call it first and after the page changes.` |
2863
- | `read` | `what` (string, required), `offset` (integer, default 0) | `pure`, `untrusted` | CDP and DOM | `Reads the page's text for what you name. Call it to learn a fact; continue with the offset a cut result names.` |
2864
- | `click` | `ref` (string, required) | none | CDP and DOM | `Clicks the element with that reference.` |
2865
- | `type` | `ref` (string, required), `text` (string, required), `submit` (boolean, true to submit its form after typing), `secret` (boolean, true to keep the text out of the receipt) | none | CDP and DOM | `Types into the text control with that reference; set submit to true to submit its form.` |
2866
- | `press` | `key` (string, required) | none | CDP | `Presses that key or chord, such as Enter or Control+a.` |
2867
- | `navigate` | `url` (string, required) | none | CDP | `Opens that absolute web address in the current tab.` |
2868
- | `wait` | `text` (string, required), `timeout` (integer seconds, default 5, at most 30) | `pure` | CDP and DOM | `Waits for that text to appear on the page.` |
2869
- | `dialog` | `accept` (boolean, required), `text` (string) | none | CDP, staged while a dialog opens | `Accepts or dismisses the open dialog.` |
2870
- | `tabs` | `what` (string, required) | `pure` | CDP, with `context` | `Lists the open tabs; the current one is marked.` |
2871
- | `switch` | `tab` (string, required) | none | CDP, with `context` | `Switches to a tab from tabs, such as t2.` |
2872
- | `record` | `journey` (string, required) | none | CDP and DOM, with `journeys` | `Starts recording your next actions as a journey with that name; call save when it is done.` |
2873
- | `save` | `description` (string, required) | none | CDP and DOM, with `journeys` | `Stops recording and saves the journey; describe what it achieves in one sentence.` |
2874
- | `journeys` | `what` (string, required), `offset` (integer, default 0) | `pure`, `untrusted` | CDP and DOM, with `journeys` | `Lists the saved journeys with their steps and the parameters each one takes.` |
2875
- | `edit` | `journey` (string, required), `edits` (`anyOf`: array of `BrowserJourneyEditRequest` or a JSON string of that array, required) | none | CDP and DOM, with `journeys` | `Changes a saved journey: add, remove, or update steps by their ids from journeys, or declare a parameter.` |
2876
- | `replay` | `journey` (string, required), `inputs` (object of strings) | none | CDP and DOM, with `journeys` | `Replays a saved journey step by step; give each parameter's value under inputs.` |
2877
- | `forget` | `journey` (string, required) | none | CDP and DOM, with `journeys` | `Removes a saved journey and all its runs; the name is free to record again.` |
2878
- | page tools | the page's input schema, plus a required `what` string when that schema requires nothing | `untrusted` always; `pure` from `readOnly`; `consequential` from `consequential` | CDP through the registry, DOM through a source | the page's own description, advertised as authored under `untrusted` |
2879
-
2880
- A call to one of the preceding tools that carries a parameter the tool does not advertise is refused before the tool's handler runs, with a `BrowserError` coded `BROWSER_TOOLSET_ARGUMENT` whose message is the receipt: `The look tool takes no ref parameter; call look with what.` `validateBrowserToolArguments` performs that check; a page tool's arguments are the page's to check.
2958
+ A page-backed toolset advertises `look`, `read`, `plain`, `click`, `type`, `press`, `navigate`, and `wait`, stages `dialog` while a dialog is open, and advertises `tabs` and `switch` when it is given a `context`; a view-backed toolset over a DOM document advertises `look`, `read`, `plain`, `click`, `type`, and `wait`. Either toolset advertises `record`, `save`, `journeys`, `edit`, `replay`, `forget`, and `capture` when it is given `journeys`. Every tool declares at least one required parameter, because the streamed tool-call parser of Ollama 0.34.4 rejects a call to a tool that declares no parameter. The following table lists each tool with its advertised description.
2959
+
2960
+ | Tool | Parameters | Annotations | Placements | Description |
2961
+ | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
2962
+ | `look` | `search` (string, required), `offset` (integer, default 0) | `pure`, `untrusted` | CDP and DOM | `Shows the page's text and the elements you can act on, each with a reference like e4. Call it first and after the page changes.` |
2963
+ | `read` | `search` (string, required), `offset` (integer, default 0) | `pure`, `untrusted` | CDP and DOM | `Reads the page as Markdown, with headings, tables, and link addresses. Call it to learn a fact; continue with the offset a cut result names.` |
2964
+ | `plain` | `search` (string, required), `offset` (integer, default 0) | `pure`, `untrusted` | CDP and DOM | `Reads the page as plain text, without Markdown, link addresses, or image text. Call it for words to pass to wait or type.` |
2965
+ | `click` | `ref` (string, required) | none | CDP and DOM | `Clicks the element with that reference.` |
2966
+ | `type` | `ref` (string, required), `text` (string, required), `submit` (boolean, true to submit its form after typing), `secret` (boolean, true to keep the text out of the receipt) | none | CDP and DOM | `Types into the text control with that reference; set submit to true to submit its form.` |
2967
+ | `press` | `key` (string, required) | none | CDP | `Presses that key or chord, such as Enter or Control+a.` |
2968
+ | `navigate` | `url` (string, required) | none | CDP | `Opens that absolute web address in the current tab.` |
2969
+ | `wait` | `text` (string, required), `absent` (boolean, true to wait until the text is gone), `timeout` (integer seconds, default 5, at most 30) | `pure` | CDP and DOM | `Waits for text to appear; set absent to true to wait for it to leave.` |
2970
+ | `dialog` | `accept` (boolean, required), `text` (string) | none | CDP, staged while a dialog opens | `Accepts or dismisses the open dialog.` |
2971
+ | `tabs` | `search` (string, required) | `pure` | CDP, with `context` | `Lists the open tabs; the current one is marked.` |
2972
+ | `switch` | `tab` (string, required) | none | CDP, with `context` | `Switches to a tab from tabs, such as t2.` |
2973
+ | `record` | `journey` (string, required) | none | CDP and DOM, with `journeys` | `Starts recording your next actions as a journey with that name; call save when it is done.` |
2974
+ | `save` | `description` (string, required) | none | CDP and DOM, with `journeys` | `Stops recording and saves the journey; describe what it achieves in one sentence.` |
2975
+ | `journeys` | `search` (string, required), `offset` (integer, default 0) | `pure`, `untrusted` | CDP and DOM, with `journeys` | `Lists the saved journeys with their steps and the parameters each one takes.` |
2976
+ | `edit` | `journey` (string, required), `edits` (`anyOf`: array of `BrowserJourneyEditRequest` or a JSON string of that array, required) | none | CDP and DOM, with `journeys` | `Changes a saved journey: add, remove, or update steps by their ids from journeys, or declare a parameter.` |
2977
+ | `replay` | `journey` (string, required), `inputs` (object of strings) | none | CDP and DOM, with `journeys` | `Replays a saved journey step by step; give each parameter's value under inputs.` |
2978
+ | `capture` | `full` (boolean, required) | none | CDP and DOM, with `journeys`; requires a trusted view | `Saves the current view as a PNG in the runs directory and returns its path.` |
2979
+ | `forget` | `journey` (string, required) | none | CDP and DOM, with `journeys` | `Removes a saved journey and all its runs; the name is free to record again.` |
2980
+ | page tools | the page's input schema, plus a required `purpose` string when that schema requires nothing | `untrusted` always; `pure` from `readOnly`; `consequential` from `consequential` | CDP through the registry, DOM through a source | the page's own description, advertised as authored under `untrusted` |
2981
+
2982
+ A call to one of the preceding tools that carries a parameter the tool does not advertise is refused before the tool's handler runs, with a `BrowserError` coded `BROWSER_TOOLSET_ARGUMENT` whose message is the receipt: `The look tool takes no ref parameter; call look with search and offset.` `validateBrowserToolArguments` performs that check; a page tool's arguments are the page's to check.
2983
+
2984
+ A text `wait` reads the main document body’s `innerText`; child-frame and shadow-root-owned text don’t count. Offscreen `content-visibility: auto` text is absent from this reading while `read` keeps it; `look` can list shadow-root-owned text that never counts here. With `absent: true`, removal, `display: none`, and hidden visibility satisfy the wait. Opacity 0, off-screen positioning, and `aria-hidden` don’t remove text from this reading. In Chromium 154.0.4258.53, a closed `details` body and `hidden="until-found"` text are absent; opening the `details` includes its body. Finished transitions and animations wake both wait engines, including element waits, without a polling timer.
2985
+
2986
+ An absent wait succeeds at its first check if the text was never present. Record an appearance wait before dismissal to prove the text was there. A misspelled string, an outline token such as `expanded=true`, offscreen `content-visibility: auto` text shown by `read`, or shadow-root-owned text shown by `look` can otherwise pass at once without checking the intended exit. A timeout isn’t recorded, and replay and a generated module stop at it.
2987
+
2988
+ The `capture` tool returns only the saved image's absolute path. Set `full` to `true` for the full page or `false` for the viewport. It requires a trusted view with screenshot support and a runs store with `snapshot`; otherwise it refuses with `BROWSER_CAPTURE_UNTRUSTED` or `BROWSER_CAPTURE_UNAVAILABLE`. A held replay refuses it with `BROWSER_TOOLSET_BUSY`. It remains available with read-only journeys, like replay artifacts, and creates no journey or replay record.
2881
2989
 
2882
2990
  ### Receipts
2883
2991
 
2884
- Every action returns a receipt line followed by a blank line and the fresh view, and every result and error message is cut at `limit` characters plus a footer, which closes with `BROWSER_TOOL_VIEW_FOOTER` for a result that carries a view and with `BROWSER_TOOL_CUT_FOOTER` for any other. After a click, a `type` with `submit`, or a `press` that submits a form, the view is the destination's, because the receipt waits for the navigation the submission started, as the steps under [`BrowserToolsetInterface`](#browsertoolsetinterface) describe. When the observer names no surviving destination and no navigation follows, the receipt line states what became of the submission: `BROWSER_TOOL_HANDLED_STATUS`, `the page handled the submission without navigating; call wait for the text you expect`, after a submission a page listener prevented, because the page's outcome can arrive after the receipt, and `no form received the submission` when a `type` with `submit`, or a `press` of Enter that an `input` a form owns received, recorded no submission. The CDP placement's `type` with `submit` ends its action with `and submitted the form` when the observer recorded a submission, or when the navigation the receipt settled names `formSubmissionGet` or `formSubmissionPost` as its `BrowserNavigationReason`, whatever the observer read answered, and with `and pressed Enter` otherwise; the DOM placement calls `requestSubmit()` and ends with `and submitted the form`. A `BrowserElementError` message is one line that carries its reason and, for `GONE` alone, ends with the refresh directive `; call look for fresh refs.`; a refusal that a fresh reference fixes, such as a reference the current view does not hold, names `look` in its own text. A `read` at a nonzero offset continues the reading an earlier `read` of the same view retained, unless a navigation has made that reading stale, which recaptures the view; an edit to the page that is not a navigation leaves the reading current. The slice restarts at 0 after a recapture and at an offset at or past the retained reading's end, and the footer shows the range returned, or is absent when the whole reading fits.
2885
-
2886
- In the following table `URL` is an address, `REF` an element reference, `ROLE` and `NAME` its accessible role and name, `TITLE` a document title, `TEXT` the text a call carried, `KEY` a key or chord, `MESSAGE` a page-authored dialog message, `FRAME` a frame id, `COUNT` and `AVAILABLE` the referenced elements a view lists and those the page holds, `LIMIT` the toolset's `limit`, and `START`, `END`, and `TOTAL` character positions. The journey rows use the journey `add-kettle` as their example name, and `REASON` is a clause that carries no directive and no final period.
2887
-
2888
- | Situation | Text |
2889
- | ----------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2890
- | The view `look` returns, first line | `page "TITLE" URL` |
2891
- | A heading row, an element row, and a text row | `# NAME`, `REF ROLE "NAME"` with `value="…"`, `[checked]`, `[disabled]`, or `[tool=NAME]` after it, and the text itself |
2892
- | The view's last line | `(COUNT of AVAILABLE elements)` |
2893
- | A click | `Clicked e4 button "Place order".` |
2894
- | A click on an element whose role is in `BROWSER_TYPED_ROLES` | `Clicked e35 searchbox "Search products"; call type with e35 to enter text.` |
2895
- | A click in the DOM placement | `Clicked e1 button "Save". (untrusted event)` |
2896
- | Text typed through `type` | `Typed "TEXT" into REF ROLE "NAME".` |
2897
- | `type` with `submit` whose form navigates, followed by the destination's view | `Typed "Grace Hopper" into e3 textbox "Name" and submitted the form.` |
2898
- | An option chosen through `type` | `Selected "Large" in e2 combobox "Size" (programmatic).` |
2899
- | `type` on an element whose role is not in `BROWSER_TYPED_ROLES` | `Element e5 button "Search" takes no text; call click for a button.` |
2900
- | A key pressed through `press` | `Pressed KEY.` |
2901
- | A page opened through `navigate` | `Navigated to URL.` |
2902
- | Text `wait` found, and text it did not find within its timeout | `"TEXT" is on the page.` and `"Order placed" did not appear within 5 s.` |
2903
- | The open tabs `tabs` lists, one line each | `t1 "TITLE" URL (current)` |
2904
- | A tab `switch` moved to, and a tab that is not open | `Switched to t2 URL.` and `Tab "t9" is not open; call tabs.` |
2905
- | A dialog that opened during the action | `Clicked e7 button "Delete". A confirm dialog is open: "MESSAGE"; call dialog.` |
2906
- | A dialog `dialog` handled | `Accepted the confirm dialog "MESSAGE".` or `Dismissed the confirm dialog "MESSAGE".` |
2907
- | A hold requested while an earlier input remains pending and no dialog is open, coded `BROWSER_TOOLSET_DIALOG` | `BROWSER_TOOL_PENDING_NOTE`: `An earlier input is still pending; call look.` |
2908
- | The note before a result when the view moved to a popup, and when its tab closed | `The view moved to a new tab: URL.` and `The tab URL closed; the view returned to URL.` |
2909
- | A settlement that ended `committed`: the navigation committed and has not loaded | `Clicked e3 link "Next"; the page is still loading URL.` |
2910
- | A settlement that ended `requested`: the navigation was requested and not committed | `Clicked e3 link "Next"; it requested URL and the page did not change.` |
2911
- | A submission a page listener prevented, with no navigation after it | `Typed "Ada Lovelace" into e3 textbox "Name" and submitted the form; the page handled the submission without navigating; call wait for the text you expect.` |
2912
- | `type` with `submit` whose Enter no form received | `Typed "Ada Lovelace" into e3 textbox "Name" and pressed Enter; no form received the submission.` |
2913
- | `press` of Enter in an `input` a form owns that no form received | `Pressed Enter; no form received the submission.` |
2914
- | An action whose input document could not be observed, coded `BROWSER_TOOLSET_OBSERVE` | `The action was not sent: frame FRAME, which receives the input, could not be observed for a form submission; call look.` |
2915
- | The note in place of the view when a capture and its one retry both meet a page change | `(The page changed before the view could be read; call look.)` |
2916
- | A reference the page no longer holds | `Element e12 is gone because the page changed; call look for fresh refs.` |
2917
- | A reference the current view does not hold | `Element e99 is not in the current view; call look for fresh refs.` |
2918
- | Any other element refusal | `Element e2 is not editable.` |
2919
- | A parameter the tool does not advertise | `The look tool takes no ref parameter; call look with what.` |
2920
- | A `read` result with more to read | `[characters START–END of TOTAL; call read with offset END for more]` |
2921
- | A result that carries a view, cut at the limit | `[characters 0–END of TOTAL; the rest was cut; call read for the page's text]` |
2922
- | Any other result or error message cut at the limit | `[characters 0–END of TOTAL; the rest was cut]` |
2923
- | A tool called after `destroy()` | `the browser session ended` |
2924
- | Text typed through `type` with `secret` | `Typed a secret into e33 textbox "Password".` |
2925
- | An action from a caller without the hold's token, or `forget`, while a replay holds the toolset, coded `BROWSER_TOOLSET_BUSY` | `The toolset is replaying add-kettle until it finishes; call look.` |
2926
- | `forget` | `Forgot add-kettle and its 2 runs; the name is free to record again.` (`1 run` when singular) |
2927
- | `forget` refused: missing journey | `No journey is named "add-kettle"; call journeys.` |
2928
- | `forget` refused: the name is recording | `Journey "add-kettle" is recording; call save first, or record another name.` |
2929
- | `forget` refused: a held lock | `Journey add-kettle is locked; call forget again.` |
2930
- | `forget` refused: a store failure | `Forgetting add-kettle failed: REASON; call forget again.` |
2931
- | `record`, followed by the view | `Recording add-kettle; each action you take is a step; call save when it is done.` |
2932
- | `record` refused: an invalid name, a saved name, and a recording in progress | `"Add kettle" is not a journey name; use lowercase words joined by hyphens, such as add-kettle.`, `Journey "add-kettle" is saved already; do not call record for it again. Call journeys to list it, edit to change it, or replay to run it, or answer the user.`, and `A journey is recording; call save first.` |
2933
- | `record`, `save`, `edit`, or `forget` under `journeys.readonly` | `The journeys are read-only; call replay.` |
2934
- | `save`, followed by the listing | `Saved add-kettle with 5 steps.` |
2935
- | `save` refused: nothing recording, a failed write, and a held lock | `No journey is recording, so nothing can be saved; answer the user. A journey holds only the actions after record, so call record before them.`, `Saving add-kettle failed: REASON; call save again.`, and `Journey add-kettle is locked; call save again.` |
2936
- | `save` refused after a save in this session | `Nothing is recording; "add-kettle" was saved. Call journeys, edit, or replay.` |
2937
- | `save` refused for an empty recording | `Nothing is recorded for add-kettle: the actions before record are not steps. Perform the flow's actions and call save, or answer the user when the task is done.` |
2938
- | `journeys` with nothing saved | `No journeys are saved; call record to start one.` |
2939
- | A `journeys` listing with more to read | `[characters START–END of TOTAL; call journeys with offset END for more]` |
2940
- | A `journeys` call whose `limit` cannot hold the next character, coded `BROWSER_TOOLSET_LIMIT` | `The journeys limit of LIMIT characters cannot hold the next character at offset START; raise the journeys limit.` |
2941
- | A malformed `edits` or `inputs` argument, coded `BROWSER_TOOLSET_ARGUMENT` | `The edits parameter must be an array or a JSON string of the array.` and `The inputs parameter must be an object of strings.` |
2942
- | An `edits` string that does not parse | `The edits parameter is not valid JSON: REASON; pass an array or a JSON string of the array.`; REASON is the JSON parser's error, such as `Unexpected end of JSON input`. |
2943
- | A negative `journeys` offset, coded `BROWSER_JOURNEY_ARGUMENT` | `The offset parameter must be a non-negative integer.` |
2944
- | `edit`, followed by the listing | `Edited add-kettle.` |
2945
- | `edit` refused: an unknown journey, an invalid edit, a stale revision, a held lock, and a reference the view does not hold | `No journey is named "checkout"; call journeys.`, `Edit 2 is refused: it REASON; call journeys.`, `Journey add-kettle changed since you read it; call journeys, then edit again.`, `Journey add-kettle is locked; call edit again.`, `Editing add-kettle failed: REASON; call edit again.`, and `Element e9 is not in the current view; call look for fresh refs.` |
2946
- | An edit with no object or operation | `Edit 1 is refused: it has no edit object with an "operation" field; call journeys.` and `Edit 1 is refused: it names no operation among add, update, remove, and declare; call journeys.` |
2947
- | An edit with an unknown or non-JSON field | `Edit 1 is refused: its "OPERATION" carries an unknown field "FIELD"; call journeys.` and `Edit 1 is refused: its "OPERATION" has non-JSON content in "FIELD"; call journeys.` |
2948
- | An added step with malformed anchors | `Edit 1 is refused: its "add" carries both "before" and "after"; call journeys.` and `Edit 1 is refused: its "add" has no step id in "FIELD"; call journeys.`, where FIELD is before or after. |
2949
- | An added step with a malformed shape or supplied id | `Edit 1 is refused: its "add" has an invalid "step": REASON; call journeys.` and `Edit 1 is refused: its "add" supplies "step.id", which is assigned automatically; call journeys.` |
2950
- | A removal or update without a step id | `Edit 1 is refused: its "remove" names no step in "id"; call journeys.` and `Edit 1 is refused: its "update" names no step in "id"; call journeys.` |
2951
- | An update with malformed fields | `Edit 1 is refused: its "update" has no object in "arguments"; call journeys.`, `Edit 1 is refused: its "update" has an invalid "target"; call journeys.`, and `Edit 1 is refused: its "update" has an invalid "tab"; call journeys.` |
2952
- | A declaration with malformed fields | `Edit 1 is refused: its "declare" has no "name"; call journeys.`, `Edit 1 is refused: its "declare" has an invalid "name"; call journeys.`, and `Edit 1 is refused: its "declare" has an invalid "parameter": REASON; call journeys.` |
2953
- | An edit batch whose result has no step | `Edit 2 is refused: it removes the last step; call journeys.`; the index names the removal that emptied the journey. |
2954
- | `replay` refused at preparation | `Journey add-kettle needs the input "email"; call replay with inputs.`, `Journey add-kettle has no parameter named "emial"; call journeys.`, `Journey add-kettle has a gap at s4 (REASON); call edit to remove or replace s4.`, `Journey add-kettle cannot run here: s3 switch needs a browser context; call journeys.`, `Journey add-kettle cannot run here: s3 press is not available in a page toolset; call journeys.`, and `Journey add-kettle cannot be read: REASON; call journeys.` |
2955
- | `replay` refused while a journey records, and while another replay holds the toolset | `Journey add-kettle is recording; call save before you replay another.` and `The toolset is replaying add-kettle until it finishes; call look.` |
2956
- | A replay's head line: complete, stopped, and aborted | `Replayed add-kettle: 5 of 5 steps.`, `Replay of add-kettle stopped at s3 of 5: REASON.`, and `Replay of add-kettle aborted at s3 of 5.` |
2957
- | A replayed step's target that several elements carry, and that none carries | `Step s3 names button "Delete", which 2 elements carry; call edit to remove or replace s3.` and `Step s3 names button "Add to cart", which no element carries; call edit to remove or replace s3.` |
2992
+ On `look`, `read`, `plain`, `tabs`, and `journeys`, the required `search` string supplies whole words to match, not a site-search request. Use an empty string to list without matches. Words shorter than 3 letters or digits are ignored. On the first page only, entries sharing the most distinct words come first in a block using at most half the available room. `look` and `tabs` show matching rows; `read` and `plain` show `[OFFSET] LINE`; `journeys` shows `[OFFSET] HEADING` for matching journey headings. The block is outside the paged text, so offsets always address the original projection. An oversized first row is cut with `…` without splitting a surrogate pair, reserving room for the first later row that can fit beside it only when the cut keeps the leading token through its first space. Otherwise it cuts without reserving. Later rows that do not fit are skipped so shorter rows can follow. No matching word or no character before the ellipsis means no block.
2993
+
2994
+ The search parameter descriptions are “Words to find on this page; matching elements come first.” on `look`, “Words to find on this page; the lines that share them come first.” on `read` and `plain`, “Words to find; matching tabs come first.” on `tabs`, and “Words to find; matching journeys come first.” on `journeys`.
2995
+
2996
+ Outline rows append `pressed`, `expanded`, and `selected` only when the state is present, including `false`. The DOM placement reads selection from an explicit ARIA token or native option selectedness; it omits selection on unannotated tabs, treeitems, and ARIA options inside their containers. On Edge 154.0.4258.53, CDP reports `selected=false` for an unannotated tab outside a tablist. That structure is invalid ARIA, and the DOM placement doesn’t emulate its selection default. On the same browser, CDP renders a native `<summary>` as a `DisclosureTriangle` row with `expanded=false` when its details element is closed; the DOM placement omits the summary row. A `treeitem` outside a tree becomes `generic` without these states in CDP; the DOM placement keeps its `treeitem` row with authored expansion and selection. These are declared row-format differences.
2997
+
2998
+ `read` and `plain` project the normalized capture described under `BrowserReadingInterface`, including live field values and selected or displayed option labels. Stylesheet-hidden panels and private controls are absent. `read` returns Markdown with headings, tables, link addresses, and image alternatives; `plain` returns plain text without Markdown, link addresses, or image text. Both keep the whole captured document. Relative links in caller HTML resolve against the reading’s URL, including without distillation.
2999
+
3000
+ Every action returns a receipt line followed by a blank line and the fresh view, and every result and error message is cut at `limit` characters plus a footer, which closes with `BROWSER_TOOL_VIEW_FOOTER` for an action or `dialog` receipt that carries a view and with `BROWSER_TOOL_CUT_FOOTER` for any other. `look` lists every referenced element in pages instead: each call captures the view afresh, a page holds at most `limit` characters of the outline and ends after the last line break in its window that lies past the page's start, or at the window's end when no such break fits, without splitting a surrogate pair; the last page ends at the end of the outline, the footer names the offset of the next page, the offset counts outline characters alone, and an offset at or past the end restarts at 0. When `search` shares a word of at least 3 letters or digits with an element's role or name, the first page opens with the elements that share the most, in at most half of the page, before the outline. After a click, a `type` with `submit`, or a `press` that submits a form, the view is the destination's, because the receipt waits for the navigation the submission started, as the steps under [`BrowserToolsetInterface`](#browsertoolsetinterface) describe. When the observer names no surviving destination and no navigation follows, the receipt line states what became of the submission: `BROWSER_TOOL_HANDLED_STATUS`, `the page handled the submission without navigating; call wait for the text you expect`, after a submission a page listener prevented, because the page's outcome can arrive after the receipt, and `no form received the submission` when a `type` with `submit`, or a `press` of Enter that an `input` a form owns received, recorded no submission. The CDP placement's `type` with `submit` ends its action with `and submitted the form` when the observer recorded a submission, or when the navigation the receipt settled names `formSubmissionGet` or `formSubmissionPost` as its `BrowserNavigationReason`, whatever the observer read answered, and with `and pressed Enter` otherwise; the DOM placement calls `requestSubmit()` and ends with `and submitted the form`. A `BrowserElementError` message is one line that carries its reason and, for `GONE` alone, ends with the refresh directive `; call look for fresh refs.`; a refusal that a fresh reference fixes, such as a reference the current view does not hold, names `look` in its own text. A `read` or `plain` at a nonzero offset continues the retained reading only when the view and projection match, unless a navigation has made that reading stale, which recaptures the view; switching projections also recaptures and restarts at 0. An edit to the page that is not a navigation leaves the reading current. The slice restarts at 0 after a recapture and at an offset at or past the retained reading's end, and the footer shows the range returned, or is absent when the whole reading fits.
3001
+
3002
+ In the following table `URL` is an address, `REF` an element reference, `ROLE` and `NAME` its accessible role and name, `TITLE` a document title, `TEXT` the text a call carried, `KEY` a key or chord, `MESSAGE` a page-authored dialog message, `FRAME` a frame id, `COUNT` the entries counted in a view or match heading, `AVAILABLE` the elements the page holds, `SEARCH` the `search` parameter carried by `look`, `read`, `plain`, `tabs`, or `journeys`, `MATCHED` the entries that match it, `OFFSET` a character position in the original projection, `LINE` a matching line, `HEADING` a journey heading, `LIMIT` the toolset's `limit`, and `START`, `END`, and `TOTAL` character positions. The journey rows use the journey `add-kettle` as their example name, and `REASON` is a clause that carries no directive and no final period.
3003
+
3004
+ | Situation | Text |
3005
+ | ------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3006
+ | The elements whose role and name share the most words with the `search` parameter of a `look` call, before the view on the first page | `MATCHED elements match "SEARCH":` (`1 element matches` for one), the matching element rows, and a blank line |
3007
+ | The matching lines before a `read` or `plain` projection on the first page | `COUNT lines match "SEARCH":` (`1 line matches` for one), `[OFFSET] LINE` rows, and a blank line |
3008
+ | The matching tabs before the tab list | `COUNT tabs match "SEARCH":` (`1 tab matches` for one), matching tab rows, and a blank line |
3009
+ | The matching journey headings before the listing on the first page | `COUNT journeys match "SEARCH":` (`1 journey matches` for one), `[OFFSET] HEADING` rows, and a blank line |
3010
+ | The view `look` returns, first line after any matches | `page "TITLE" URL` |
3011
+ | A heading row, an element row, and a text row | `# NAME`, `REF ROLE "NAME"` with `value="…"`, `pressed=true\|false\|mixed`, `expanded=true\|false`, `selected=true\|false`, `[checked]`, `[disabled]`, or `[tool=NAME]` after it, in that order, and the text itself |
3012
+ | The view's last line | `(COUNT of AVAILABLE elements)` |
3013
+ | A click | `Clicked e4 button "Place order".` |
3014
+ | A click on an element whose role is in `BROWSER_TYPED_ROLES` | `Clicked e35 searchbox "Search products"; call type with e35 to enter text.` |
3015
+ | A click in the DOM placement | `Clicked e1 button "Save". (untrusted event)` |
3016
+ | Text typed through `type` | `Typed "TEXT" into REF ROLE "NAME".` |
3017
+ | `type` with `submit` whose form navigates, followed by the destination's view | `Typed "Grace Hopper" into e3 textbox "Name" and submitted the form.` |
3018
+ | An option chosen through `type` | `Selected "Large" in e2 combobox "Size" (programmatic).` |
3019
+ | `type` on an element whose role is not in `BROWSER_TYPED_ROLES` | `Element e5 button "Search" takes no text; call click for a button.` |
3020
+ | A key pressed through `press` | `Pressed KEY.` |
3021
+ | A key pressed through `press` that leaves focus on a referenced element | `Pressed KEY; focus is on REF ROLE "NAME".` |
3022
+ | A page opened through `navigate` | `Navigated to URL.` |
3023
+ | Text `wait` found, and text it did not find within its timeout; with `absent`, text that is gone, and text that stayed | `"TEXT" is on the page.`, `"Order placed" did not appear within 5 s.`, `"TEXT" is not on the page.`, and `"Saved to drafts" is still on the page after 5 s.` |
3024
+ | The open tabs `tabs` lists, one line each, after any pending move note | `t1 "TITLE" URL (current)` |
3025
+ | A tab `switch` moved to, and a tab that is not open | `Switched to t2 URL.` and `Tab "t9" is not open; call tabs.` |
3026
+ | A dialog that opened during the action | `Clicked e7 button "Delete". A confirm dialog is open: "MESSAGE"; call dialog.` |
3027
+ | A dialog `dialog` handled | `Accepted the confirm dialog "MESSAGE".` or `Dismissed the confirm dialog "MESSAGE".` |
3028
+ | A hold requested while an earlier input remains pending and no dialog is open, coded `BROWSER_TOOLSET_DIALOG` | `BROWSER_TOOL_PENDING_NOTE`: `An earlier input is still pending; call look.` |
3029
+ | The note before a result when the view moved to a popup, and when its tab closed | `The view moved to a new tab: URL.` and `The tab URL closed; the view returned to URL.` |
3030
+ | A settlement that ended `committed`: the navigation committed and has not loaded | `Clicked e3 link "Next"; the page is still loading URL.` |
3031
+ | A settlement that ended `requested`: the navigation was requested and not committed | `Clicked e3 link "Next"; it requested URL and the page did not change.` |
3032
+ | A submission a page listener prevented, with no navigation after it | `Typed "Ada Lovelace" into e3 textbox "Name" and submitted the form; the page handled the submission without navigating; call wait for the text you expect.` |
3033
+ | `type` with `submit` whose Enter no form received | `Typed "Ada Lovelace" into e3 textbox "Name" and pressed Enter; no form received the submission.` |
3034
+ | `press` of Enter in an `input` a form owns that no form received | `Pressed Enter; no form received the submission.` |
3035
+ | An action whose input document could not be observed, coded `BROWSER_TOOLSET_OBSERVE` | `The action was not sent: frame FRAME, which receives the input, could not be observed for a form submission; call look.` |
3036
+ | The note in place of the view when a capture and its one retry both meet a page change | `(The page changed before the view could be read; call look.)` |
3037
+ | A reference the page no longer holds | `Element e12 is gone because the page changed; call look for fresh refs.` |
3038
+ | A reference the current view does not hold | `Element e99 is not in the current view; call look for fresh refs.` |
3039
+ | Any other element refusal | `Element e2 is not editable.` |
3040
+ | A parameter the tool does not advertise | `The look tool takes no ref parameter; call look with search and offset.` |
3041
+ | A `read` or `plain` result with more to read | `[characters START–END of TOTAL; call read with offset END for more]` (or `plain` in place of `read`) |
3042
+ | A `look` result with more to read | `[characters START–END of TOTAL; call look with offset END for more]` |
3043
+ | An action or `dialog` receipt cut at the limit | `[characters 0–END of TOTAL; the rest was cut; call look with words to find]` |
3044
+ | Any other result or error message cut at the limit | `[characters 0–END of TOTAL; the rest was cut]` |
3045
+ | A tool called after `destroy()` | `the browser session ended` |
3046
+ | Text typed through `type` with `secret` | `Typed a secret into e33 textbox "Password".` |
3047
+ | An action from a caller without the hold's token, or `forget`, while a replay holds the toolset, coded `BROWSER_TOOLSET_BUSY` | `The toolset is replaying add-kettle until it finishes; call look.` |
3048
+ | `forget` | `Forgot add-kettle and its 2 runs; the name is free to record again.` (`1 run` when singular) |
3049
+ | `forget` refused: missing journey | `No journey is named "add-kettle"; call journeys.` |
3050
+ | `forget` refused: the name is recording | `Journey "add-kettle" is recording; call save first, or record another name.` |
3051
+ | `forget` refused: a held lock | `Journey add-kettle is locked; call forget again.` |
3052
+ | `forget` refused: a store failure | `Forgetting add-kettle failed: REASON; call forget again.` |
3053
+ | `record`, followed by the view | `Recording add-kettle; each action you take is a step; call save when it is done.` |
3054
+ | `record` refused: an invalid name, a saved name, and a recording in progress | `"Add kettle" is not a journey name; use lowercase words joined by hyphens, such as add-kettle.`, `Journey "add-kettle" is saved already; do not call record for it again. Call journeys to list it, edit to change it, or replay to run it, or answer the user.`, and `A journey is recording; call save first.` |
3055
+ | `record`, `save`, `edit`, or `forget` under `journeys.readonly` | `The journeys are read-only; call replay.` |
3056
+ | `save`, followed by the listing | `Saved add-kettle with 5 steps.` |
3057
+ | `save` refused: nothing recording, a failed write, and a held lock | `No journey is recording, so nothing can be saved; answer the user. A journey holds only the actions after record, so call record before them.`, `Saving add-kettle failed: REASON; call save again.`, and `Journey add-kettle is locked; call save again.` |
3058
+ | `save` refused after a save in this session | `Nothing is recording; "add-kettle" was saved. Call journeys, edit, or replay.` |
3059
+ | `save` refused for an empty recording | `Nothing is recorded for add-kettle: the actions before record are not steps. Perform the flow's actions and call save, or answer the user when the task is done.` |
3060
+ | `journeys` with nothing saved | `No journeys are saved; call record to start one.` |
3061
+ | A `journeys` listing with more to read | `[characters START–END of TOTAL; call journeys with offset END for more]` |
3062
+ | A `look`, `read`, or `plain` call whose `limit` cannot hold the next character, coded `BROWSER_TOOLSET_LIMIT` | `The look limit of LIMIT characters cannot hold the next character at offset START; raise the toolset limit.` (or `read` or `plain` in place of `look`). |
3063
+ | A `journeys` call whose `limit` cannot hold the next character, coded `BROWSER_TOOLSET_LIMIT` | `The journeys limit of LIMIT characters cannot hold the next character at offset START; raise the journeys limit.` |
3064
+ | A malformed `edits` or `inputs` argument, coded `BROWSER_TOOLSET_ARGUMENT` | `The edits parameter must be an array or a JSON string of the array.` and `The inputs parameter must be an object of strings.` |
3065
+ | An `edits` string that does not parse | `The edits parameter is not valid JSON: REASON; pass an array or a JSON string of the array.`; REASON is the JSON parser's error, such as `Unexpected end of JSON input`. |
3066
+ | A negative `journeys` offset, coded `BROWSER_JOURNEY_ARGUMENT` | `The offset parameter must be a non-negative integer.` |
3067
+ | `edit`, followed by the listing | `Edited add-kettle.` |
3068
+ | `edit` refused: an unknown journey, an invalid edit, a stale revision, a held lock, and a reference the view does not hold | `No journey is named "checkout"; call journeys.`, `Edit 2 is refused: it REASON; call journeys.`, `Journey add-kettle changed since you read it; call journeys, then edit again.`, `Journey add-kettle is locked; call edit again.`, `Editing add-kettle failed: REASON; call edit again.`, and `Element e9 is not in the current view; call look for fresh refs.` |
3069
+ | An edit with no object or operation | `Edit 1 is refused: it has no edit object with an "operation" field; call journeys.` and `Edit 1 is refused: it names no operation among add, update, remove, and declare; call journeys.` |
3070
+ | An edit with an unknown or non-JSON field | `Edit 1 is refused: its "OPERATION" carries an unknown field "FIELD"; call journeys.` and `Edit 1 is refused: its "OPERATION" has non-JSON content in "FIELD"; call journeys.` |
3071
+ | An added step with malformed anchors | `Edit 1 is refused: its "add" carries both "before" and "after"; call journeys.` and `Edit 1 is refused: its "add" has no step id in "FIELD"; call journeys.`, where FIELD is before or after. |
3072
+ | An added step with a malformed shape or supplied id | `Edit 1 is refused: its "add" has an invalid "step": REASON; call journeys.` and `Edit 1 is refused: its "add" supplies "step.id", which is assigned automatically; call journeys.` |
3073
+ | A removal or update without a step id | `Edit 1 is refused: its "remove" names no step in "id"; call journeys.` and `Edit 1 is refused: its "update" names no step in "id"; call journeys.` |
3074
+ | An update with malformed fields | `Edit 1 is refused: its "update" has no object in "arguments"; call journeys.`, `Edit 1 is refused: its "update" has an invalid "target"; call journeys.`, and `Edit 1 is refused: its "update" has an invalid "tab"; call journeys.` |
3075
+ | A declaration with malformed fields | `Edit 1 is refused: its "declare" has no "name"; call journeys.`, `Edit 1 is refused: its "declare" has an invalid "name"; call journeys.`, and `Edit 1 is refused: its "declare" has an invalid "parameter": REASON; call journeys.` |
3076
+ | An edit batch whose result has no step | `Edit 2 is refused: it removes the last step; call journeys.`; the index names the removal that emptied the journey. |
3077
+ | `replay` refused at preparation | `Journey add-kettle needs the input "email"; call replay with inputs.`, `Journey add-kettle has no parameter named "emial"; call journeys.`, `Journey add-kettle has a gap at s4 (REASON); call edit to remove or replace s4.`, `Journey add-kettle cannot run here: s3 switch needs a browser context; call journeys.`, `Journey add-kettle cannot run here: s3 press is not available in a page toolset; call journeys.`, and `Journey add-kettle cannot be read: REASON; call journeys.` |
3078
+ | `replay` refused while a journey records, and while another replay holds the toolset | `Journey add-kettle is recording; call save before you replay another.` and `The toolset is replaying add-kettle until it finishes; call look.` |
3079
+ | A replay's head line: complete, stopped, and aborted | `Replayed add-kettle: 5 of 5 steps.`, `Replay of add-kettle stopped at s3 of 5: REASON.`, and `Replay of add-kettle aborted at s3 of 5.` |
3080
+ | A replayed step's target that several elements carry, and that none carries | `Step s3 names button "Delete", which 2 elements carry; call edit to remove or replace s3.` and `Step s3 names button "Add to cart", which no element carries; call edit to remove or replace s3.` |
2958
3081
 
2959
3082
  ## Journeys
2960
3083
 
2961
- The store proof measured the journey tools and `type`'s `secret` at 798 prompt tokens per turn on the store model's tokenizer (`qwen3.5:2b-q4_K_M`), and the full tool list at 1 651, on 2026-10-01 against the tree at `4a10abe`; the measurement moves with the tool copy. A 4 096-token window cut a page task's third turn, while a 16 384-token window held the proof's journey conversation. When a replay's final view must show a delayed confirmation, end the recording with a `wait` for that confirmation.
3084
+ The store proof measured the journey tools and `type`'s `secret` at 798 prompt tokens per turn on the store model's tokenizer (`qwen3.5:2b-q4_K_M`), and the full tool list at 1 651, on 2026-10-01 against the tree at `4a10abe`; the measurement moves with the tool copy. A 4 096-token window cut a page task's third turn, while a 16 384-token window held the proof's journey conversation. When a replay's final view must show a delayed confirmation, end the recording with a `wait` for that confirmation. When a step dismisses a message or closes a panel, follow it with a `wait` with `absent` set to `true` for its text, so the journey keeps the exit check.
2962
3085
 
2963
- A vocabulary case in [`tests/src/core/BrowserToolset.test.ts`](../tests/src/core/BrowserToolset.test.ts) bounds the copy a model reads, each tool's compact JSON name, description, and input schema, at 3 100 characters for the journey tools plus `type`'s `secret` property and at 5 900 for the full list. The character bound fails the suite when the copy grows, with no tokenizer installed; it is not a token count.
3086
+ A vocabulary case in [`tests/src/core/BrowserToolset.test.ts`](../tests/src/core/BrowserToolset.test.ts) bounds the copy a model reads, each tool's compact JSON name, description, and input schema, at 3 400 characters for the journey tools plus `type`'s `secret` property and at 7 000 for the full list. With `capture`, the measured full copy is 6 952 characters; 7 000 is the smallest multiple of 50 that holds it. The journey copy measures 3 367, giving the same bound rule 3 400. The character bound fails the suite when the copy grows, with no tokenizer installed; it is not a token count.
2964
3087
 
2965
- A journey is one user intent kept as JSON: a `name`, a one-sentence `description`, the `parameters` it takes, the `next` step number, and `steps` that mirror the toolset's own tool calls. An acting step names its element by role and exact accessible name, the way a receipt names it, and keeps the record-time `reference` and a `css` selector only as evidence a developer reads when a resolution is refused; replay never reads either. A `switch` step names its tab by URL and title. A model records, lists, edits, replays, and forgets journeys through the six journey tools; a developer compiles the same steps into a module. `validateBrowserJourney` asserts these invariants, and [`tests/src/core/validators.test.ts`](../tests/src/core/validators.test.ts) gives each one a failing case:
3088
+ A journey is one user intent kept as JSON: a `name`, a one-sentence `description`, the `parameters` it takes, the `next` step number, and `steps` that mirror the toolset's own tool calls. An acting step names its element by role and exact accessible name, the way a receipt names it, and keeps the record-time `reference` and a `css` selector only as evidence a developer reads when a resolution is refused; replay never reads either. A `switch` step names its tab by URL and title. A model records, lists, edits, replays, and forgets journeys through the journey tools; a developer compiles the same steps into a module. `validateBrowserJourney` asserts these invariants, and [`tests/src/core/validators.test.ts`](../tests/src/core/validators.test.ts) gives each one a failing case:
2966
3089
 
2967
3090
  1. `name` matches `BROWSER_JOURNEY_NAME_PATTERN`: lowercase words joined by hyphens, at most 64 characters, and none of the reserved device names `con`, `prn`, `aux`, `nul`, `com1` to `com9`, and `lpt1` to `lpt9`.
2968
3091
  2. A journey has at least one step. Step ids are unique, each is `s` followed by a number below `next`, and an added step takes `next` and increments it, so a removed id is never reused.
@@ -2970,7 +3093,7 @@ A journey is one user intent kept as JSON: a `name`, a one-sentence `description
2970
3093
  4. Every binding names a declared parameter, and every declared parameter is bound by at least one step.
2971
3094
  5. A secret parameter binds `type.text` only and has no default.
2972
3095
  6. A journey survives `JSON.stringify` and `parseBrowserJourney` unchanged.
2973
- 7. A step's action is `click`, `type`, `press`, `navigate`, `wait`, `dialog`, `switch`, an adopted page tool, or `unresolved`; `look`, `read`, `tabs`, and the six journey tools are never steps.
3096
+ 7. A step's action is `click`, `type`, `press`, `navigate`, `wait`, `dialog`, `switch`, an adopted page tool, or `unresolved`; `look`, `read`, `plain`, `tabs`, and the journey tools are never steps.
2974
3097
 
2975
3098
  ### Record a journey
2976
3099
 
@@ -2990,7 +3113,7 @@ A parameter is text whose name matches `BROWSER_JOURNEY_PARAMETER_PATTERN`. A na
2990
3113
 
2991
3114
  `BrowserJourneyOptions.limit` defaults to the owner’s `limit`, including when you construct `BrowserJourneyToolset` directly. `BrowserStoreFault` carries the entry’s `name` and a path-free `reason`; `renderBrowserJourneyFault` renders those fields as `NAME cannot be read: REASON`. The `journeys` tool deduplicates faults by name.
2992
3115
 
2993
- `renderBrowserJourney` lists a journey the way `save`, `journeys`, and `edit` return it: the head line with the parameters, one line per step, a binding as `as NAME`, a secret as `(secret)` in place of its text, and never a reference. The following fence shows the listing of `add-kettle`.
3116
+ `renderBrowserJourney` lists a journey the way `save`, `journeys`, and `edit` return it: the head line with the parameters, one line per step, a binding as `as NAME`, a secret as `(secret)` in place of its text, a `wait` with `absent` as `, absent` after its text and binding, and never a reference. The following fence shows the listing of `add-kettle`.
2994
3117
 
2995
3118
  ```ts
2996
3119
  renderBrowserJourney(journey)
@@ -3038,14 +3161,14 @@ The same steps reach two artifacts, and each one is usable without the other. Th
3038
3161
 
3039
3162
  A file store keeps its entries under a root that exists before the store is constructed; the constructor resolves it through `realpath` and throws `BROWSER_JOURNEY_PATH` naming the root when it is missing. Every path the store touches lies under the root, and a symbolic link at any component refuses with `BROWSER_JOURNEY_PATH`; the stores guard against a link present when they check a path, not one a writer with access to the root swaps in between the check and the use. The `browse` binary uses the root `tmp/browsers` under its working directory and creates it. The following table lists what the root holds.
3040
3163
 
3041
- | Path | Holds |
3042
- | ---------------------------- | -------------------------------------------------------------------------------------------------- |
3043
- | `ROOT/.profiles/ID/` | the browser profile one `browse` server owns, created exclusively and removed when the server ends |
3044
- | `ROOT/NAME/journey.json` | the journey and the revision the store assigned it |
3045
- | `ROOT/NAME/revision` | the revision counter, kept across `delete` and recreate |
3046
- | `ROOT/NAME/journey.lock/` | the write lock directory; its empty `PID-TOKEN` entry identifies the holder |
3047
- | `ROOT/NAME/runs/ID/run.json` | one run, under the run id the store minted in `open` |
3048
- | `ROOT/NAME/runs/ID/sN.png` | the capture of step `sN` in the page placement |
3164
+ | Path | Holds |
3165
+ | ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
3166
+ | `ROOT/.profiles/<pid>-<uuid>/` | browser profiles created exclusively for eager pool slots; slot teardown removes them, the startup sweep handles exited owners, and the shutdown recheck retries recorded folders while retaining live, unreadable, or malformed records and reporting persistent removal failures |
3167
+ | `ROOT/NAME/journey.json` | the journey and the revision the store assigned it |
3168
+ | `ROOT/NAME/revision` | the revision counter, kept across `delete` and recreate |
3169
+ | `ROOT/NAME/journey.lock/` | the write lock directory; its empty `PID-TOKEN` entry identifies the holder |
3170
+ | `ROOT/NAME/runs/ID/run.json` | one run, under the run id the store minted in `open` |
3171
+ | `ROOT/NAME/runs/ID/sN.png` | the capture of step `sN` in the page placement |
3049
3172
 
3050
3173
  ### Placements
3051
3174
 
@@ -3053,14 +3176,14 @@ The page placement, a toolset over a `BrowserPageInterface`, records and replays
3053
3176
 
3054
3177
  ## Relation to WebMCP
3055
3178
 
3056
- WebMCP puts a tool registry on the document, `document.modelContext`, so a page can offer its own capabilities to an agent. This package does not depend on it: the toolset drives any page through its own vocabulary, and `look`, `read`, `click`, `type`, `press`, `navigate`, `wait`, and `dialog` run against a browser that ships no registry. The Chromium project's intent to experiment, posted to blink-dev on 2026-05-15, names Chrome 157 as the milestone that would ship WebMCP; see [the WebMCP intent to experiment on blink-dev](https://groups.google.com/a/chromium.org/g/blink-dev/c/gmYffo5WOE8/m/OJxuQRP3AAAJ). The package adapts to WebMCP in both directions and pins that alignment against revision-named mirrors, which [Declared conformance gaps](#declared-conformance-gaps) records. No export is named after WebMCP; an adapter is named in prose.
3179
+ WebMCP puts a tool registry on the document, `document.modelContext`, so a page can offer its own capabilities to an agent. This package does not depend on it: the toolset drives any page through its own vocabulary, and `look`, `read`, `plain`, `click`, `type`, `press`, `navigate`, `wait`, and `dialog` run against a browser that ships no registry. The Chromium project's intent to experiment, posted to blink-dev on 2026-05-15, names Chrome 157 as the milestone that would ship WebMCP; see [the WebMCP intent to experiment on blink-dev](https://groups.google.com/a/chromium.org/g/blink-dev/c/gmYffo5WOE8/m/OJxuQRP3AAAJ). The package adapts to WebMCP in both directions and pins that alignment against revision-named mirrors, which [Declared conformance gaps](#declared-conformance-gaps) records. No export is named after WebMCP; an adapter is named in prose.
3057
3180
 
3058
3181
  The following table names each adapter, the contract on each side, and the proof that pins it.
3059
3182
 
3060
3183
  | Adapter | This package | WebMCP or `@orkestrel/mcp` | Proof |
3061
3184
  | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
3062
3185
  | The tool source contract | `BrowserToolSourceInterface`: an `emitter` emitting `change`, `adopt()`, and an optional `tools()` census, which `createDocumentToolset` takes as `source` | `@orkestrel/mcp`'s `ModelContextInterface`, returned by `createModelContext`, whose `emitter` and `adopt()` satisfy the contract structurally and which carries no census | [the type test](../tests/src/browser/types.test.ts) assigns the model context to the contract and refuses a shape without `adopt`; [the composition cases](../tests/src/browser/factories.test.ts) run the installed bridge over this package's double |
3063
- | The registry twin's annotation mapping | `BrowserRegistry.adopt()` projects a `BrowserToolAnnotation` onto `@orkestrel/tool`'s annotations: `readOnly` to `pure`, `consequential` to `consequential`, `untrusted` always `true`; a `debugging` tool is skipped by the toolset, and `autosubmit` is retained on the protocol tool alone | the domain's `Annotation` type carries `readOnly`, `untrustedContent`, `consequential`, `debugging`, and `autosubmit`; the specification source's `ToolAnnotations` carries `readOnlyHint`, `untrustedContentHint`, `consequentialHint`, and `debugging` | [the mapping rows](../tests/conformance.test.ts) drive the real `adopt()` over mirror-shaped tools, and [the registry proof](../tests/src/core/BrowserRegistry.test.ts) pins the untrusted mark and the synthetic `what` |
3186
+ | The registry twin's annotation mapping | `BrowserRegistry.adopt()` projects a `BrowserToolAnnotation` onto `@orkestrel/tool`'s annotations: `readOnly` to `pure`, `consequential` to `consequential`, `untrusted` always `true`; a `debugging` tool is skipped by the toolset, and `autosubmit` is retained on the protocol tool alone | the domain's `Annotation` type carries `readOnly`, `untrustedContent`, `consequential`, `debugging`, and `autosubmit`; the specification source's `ToolAnnotations` carries `readOnlyHint`, `untrustedContentHint`, `consequentialHint`, and `debugging` | [the mapping rows](../tests/conformance.test.ts) drive the real `adopt()` over mirror-shaped tools, and [the registry proof](../tests/src/core/BrowserRegistry.test.ts) pins the untrusted mark and the synthetic `purpose` |
3064
3187
  | The domain mirror the registry parses | `parseBrowserTool`, `parseBrowserRemoval`, `parseBrowserInvocation`, and `parseBrowserInvocationResult`; the registry sends `enable`, `disable`, `invokeTool`, and `cancelInvocation` and subscribes `toolsAdded`, `toolsRemoved`, `toolInvoked`, and `toolResponded` | the `WebMCP` domain of `browser_protocol.json`: the `Tool`, `Annotation`, and `RemovedTool` types, the `InvocationStatus` values `Completed`, `Canceled`, and `Error`, the four commands, and the four events | [the conformance project](../tests/conformance.test.ts) compares every property the parsers read against [the domain mirror](../tests/mirrors/webmcp-domain-dc2ddf369035.json), and every command and event name the registry uses |
3065
3188
  | The declarative form | the element managers mark a form that a registered tool's `backendNodeId` names (CDP), or that carries a `toolname` attribute (DOM), as `[tool=NAME]` after its role and name | the declarative attributes of Chrome's explainer; the specification's declarative section is a TODO at revision `19fc56516057` | [the CDP mark](../tests/conformance.test.ts) and [the DOM mark](../tests/src/browser/factories.test.ts) each render `e5 form "Search cars" [tool=search-cars]` |
3066
3189
 
@@ -3106,15 +3229,15 @@ These invariants hold across the four faces (`src/core`, `src/browser`, `src/ser
3106
3229
  2. **Core is environment-agnostic.** `src/core` imports only `@orkestrel/contract`, `@orkestrel/emitter`, `@orkestrel/html`, `@orkestrel/markdown`, and `@orkestrel/tool`: no `node:*`, no `WebSocket`, no DOM, and no filesystem. `@orkestrel/html` and `@orkestrel/markdown` are string-to-tree-to-string work with no host of their own, and `@orkestrel/tool` supplies the `ToolInterface` and `ToolManagerInterface` values the toolset fills, never re-exported. Every CDP method call and event flows through the injected `CDPTransportInterface`. Host-side CDP boundaries use `@orkestrel/contract` guards; raw `typeof` and `instanceof` checks appear only inside compiled expressions that run in the remote page. The `browser → html` edge is one-way, and `BrowserSnapshot` navigates CDP DOM snapshots rather than HTML source, so it never gains rendering, extraction, or distillation. `src/browser` imports the core, `@orkestrel/contract`, and `@orkestrel/emitter`; `src/server` imports the core, `@orkestrel/contract`, `@orkestrel/emitter`, `@orkestrel/websocket`, `@orkestrel/tool`, `@orkestrel/mcp` for `BrowserMCPServer`, which makes `@orkestrel/mcp` a runtime dependency, and `node:*`, and its file stores import `@orkestrel/contract` and `node:*` alone; `src/bin` imports the core, the server, and `@orkestrel/contract`; the in-page face and the Node runtime never import each other. The scoped `check:src:core`, `check:src:browser`, `check:src:server`, and `check:src:bin` projects and [`tests/config.test.ts`](../tests/config.test.ts) pin the boundaries.
3107
3230
  3. **The transport is a dumb text pipe.** `CDPTransportInterface` does no JSON framing of its own; `CDPClient` owns request and response correlation, timeouts, abort signals, and event dispatch over the transport's raw `message`, `close`, and `error` events. [`tests/src/core/CDPClient.test.ts`](../tests/src/core/CDPClient.test.ts) pins it.
3108
3231
  4. **Captured bytes never touch a filesystem in core.** A page accepts an optional `BrowserWriterInterface`, injected through `BrowserContext`, and calls `write(path, bytes)` only when a screenshot, PDF, trace, or HAR request carries a `path`; the server supplies `createBrowserWriter` through `Browser`. A replay takes each capture's bytes from the view without a `path` and hands them to its run store's `capture`, which writes them only into the run directory its `open` created and creates no directory; the memory run store keeps no bytes. [`tests/src/server/writers/FileBrowserWriter.test.ts`](../tests/src/server/writers/FileBrowserWriter.test.ts) pins the writer, the capture cases of [`tests/src/core/BrowserReplay.test.ts`](../tests/src/core/BrowserReplay.test.ts) pin that no path reaches the page, and [`tests/src/server/stores/FileBrowserRunStore.test.ts`](../tests/src/server/stores/FileBrowserRunStore.test.ts) pins the capture's confinement.
3109
- 5. **The server owns the connection lifecycle, and launch readiness is an event.** `Browser.connect()` tries, in order: an explicit `cdp.endpoint`; a passive probe of `{cdp.host}:{cdp.port}` through `discover()`; then a launch. A launch spawns the executable with `--remote-debugging-port` set to `cdp.port`, or to `0` so the operating system picks the port when none is given, with standard error piped, and `readBrowserEndpoint` resolves the `ws://` endpoint from the `DevTools listening on` line the browser prints there, reading across chunk boundaries and draining the stream afterwards. No HTTP request polls for readiness. A found browser is preferred over a launch; `engine` narrows discovery to a preferred engine, and a `BrowserConnectionError` carries the requested `engine` when none matches. `disconnect()` retains process ownership, and `discover: false` probes the port directly and rejects with a coded `BrowserConnectionError` naming an occupied port. [`tests/src/server/Browser.test.ts`](../tests/src/server/Browser.test.ts) resolves a launch with no `GET /json/version` recorded, and [`tests/src/server/helpers.test.ts`](../tests/src/server/helpers.test.ts) pins the endpoint read.
3232
+ 5. **The server owns the connection lifecycle, and launch readiness is an event.** `Browser.connect()` tries, in order: an explicit `cdp.endpoint`; a passive probe of `{cdp.host}:{cdp.port}` through `discover()`; then a launch. A launch spawns the executable with `--remote-debugging-port` set to `cdp.port`, or to `0` so the operating system picks the port when none is given, with standard error piped, and `readBrowserEndpoint` resolves the `ws://` endpoint from the `DevTools listening on` line the browser prints there, reading across chunk boundaries and draining the stream afterwards. No HTTP request polls for readiness. A found browser is preferred over a launch; `engine` narrows discovery to a preferred engine, and a `BrowserConnectionError` carries the requested `engine` when none matches. `disconnect()` retains process ownership, and `discover: false` probes the port directly only when `cdp.port` is set and rejects with a coded `BrowserConnectionError` naming an occupied port. [`tests/src/server/Browser.test.ts`](../tests/src/server/Browser.test.ts) resolves a launch with no `GET /json/version` recorded, and [`tests/src/server/helpers.test.ts`](../tests/src/server/helpers.test.ts) pins the endpoint read.
3110
3233
  6. **Lifecycle events are observable, never polled.** `BrowserInterface.emitter` fires `idle`, `discover`, `connect`, `disconnect`, `launch`, `page`, `context`, `error`, and `destroy`; `CDPClientInterface.emitter` fires `connect`, `close`, `drop`, and `error`; a recorder, `page.codegen()` included, fires `start`, `step`, `stop`, and `clear`, and a replay fires `step`. A page fires `navigate` with `[url, same]` for both a cross-document and a same-document navigation, `session` when an out-of-process frame's session attaches, `popup` for each page it opens, and `dialog`, `close`, and the network and worker events; a context fires `page` for each page it publishes, popups included. A page a context constructs holds its target on the client's connection, and the first such page on a connection enables `Target.setDiscoverTargets` for it; a second live page for a held target is refused with `BROWSER_TARGET_HELD`, and a `create()` that meets a page another path published for its target joins that page, or rejects with `BROWSER_PAGE_CLOSED` when that page closed. A page constructed directly holds no target, enables no discovery, and counts as published when its setup completes. A discovered popup is published one time, after its opener, through the opener's `popup`, the context's `page`, and `pages()`. Limit: when the page holding a popup's target fails its setup, discovery publishes nothing, and a later `sync()` adds the target without a `popup` from its opener. Limit: when `Target.setDiscoverTargets` fails, or the connection ends and another opens, the next page a context constructs on that connection sends it again, and nothing sends it before then; `sync()` is the recovery for a popup that discovery missed meanwhile. The registry fires `change`, `invoke`, and `respond`, and the toolset `adopt`, `skip`, `select`, `action`, `hold`, and `release`. A journey store never polls: a held `journey.lock` refuses at once with `BROWSER_JOURNEY_LOCKED`, and the tool tells the model to call again. Every wait parks on a protocol event, a DOM observer, or an abort signal, and a `setTimeout` survives only as a deadline; the one liveness probe with no event source is the bounded drain of a terminated process group, at `BROWSER_DRAIN_INTERVAL_MS` in `src/server`. An external disconnect emits a coded `error` before `disconnect`; transport loss with the process alive is resumable, and a process exit is terminal. [`tests/src/core/BrowserPage.test.ts`](../tests/src/core/BrowserPage.test.ts), [`tests/src/core/recorders/BrowserCodegen.test.ts`](../tests/src/core/recorders/BrowserCodegen.test.ts), [`tests/src/core/recorders/BrowserRecorder.test.ts`](../tests/src/core/recorders/BrowserRecorder.test.ts), and [`tests/src/core/BrowserToolset.test.ts`](../tests/src/core/BrowserToolset.test.ts) pin the page, recorder, and toolset events, [`tests/src/server/stores/FileBrowserJourneyStore.test.ts`](../tests/src/server/stores/FileBrowserJourneyStore.test.ts) pins the lock refused at once, and [`tests/src/core/BrowserContext.test.ts`](../tests/src/core/BrowserContext.test.ts) pins target ownership, the joined creation, and popup publication.
3111
3234
  7. **Errors carry a machine-readable `code` and an optional `context`.** `BrowserError` is the base; `CDPError`, `CDPConnectionError`, `CDPTimeoutError`, `BrowserResultLimitError`, `BrowserConnectionError`, `BrowserElementError`, and `BrowserStepError` (core) narrow protocol, connectivity, timeout, oversized-result, connection, element, and journey step faults; `BrowserNotConnectedError` and `BrowserDestroyedError` (server) narrow the lifecycle. `BrowserConnectionError` lives in the core because the in-page `SocketCDPTransport` throws it too. A `BrowserElementError` carries `context.reason`, one of `GONE`, `HIDDEN`, `OCCLUDED`, `DISABLED`, `UNTRUSTED`, and `UNKNOWN`, and a one-line message that ends `; call look for fresh refs.` for `GONE` alone. A `BrowserStepError` carries the performed `BrowserAction` in `action`, and a replay records a step that did not complete from it. Each class ships an `is*` guard, and the code table under [Errors](#errors) names every code that reaches a caller, the `BROWSER_JOURNEY_*` codes, `BROWSER_TOOLSET_BUSY`, and `BROWSER_SERVER_ENVIRONMENT` included. [`tests/src/core/errors.test.ts`](../tests/src/core/errors.test.ts) and [`tests/src/server/errors.test.ts`](../tests/src/server/errors.test.ts) pin the guards; [`tests/src/core/validators.test.ts`](../tests/src/core/validators.test.ts), [`tests/src/core/BrowserReplay.test.ts`](../tests/src/core/BrowserReplay.test.ts), [`tests/src/core/BrowserJourneyToolset.test.ts`](../tests/src/core/BrowserJourneyToolset.test.ts), the store suites, and [`tests/src/bin/main.test.ts`](../tests/src/bin/main.test.ts) pin the journey, busy, and environment codes.
3112
3235
  8. **Oversized results fail clean.** `evaluate()` and `read()` wrap their in-page result with `compileGuardedEvaluateExpression(expression, BROWSER_RESULT_LIMIT)`, which throws the `BROWSER_RESULT_LIMIT_SENTINEL_PREFIX` sentinel before an oversized result could overflow the transport frame; the frame recognizes it through `BROWSER_RESULT_LIMIT_PATTERN` and rejects with a coded `BrowserResultLimitError`, and the connection and the browser process are unaffected. [`tests/service/browser.test.ts`](../tests/service/browser.test.ts) pins both against a real browser.
3113
3236
  9. **The page recorder records semantic steps, and a journey compiles to a module that runs as a replay does.** `page.codegen()` records each gesture by role and exact accessible name, collapses consecutive edits on one field while the edit is open, and never across a submission, a focus departure, a navigation, or `stop`. `compileBrowserJourney` emits one `follow` call per step on a toolset the module constructs, as `'javascript'` or `'typescript'`, and throws at a gap step. [`tests/src/core/recorders/BrowserCodegen.test.ts`](../tests/src/core/recorders/BrowserCodegen.test.ts) pins the recorder, [`tests/service/codegen.test.ts`](../tests/service/codegen.test.ts) pins its gestures on Chromium against the fixture's own event log, [`tests/src/core/compilers.test.ts`](../tests/src/core/compilers.test.ts) pins the module byte for byte, and the `compiled module equality` block of [`tests/service/journey.test.ts`](../tests/service/journey.test.ts) runs each generated module and its replay to one page outcome with the same receipts.
3114
3237
  10. **Doc ↔ source method bijection.** Each `## Methods` table lists exactly the call-signature members of its interface, inherited members included, and each implementing class named for its interface exposes no public method its table omits: `BrowserCodegen`, `BrowserRecorder`, `BrowserReplay`, `BrowserHold`, `BrowserJourneyToolset`, `BrowserMCPServer`, the two memory stores, and the two file stores pair with their interfaces as every earlier class does. Every other export is a function or a data bag. [`tests/guides.test.ts`](../tests/guides.test.ts) pins it.
3115
3238
  11. **The WebSocket transports are thin bridges.** `WebSocketCDPTransport` (server) and `SocketCDPTransport` (in-page) connect a `WebSocket` to the CDP debugger URL, race the opening against `timeout` (default `BROWSER_DEFAULT_TIMEOUT_MS`), and bridge the socket's `message`, `close`, and `error` events onto their emitter unchanged. `start()` rejects with a `BrowserConnectionError` carrying the URL on a socket error, a non-open close, or the timeout, and `send` before `start` throws the same coded error. A browser launched without `--remote-allow-origins` naming the caller's origin refuses the in-page handshake. [`tests/src/server/transports/WebSocketCDPTransport.test.ts`](../tests/src/server/transports/WebSocketCDPTransport.test.ts) and [`tests/src/browser/transports/SocketCDPTransport.test.ts`](../tests/src/browser/transports/SocketCDPTransport.test.ts) pin them.
3116
- 12. **`Browser.destroy()` escalates SIGTERM to SIGKILL; `close()` is graceful.** On POSIX each launch owns an isolated process group, and `destroy()` signals that group, waiting `BROWSER_KILL_GRACE_MS` before `SIGKILL` and the same bounded window after it; on Windows a launch owns no group, so each step signals one process by identifier, and terminating a Chromium browser process takes its subprocesses with it. `close()` sends CDP `Browser.close` first and escalates to the same sequence only when an owned process fails to exit within the grace period. `owned` is `true` for a launched or adopted session, `false` for an active attachment, and `undefined` when no session is represented; `pid` names the process serving the endpoint and stays readable across a `'persistent'` session's `disconnect()`. [`tests/src/server/Browser.test.ts`](../tests/src/server/Browser.test.ts) pins the sequence against a spawned stand-in process.
3117
- 13. **A launch owns the process that serves its endpoint, through the inherited pipe.** Chrome and Chromium serve the endpoint from the process they spawn. A launcher such as Microsoft Edge on Windows instead re-executes the browser with the same `--remote-debugging-port` and exits 0 before the endpoint answers, and the process it spawned inherits its standard error, so `connect()` treats that clean exit as a hand-off: it keeps reading the same pipe on the same `timeout` budget until the `DevTools listening on` line arrives, then reads the `browser` entry of CDP `SystemInfo.getProcessInfo` and owns the process named there. A nonzero exit or a signal rejects at once with a `BrowserConnectionError` naming the exit; a pipe that closes without the line rejects with the readiness failure; an endpoint that names no browser process rejects after a best-effort `Browser.close`. Whether Edge's Windows launcher passes the pipe on is unread; see limit 26. The launcher hand-off cases in [`tests/src/server/Browser.test.ts`](../tests/src/server/Browser.test.ts) pin the rest.
3239
+ 12. **`Browser.destroy()` escalates SIGTERM to SIGKILL; `close()` is graceful.** On POSIX each launch owns an isolated process group, and `destroy()` signals that group, waiting `BROWSER_KILL_GRACE_MS` before `SIGKILL` and the same bounded window after it; on Windows a launch owns no group, so each step signals one process by identifier. `close()` sends CDP `Browser.close` first and escalates to the same sequence only when an owned process fails to exit within the grace period. Teardown explicitly closes and awaits the owned stderr read pipe, even when a surviving descendant retains its writer. `owned` is `true` for a launched or adopted session, `false` for an active attachment, and `undefined` when no session is represented; `pid` names the process serving the endpoint and stays readable across a `'persistent'` session's `disconnect()`. [`tests/src/server/Browser.test.ts`](../tests/src/server/Browser.test.ts) pins the sequence and pipe release against spawned processes.
3240
+ 13. **A launch owns the process that serves its endpoint, through the inherited pipe.** Chrome and Chromium serve the endpoint from the process they spawn. A launcher such as Microsoft Edge on Windows instead re-executes the browser with the same `--remote-debugging-port` and exits 0 before the endpoint answers, and the process it spawned inherits its standard error, so `connect()` treats that clean exit as a hand-off: it keeps reading the same pipe on the same `timeout` budget until the `DevTools listening on` line arrives, then reads the `browser` entry of CDP `SystemInfo.getProcessInfo` and owns the process named there. A nonzero exit or a signal rejects at once with a `BrowserConnectionError` naming the exit; a pipe that closes without the line rejects with the readiness failure; an endpoint that names no browser process rejects after a best-effort `Browser.close`. The Windows Edge launch reading is recorded in limit 26. The launcher hand-off cases in [`tests/src/server/Browser.test.ts`](../tests/src/server/Browser.test.ts) pin the rest.
3118
3241
  14. **A snapshot is serializable data plus navigation.** `BrowserSnapshot` holds exactly `documents` and `styles`, so `JSON.stringify(snapshot)` yields `{ documents, styles }` and `createBrowserSnapshot(parsed)` navigates it again; every method takes and returns bare `BrowserNode` values, and containment is derived from `ancestors`. [`tests/src/core/BrowserSnapshot.test.ts`](../tests/src/core/BrowserSnapshot.test.ts) pins it.
3119
3242
  15. **A reference names one element for as long as that element exists.** A reference is `e` followed by a positive integer. On CDP every page's element manager mints from one counter its browser context owns and binds the reference to `SESSION:BACKEND`, because backend node ids are per renderer; in the DOM placement the view owns the counter and binds a `WeakRef`. No number is reused within the context. A cross-document navigation of the main frame drops every reference, a child frame's navigation or detachment drops that frame's, and a stale or unknown reference refuses `GONE` or `UNKNOWN` with a message naming `look`. `parseBrowserReference` accepts `e12`, `E12`, `12`, `[e12]`, `ref=e12`, and `[ref=e12]`. A journey's `reference` is evidence a developer reads, never a lookup: replay resolves each target by role and exact name. [`tests/src/core/elements/BrowserElementManager.test.ts`](../tests/src/core/elements/BrowserElementManager.test.ts), [`tests/src/core/parsers.test.ts`](../tests/src/core/parsers.test.ts), and [`tests/src/browser/elements/BrowserDOMElementManager.test.ts`](../tests/src/browser/elements/BrowserDOMElementManager.test.ts) pin it, and the `journey semantic replay` block of [`tests/service/journey.test.ts`](../tests/service/journey.test.ts) pins that a changed page resolves by name and that neither a stored reference nor a matching CSS selector resolves a target.
3120
3243
  16. **A reading is captured one time and sliced from one projection.** `frame.read()` issues one size-guarded evaluation in the isolated world; `markdown` and `text` each project the capture one time per mode and cut every slice from it, ending a bounded slice after the last line break in its window when one lies past `offset`. Truncation is derived as `offset + text.length < total`, and `stale` is derived from the navigation epoch, never stored. [`tests/src/core/BrowserReading.test.ts`](../tests/src/core/BrowserReading.test.ts) and [`tests/src/core/BrowserPage.test.ts`](../tests/src/core/BrowserPage.test.ts) pin it.
@@ -3122,12 +3245,12 @@ These invariants hold across the four faces (`src/core`, `src/browser`, `src/ser
3122
3245
  18. **Actions run one at a time.** The toolset runs actions in first-in, first-out order, and an action holds the queue until its receipt is produced; an action whose signal aborts while queued sends nothing. After a `mousePressed` or `keyDown` is sent, the matching release is sent without the signal, so an abort never leaves a button or key down, and the next action waits for a pending release. Every result and error message is cut at `limit` characters plus a footer. A `click`, `type`, or `press` on a page opens `page.navigation.record(frame)` before its first input and settles its receipt through that record, so the receipt's view follows the navigation the record selects, and the toolset holds no frame, session, or loader state of its own. While a replay holds the toolset, an action admitted after the hold that does not carry the hold's token is refused with `BROWSER_TOOLSET_BUSY` rather than queued, and the actions admitted before the hold complete first. The queue, bounds, destroy, hold, and navigation settlement cases in [`tests/src/core/BrowserToolset.test.ts`](../tests/src/core/BrowserToolset.test.ts), the selection cases in [`tests/src/core/BrowserNavigationRecord.test.ts`](../tests/src/core/BrowserNavigationRecord.test.ts), and the `claim 6` block of [`tests/service/journey.test.ts`](../tests/service/journey.test.ts) pin it.
3123
3246
  19. **A dialog interrupts every tool and stages `dialog`.** Every pending step of every tool is raced against the page's `dialog` event, so a tool returns a receipt naming the dialog while the blocked command waits; the `dialog` tool is advertised while the dialog is open and bypasses the queue, and every other tool refuses with a message naming the open dialog and ending `call dialog.` A replay admits a `dialog` step only after an `interrupted` action, the continuation the toolset stages, and under a hold a `dialog` from another caller is refused with `BROWSER_TOOLSET_BUSY`. The dialog cases in [`tests/src/core/BrowserToolset.test.ts`](../tests/src/core/BrowserToolset.test.ts) and [`tests/src/core/BrowserReplay.test.ts`](../tests/src/core/BrowserReplay.test.ts), the `confirm()` and `beforeunload` dialog cases in [`tests/service/toolset.test.ts`](../tests/service/toolset.test.ts), and the `claim 6` block of [`tests/service/journey.test.ts`](../tests/service/journey.test.ts) pin it.
3124
3247
  20. **CDP input is trusted and DOM input is not.** A page's `trusted` is `true`: clicks, keys, and hovers are `Input` events whose `isTrusted` is `true`. A DOM view's `trusted` is `false`: `click` is `HTMLElement.click()`, `fill` is the native value setter plus `input` and `change`, and `submit` is `requestSubmit()` observed by a `submit` listener, so a form that fails validation reports `did not submit` with the field's `validationMessage`. Its `click` and `type` receipts end `(untrusted event)`. It refuses rather than fakes a key press, a navigation, a file chooser, typing into `contenteditable`, a link or form whose target opens another browsing context, a disabled control, and a cross-origin frame. [`tests/src/browser/elements/BrowserDOMElement.test.ts`](../tests/src/browser/elements/BrowserDOMElement.test.ts) and [`tests/service/document.test.ts`](../tests/service/document.test.ts) pin it.
3125
- 21. **The toolset's names are reserved at `start()`.** `start()` rejects with a coded `BrowserError` and adds nothing when the manager already holds `look`, `read`, `click`, `type`, `press`, `navigate`, `wait`, `dialog`, `tabs`, or `switch` under a tool the toolset did not add, and a page tool under a reserved name is skipped with `reserved`. A page tool named `unresolved` is also skipped as reserved. A toolset constructed with `journeys` also reserves `record`, `save`, `journeys`, `edit`, `replay`, and `forget`: construction refuses a manager that holds one with `BROWSER_TOOLSET_RESERVED`, and a page tool under one is skipped with `reserved`. The `browse` server keeps its dispatchers on a manager of its own and forwards to the toolset's, so the toolset meets no foreign name. A consumer that replaces a reserved name after `start()` breaks the path a receipt names, such as `call dialog`. [`tests/src/core/BrowserToolset.test.ts`](../tests/src/core/BrowserToolset.test.ts), [`tests/src/core/BrowserJourneyToolset.test.ts`](../tests/src/core/BrowserJourneyToolset.test.ts), and [`tests/src/server/BrowserMCPServer.test.ts`](../tests/src/server/BrowserMCPServer.test.ts) pin it.
3248
+ 21. **The toolset's names are reserved at `start()`.** `start()` rejects with a coded `BrowserError` and adds nothing when the manager already holds `look`, `read`, `plain`, `click`, `type`, `press`, `navigate`, `wait`, `dialog`, `tabs`, or `switch` under a tool the toolset did not add, and a page tool under a reserved name is skipped with `reserved`. A page tool named `unresolved` is also skipped as reserved. A toolset constructed with `journeys` also reserves `record`, `save`, `journeys`, `edit`, `replay`, `forget`, and `capture`: construction refuses a manager that holds one with `BROWSER_TOOLSET_RESERVED`, and a page tool under one is skipped with `reserved`. The `browse` server keeps its dispatchers on a manager of its own and forwards to the toolset's, so the toolset meets no foreign name. A consumer that replaces a reserved name after `start()` breaks the path a receipt names, such as `call dialog`. [`tests/src/core/BrowserToolset.test.ts`](../tests/src/core/BrowserToolset.test.ts), [`tests/src/core/BrowserJourneyToolset.test.ts`](../tests/src/core/BrowserJourneyToolset.test.ts), and [`tests/src/server/BrowserMCPServer.test.ts`](../tests/src/server/BrowserMCPServer.test.ts) pin it.
3126
3249
  22. **The in-page toolset never drives its own document by default.** An action that navigates the realm's own document cannot return, so `createBrowserDOMView` and `createDocumentToolset` refuse `globalThis.document` with `BROWSER_DOCUMENT_OWN` unless `own` is `true`. [`tests/src/browser/factories.test.ts`](../tests/src/browser/factories.test.ts) pins it.
3127
3250
  23. **Limit: an `alert()` blocks the driven document.** The DOM placement never replaces `window.alert`, `confirm`, or `prompt`, so a click that opens one blocks the driven document's thread and the action does not return until a person answers it; the CDP placement stages `dialog` instead. [`tests/guides.test.ts`](../tests/guides.test.ts) pins that no `src/browser` module assigns those functions.
3128
3251
  24. **Limit: a `debugging` page tool is not adopted.** [Declared conformance gaps](#declared-conformance-gaps) records this limit in its entry "A `debugging` page tool is not adopted". [`tests/src/core/BrowserToolset.test.ts`](../tests/src/core/BrowserToolset.test.ts) and the skip rows of [`tests/conformance.test.ts`](../tests/conformance.test.ts) pin it.
3129
3252
  25. **Limit: the `WebMCP` live proof names its host.** Chromium 141, the host browser, answers `WebMCP.enable` with `-32601`, so the registry conforms to the vendored mirrors and the scripted transports, and this guide claims no interoperability with a shipping registry. [Declared conformance gaps](#declared-conformance-gaps) records this limit and its closer in its entry "The live `WebMCP` domain is unproven on this host". The case in [`tests/service/browser.test.ts`](../tests/service/browser.test.ts) that compares `registry.start()` with whether `Schema.getDomains` lists `WebMCP`, and the live case that skips on that answer, pin it.
3130
- 26. **Limit: the Edge launcher hand-off is unread on Windows.** Invariant 13 describes the hand-off from a launcher that exits after it re-executes the browser. Whether Microsoft Edge's Windows launcher passes its standard error on to the browser it spawns is unread, because no Windows host with Edge has run a launch. The closer is a launch of Edge on a Windows host. The launcher hand-off cases in [`tests/src/server/Browser.test.ts`](../tests/src/server/Browser.test.ts) pin the hand-off against a stand-in process.
3253
+ 26. **Limit: the Windows launch reading covers Edge 154.0.4258.53.** On 2026-10-03, `npm run test:service` launched Edge 154.0.4258.53 on Windows and reported 105 passed tests after commit `73c608f`. That run proves launch and endpoint ownership on that host; it doesn’t establish a launcher hand-off on every Edge installation or a Linux or macOS result. The launcher hand-off cases in [`tests/src/server/Browser.test.ts`](../tests/src/server/Browser.test.ts) exercise re-execution and inherited stderr with fixture processes.
3131
3254
 
3132
3255
  ## Patterns
3133
3256
 
@@ -3155,7 +3278,7 @@ await browser.destroy()
3155
3278
 
3156
3279
  ### Record a journey from the toolset and save it
3157
3280
 
3158
- A model records a journey by calling `record`, taking its actions, and calling `save`; the observations it calls between them are not steps. The following fence makes the same calls through the manager over file stores, and each comment quotes what the `browse` binary answered for the same calls on 2026-10-01 against a two-page loopback shop on Chromium 141.0.7390.37, with the view after each receipt left out.
3281
+ A model records a journey by calling `record`, taking its actions, and calling `save`; the observations it calls between them are not steps. The following fence makes the same calls through the manager over file stores, with comments adapted from the `browse` binary’s answers on 2026-10-01 against a two-page loopback shop on Chromium 141.0.7390.37 to the vocabulary that replaces `what` with `search` and adds `plain`. The view after each receipt is left out.
3159
3282
 
3160
3283
  ```ts
3161
3284
  import { mkdir } from 'node:fs/promises'
@@ -3177,7 +3300,7 @@ await toolset.start()
3177
3300
  await toolset.tools.execute({ id: '1', name: 'record', arguments: { journey: 'add-kettle' } })
3178
3301
  // Recording add-kettle; each action you take is a step; call save when it is done.
3179
3302
  await toolset.tools.execute({ id: '2', name: 'click', arguments: { ref: 'e1' } }) // Clicked e1 link "Alpine Kettle".
3180
- await toolset.tools.execute({ id: '3', name: 'look', arguments: { what: 'the page' } }) // no step
3303
+ await toolset.tools.execute({ id: '3', name: 'look', arguments: { search: '' } }) // no step
3181
3304
  await toolset.tools.execute({ id: '4', name: 'click', arguments: { ref: 'e2' } }) // Clicked e2 button "Add to cart".
3182
3305
  await toolset.tools.execute({ id: '5', name: 'wait', arguments: { text: 'Added to cart' } }) // "Added to cart" is on the page.
3183
3306
  const saved = await toolset.tools.execute({
@@ -3220,7 +3343,10 @@ The run lands at `tmp/browsers/add-kettle/runs/ID/run.json` with one `sN.png` ca
3220
3343
  `edit` is the review path: read the listing `journeys` returns, then change the journey by step id in one batch, which applies in order and is refused whole on its first invalid edit. A batch can declare a parameter and bind it in the same call, and `remove` drops a step a model repeated. The following fence edits a recorded order form whose model pressed Enter after a `type` that had already submitted: it declares `customer`, binds the name field's text to it, and removes the second submission.
3221
3344
 
3222
3345
  ```ts
3223
- await toolset.tools.execute({ id: '9', name: 'journeys', arguments: { what: 'place-order' } })
3346
+ await toolset.tools.execute({ id: '9', name: 'journeys', arguments: { search: 'place-order' } })
3347
+ // 1 journey matches "place-order":
3348
+ // [0] place-order "Order the Alpine Kettle with a name"
3349
+ //
3224
3350
  // place-order "Order the Alpine Kettle with a name"
3225
3351
  // s1 type "Ada Lovelace" into textbox "Full name", submit
3226
3352
  // s2 press Enter
@@ -3379,9 +3505,9 @@ await client.close()
3379
3505
 
3380
3506
  ### Drive a page with a small model
3381
3507
 
3382
- The store proof in `@orkestrel/ollama` drives a 2-billion-parameter model through a toolset whose tools and prompt follow these rules: every tool declares at least one required parameter, so `look`, `read`, and `tabs` take `what`; references are spelled `e4` and the parameter descriptions name one; one observation carries text and references in document order; every action's receipt carries the fresh view; and the first message carries the view, so the model starts from the page rather than from a guess. The system prompt tells the model to call a tool before it answers, states that the first message shows the page as `look` returns it and that references such as `e4` name its elements, names the one call for each kind of step (`read` with `what` set to the question, and again with the offset its result names, to learn a fact; `type` with the search box reference, the words, and `submit` to search; `click` with a reference from the latest result to press a button or follow a link; and `wait` one time for text that has not appeared), tells it never to invent a reference, and tells it to answer in one short sentence.
3508
+ The following prompt follows the reading vocabulary. The recorded store proof in `@orkestrel/ollama` used the earlier argument name and predates the plain-text tool. The toolset follows these rules: every tool declares at least one required parameter, so `look`, `read`, `plain`, `tabs`, and `journeys` take `search`; references are spelled `e4` and the parameter descriptions name one; one observation carries text and references in document order; every action's receipt carries the fresh view; and the first message carries the view, so the model starts from the page rather than from a guess. The system prompt tells the model to call a tool before it answers, states that the first message shows the page as `look` returns it and that references such as `e4` name its elements, names the one call for each kind of step (`read` with `search` set to words from the question, and again with the offset its result names, to learn a fact; `type` with the reference, the words, and `submit true` to use “the site's search box”; `click` with a reference from the latest result to press a button or follow a link; and `wait` one time for text that has not appeared), tells it never to invent a reference, and tells it to answer in one short sentence.
3383
3509
 
3384
- With that prompt, `qwen3.5:2b-q4_K_M` at temperature 0 with 256 predicted tokens a turn met the oracle of all five store tasks against this package's 0.0.19 build, packed from commit `254d107`: read, click, search, and form on their first attempt, and paging on its second. The run took 627.4 s, and its transcripts sit under `tmp/probes/logs/v8/` in `@orkestrel/ollama`; every count and duration in the following list is from them. The list states what the proof asserts for each task and what the transcripts show beside it.
3510
+ With the earlier prompt, `qwen3.5:2b-q4_K_M` at temperature 0 with 256 predicted tokens a turn met the oracle of all five store tasks against this package's 0.0.19 build, packed from commit `254d107`: read, click, search, and form on their first attempt, and paging on its second. The run took 627.4 s, and its transcripts sit under `tmp/probes/logs/v8/` in `@orkestrel/ollama`; every count and duration in the following list is from them. The list states what the proof asserts for each task and what the transcripts show beside it.
3385
3511
 
3386
3512
  - Read: 2 calls in 55.4 s, `look` and then `read` without an offset. The proof asserts that a result carried the shipping cutoff the seeded view did not and that the answer names it, and the answer named `2:40 PM`.
3387
3513
  - Click: 8 calls in 93.6 s. The proof asserts that the cart holds the named product and no other, and it held `Cedar Tea Tray`. On the product page the model called `type` on the button, which was refused with `Element e28 button "Add to cart" takes no text; call click for a button.`, and its `click` on the button returned a receipt whose view was the cart page. The model then called `wait` four times for text it invented and reached the 8-call limit without an answer, which the proof does not assert.
@@ -3400,8 +3526,8 @@ import { createToolManager } from '@orkestrel/tool'
3400
3526
  const system =
3401
3527
  'You control a web browser with tools and must call a tool before you answer. ' +
3402
3528
  'The first message shows the page as look returns it; references such as e4 name its elements. ' +
3403
- 'To learn a fact, call read with what set to your question; when its result ends by naming an offset, call read again with that offset. ' +
3404
- 'To search, call type with the search box reference, the words, and submit true. ' +
3529
+ 'To learn a fact, call read with search set to words from your question; when its result ends by naming an offset, call read again with that offset. ' +
3530
+ "To use the site's search box, call type with its reference, the words, and submit true. " +
3405
3531
  'To press a button or follow a link, call click with its reference from the latest result. Never invent a reference. ' +
3406
3532
  'If text you expect has not appeared, call wait once. ' +
3407
3533
  'When the task is done, answer in one short sentence.'
@@ -3412,7 +3538,7 @@ try {
3412
3538
  const seeded = await toolset.tools.execute({
3413
3539
  id: 'seed',
3414
3540
  name: 'look',
3415
- arguments: { what: 'the page' },
3541
+ arguments: { search: '' },
3416
3542
  })
3417
3543
  const view = seeded.success ? String(seeded.value) : seeded.error
3418
3544
  const agent = createAgent(createOllama({ model: 'qwen3.5:2b-q4_K_M' }), {
@@ -3455,18 +3581,58 @@ const server = createMCPServer({
3455
3581
  await createStdioServer(server).start()
3456
3582
  ```
3457
3583
 
3458
- The page tools the page registers join the manager as they are adopted and leave it as they are removed, so the client's next `tools/list` sees them. The `browse` binary serves the same vocabulary with the journey tools and launches the browser on its first call; see [Register the browse binary with Claude Code](#register-the-browse-binary-with-claude-code).
3584
+ The page tools the page registers join the manager as they are adopted and leave it as they are removed, so the client's next `tools/list` sees them. The `browse` binary serves the same vocabulary with the journey tools and starts its browser when the server starts; see [Register the browse binary with Claude Code](#register-the-browse-binary-with-claude-code).
3459
3585
 
3460
3586
  ### Register the browse binary with Claude Code
3461
3587
 
3462
- The `browse` binary serves the vocabulary and the journey tools over MCP on stdio, so a client registers it as a command and needs no code. It ships in `@orkestrel/browser` as `dist/bin/main.js`, with `@orkestrel/mcp` as a runtime dependency, and takes no command-line arguments. It reads four environment variables, and an empty value counts as unset:
3588
+ The `browse` binary serves the vocabulary and the journey tools over MCP on stdio, so a client registers it as a command and needs no code. It ships in `@orkestrel/browser` as `dist/bin/main.js`, with `@orkestrel/mcp` as a runtime dependency, and takes no command-line arguments. It reads the following environment variables, and an empty value counts as unset:
3463
3589
 
3464
3590
  - `BROWSE_ROOT`: the root of the journeys, the runs, and the profiles, resolved against the working directory. Default: `tmp/browsers`.
3465
3591
  - `BROWSE_HEADLESS`: `true`, `false`, `1`, or `0`. Default: `true`.
3466
3592
  - `BROWSE_EXECUTABLE`: the path of the Chromium executable. Default: the browser `findSystemBrowser` finds.
3467
3593
  - `BROWSE_READONLY`: `true`, `false`, `1`, or `0`; `true` refuses `record`, `save`, `edit`, and `forget`, and `replay` still writes runs. Default: `false`.
3594
+ - `BROWSE_POOL`: an integer from `1` through `3` setting the number of browsers the server keeps, and so the most holders at the same time, the shared browser included; see [Run work in parallel](#run-work-in-parallel). Default: `1`.
3595
+ - `BROWSE_VIEWPORT`: positive integer dimensions in `WIDTHxHEIGHT` form, such as `390x844`. Applies to every page and popup, including those in spares and refills. Default: the browser's launch default.
3596
+
3597
+ A malformed value ends the process with exit code 1 and one line on standard error. Any other value of `BROWSE_HEADLESS` or `BROWSE_READONLY`, a `BROWSE_POOL` that is not an integer, and a malformed `BROWSE_VIEWPORT` write a `BROWSER_SERVER_ENVIRONMENT` line, such as `browse: BROWSER_SERVER_ENVIRONMENT: BROWSE_HEADLESS must be true, false, 1, or 0, not "sometimes"`. Viewport dimensions must be positive safe integers written as decimal digits with a lowercase `x` separator and no whitespace. An integer `BROWSE_POOL` outside `1` through `3` writes `browse: BROWSER_SERVER_OPTIONS: pool.size must be an integer from 1 through 3`. On Linux a server running as root launches Chromium with `--no-sandbox`, because Chromium refuses to start as root with its sandbox on.
3598
+
3599
+ Chromium starts when the server starts, before the client sends a request. The server launches its first browser, checks that it answers a CDP ping, and leases it as the shared browser, which the named tools drive. `initialize` and every tool call wait for that lease, and `ping` and `tools/list` answer while the browser warms. With `BROWSE_POOL` at `2` or `3`, the other browsers warm after the first, and `initialize` does not wait for them. A launch that fails is retried one time. The end of input or `SIGTERM` closes every browser and removes its profile, the process exits with code 0, and a run without a fault writes nothing to standard error.
3600
+
3601
+ A client gives a server a limited time to answer `initialize`. On 2026-10-03, Claude Code's documentation gave 30 s and connected servers in the background, the Codex configuration reference gave 10 s through `startup_timeout_sec`, and Cursor's documentation gave no limit; see [Claude Code's MCP documentation](https://code.claude.com/docs/en/mcp), [the Codex configuration reference](https://learn.chatgpt.com/docs/config-file/config-reference), and [Cursor's MCP documentation](https://cursor.com/docs/context/mcp). On Windows 11 with Edge 154 on 2026-10-04, while a browser test suite ran beside it, the built binary answered `initialize` at most 2.07 s after its spawn at every `BROWSE_POOL` size, a leftover browser to sweep included. No client needs a longer startup timeout.
3468
3602
 
3469
- Any other value of `BROWSE_HEADLESS` or `BROWSE_READONLY` ends the process with exit code 1 and one line on standard error, such as `browse: BROWSER_SERVER_ENVIRONMENT: BROWSE_HEADLESS must be true, false, 1, or 0, not "sometimes"`. Chromium starts on the first tool call, not at registration, and on Linux a server running as root launches it with `--no-sandbox`, because Chromium refuses to start as root with its sandbox on.
3603
+ Set `BROWSE_POOL` to `2` or `3` to keep warm browsers beyond the shared one. A browser no holder leases is a spare: it waits idle until `acquire` admits a holder on it or a holder's browser is lost. After a loss, the holder's next call runs on a spare while a replacement warms, and concurrent calls on that holder share its one replacement. At `1`, the next call after a loss waits for a replacement launch. In the 2026-10-04 run, the next successful call after a kill of the session's browser took a median 1.92 s at `1` and 0.40 s at `2`. On Windows 11 with Edge 154 on 2026-10-04, an idle spare's process tree used about 130% of one core in the first 20 s, then a median near 10%, and its summed working set grew from 1.22 GB to 1.78 GB over 2 minutes, with shared pages counted in every process that maps them. With `BROWSE_HEADLESS=false`, each spare opens its own window.
3604
+
3605
+ When a holder's browser is lost, the shared browser's included, browse never repeats a call. A loss is the browser process exiting, its CDP connection dropping, the renderer of its current page crashing, or a CDP ping it fails before a call or after a failed one; a crashed background tab is not a loss. The following list gives what each call answers around a loss:
3606
+
3607
+ - A call after the loss runs on a fresh browser that starts at `about:blank`, and its text opens with a `BROWSER_SERVER_CRASH:` note that names the cause and the lost page's URL. An element reference from the lost page is refused.
3608
+ - A call the loss interrupts answers `BROWSER_SERVER_UNRESOLVED:`: its outcome is unknown, and browse did not repeat it. Read the page before you repeat the call.
3609
+ - A call that completed before the loss keeps its result, and the next call carries the note.
3610
+ - A call that fails for its own reason on a live browser answers its plain failure, with no note.
3611
+ - When no browser can serve, the call answers the note, then `BROWSER_SERVER_UNAVAILABLE:` naming the cause.
3612
+
3613
+ A hang of the whole browser during a call can take two command deadlines, the call's and then the post-failure ping's, so in Codex set `tool_timeout_sec` for `browse` higher than the default 60 s.
3614
+
3615
+ Cancelling a call ends its wait without cancelling the browser's liveness check. Concurrent checks share one ping per slot, so a later call joins the remaining deadline. A failed ping retires the slot and leaves the `BROWSER_SERVER_CRASH:` note for the successor's outcome.
3616
+
3617
+ A ping deadline forces the owned process to exit before slot teardown. On Windows, the service proof launches a Node stand-in that completes CDP setup and then withholds replies; it asserts that the pid exits and the call runs on a real browser successor. The `SIGSTOP` proof remains conditional on the host accepting that signal.
3618
+
3619
+ When no browser starts at setup, the server refuses on each surface and keeps answering until its input ends. Setup fails, for example, when the first browser fails to launch twice or the root cannot be created. The following list gives what each request answers, where `CAUSE` is the failure's message:
3620
+
3621
+ - `initialize` answers the JSON-RPC error `-32000` with the message `BROWSER_SERVER_UNAVAILABLE: CAUSE` and `data.code` set to `BROWSER_SERVER_UNAVAILABLE`.
3622
+ - `ping` answers `{}`, and `tools/list` answers the vocabulary.
3623
+ - Every `tools/call` answers an error result whose text opens with `BROWSER_SERVER_UNAVAILABLE:`, so a client that connects without the legacy `initialize` meets the refusal at its first tool call.
3624
+ - The binary writes `browse: BROWSER_SERVER_UNAVAILABLE: CAUSE` to standard error and exits with code 1 after its input ends.
3625
+
3626
+ The server writes each diagnostic as one line on standard error in the form `browse: CODE: DETAIL`, where `CODE` is one of the following codes and `DETAIL` is the cause:
3627
+
3628
+ - `BROWSER_SERVER_LAUNCH`: a browser failed to start, and the pool retries it within its bound.
3629
+ - `BROWSER_SERVER_EXHAUSTED`: setup's warming or a call's acquire rejected with the pool's `create` error after the launch bound was spent; a spare that spends the bound after setup writes `BROWSER_SERVER_LAUNCH` lines without this line.
3630
+ - `BROWSER_SERVER_UNAVAILABLE`: setup was refused, and the binary writes this line before it exits with code 1.
3631
+ - `BROWSER_SERVER_TEARDOWN`: a browser's termination is unconfirmed or its teardown failed; its profile folder stays until the shutdown recheck, and a shutdown that meets it exits with code 1.
3632
+ - `BROWSER_SERVER_SWEEP`: the sweep could not read the `.profiles` folder under `BROWSE_ROOT`, and the server serves without it.
3633
+ - `BROWSER_SERVER_ENVIRONMENT` and `BROWSER_SERVER_OPTIONS`: a malformed variable, as the earlier paragraph describes.
3634
+
3635
+ At start, beside the launch, the server sweeps the profile folders that ended servers left under `ROOT/.profiles`, where `ROOT` is the `BROWSE_ROOT` directory. It visits each `<pid>-<uuid>` folder whose owning process has exited. It removes a folder with no `browse.json` record or whose recorded browser has exited, closes a recorded browser that still runs at a `ws://127.0.0.1` endpoint and then removes its folder, and keeps a folder whose record it cannot read, whose endpoint names a host other than `127.0.0.1`, or whose browser refuses to close; the shutdown recheck removes the last kind after its browser exits. `initialize` never waits for the sweep. The sweep never visits a bare `ROOT/.profiles/<uuid>` folder, which releases before 0.0.23 left: delete those folders by hand one time, while no `browse` server runs on that root, and leave every `<pid>-<uuid>` folder to the sweep.
3470
3636
 
3471
3637
  Claude Code 2.1.286 registers the binary for a checkout in four steps:
3472
3638
 
@@ -3477,20 +3643,20 @@ Claude Code 2.1.286 registers the binary for a checkout in four steps:
3477
3643
 
3478
3644
  Steps 2 and 3 ran on 2026-10-01 against a scratch checkout whose `node_modules/@orkestrel/browser` linked this package's build, with their output quoted. The approval in step 4 is interactive, and no approved Claude Code session drove the server in that run; the exchange that follows drove the command the entry names over stdio directly. With `@orkestrel/mcp` 0.0.34, a client that subscribes through `subscriptions/listen` receives `notifications/tools/list_changed` when the server mirrors a page tool, and a client that connects through `initialize` receives none and sees the tool at its next `tools/list`; which of the two Claude Code 2.1.286 opens is unread.
3479
3645
 
3480
- The following fence lists the exchange that drove the binary, one request and the text of its answer per line, with the view after each receipt left out; `tools/list` answered the 15 names before Chromium started, and the replay wrote `tmp/browsers/add-kettle/runs/2026-10-01T03-07-06.041Z-6d7e/` with `run.json`, `s1.png`, `s2.png`, and `s3.png`.
3646
+ The following fence adapts the recorded exchange to the vocabulary that replaces `what` with `search` and adds `plain` and the holder tools, one request and the text of its answer per line, with the view after each receipt left out; the replay wrote `tmp/browsers/add-kettle/runs/2026-10-01T03-07-06.041Z-6d7e/` with `run.json`, `s1.png`, `s2.png`, and `s3.png`.
3481
3647
 
3482
3648
  ```ts
3483
3649
  // -> initialize { protocolVersion: '2025-06-18' }
3484
3650
  // <- { protocolVersion: '2025-06-18', serverInfo: { name: 'browse', version: '0.0.19' }, capabilities: { tools: {} } }
3485
3651
  // -> tools/list
3486
- // <- look, read, click, type, press, navigate, wait, dialog, tabs, switch, record, save, journeys, edit, replay, forget
3652
+ // <- look, read, plain, click, type, press, navigate, wait, dialog, tabs, switch, record, save, journeys, edit, replay, forget, acquire, execute, tools, destroy, capture
3487
3653
  // -> tools/call navigate { url: 'http://127.0.0.1:35605/' }
3488
3654
  // <- Navigated to http://127.0.0.1:35605/.
3489
3655
  // -> tools/call record { journey: 'add-kettle' }
3490
3656
  // <- Recording add-kettle; each action you take is a step; call save when it is done.
3491
3657
  // -> tools/call click { ref: 'e1' }
3492
3658
  // <- Clicked e1 link "Alpine Kettle".
3493
- // -> tools/call look { what: 'the page' }
3659
+ // -> tools/call look { search: '' }
3494
3660
  // <- page "Alpine Kettle" http://127.0.0.1:35605/kettle
3495
3661
  // -> tools/call click { ref: 'e2' }
3496
3662
  // <- Clicked e2 button "Add to cart".
@@ -3498,7 +3664,7 @@ The following fence lists the exchange that drove the binary, one request and th
3498
3664
  // <- "Added to cart" is on the page.
3499
3665
  // -> tools/call save { description: 'Adds the Alpine Kettle to the cart' }
3500
3666
  // <- Saved add-kettle with 3 steps.
3501
- // -> tools/call journeys { what: 'all' }
3667
+ // -> tools/call journeys { search: '' }
3502
3668
  // <- add-kettle "Adds the Alpine Kettle to the cart"
3503
3669
  // <- s1 click link "Alpine Kettle"
3504
3670
  // <- s2 click button "Add to cart"
@@ -3514,6 +3680,51 @@ The following fence lists the exchange that drove the binary, one request and th
3514
3680
 
3515
3681
  The `packed browse binary` case of [`tests/distribution.test.ts`](../tests/distribution.test.ts) runs the same command from an installed tarball through `@orkestrel/mcp`'s stdio client: it lists the vocabulary with Chromium absent, then records, saves, lists, edits, and replays a journey.
3516
3682
 
3683
+ On 2026-10-04, Claude Code 2.1.285 under `claude -p --mcp-config FILE --strict-mcp-config` and `codex exec` with `-c mcp_servers.browse.command`, `-c mcp_servers.browse.args`, and `-c mcp_servers.browse.env` overrides each started the built binary, where `FILE` names a JSON file holding the `browse` entry, with no saved client configuration. The following list gives what each client showed:
3684
+
3685
+ - Claude Code connects `browse` when setup is refused and shows the refusal as the answer to the first tool call, a text that opens with `BROWSER_SERVER_UNAVAILABLE:` and names the cause.
3686
+ - Codex hides a server whose `initialize` fails: the agent sees no `browse` tools, and neither the agent nor the `exec` output carries the cause. Set `required = true` in the `browse` entry of Codex's MCP configuration: Codex then refuses to start the session and prints the refusal with its cause, such as `required MCP servers failed to initialize: browse: ... BROWSER_SERVER_UNAVAILABLE: spawn ... ENOENT.` (read with `codex exec -c mcp_servers.browse.required=true` on 2026-10-04).
3687
+ - Codex `exec` asks approval for each `browse` tool that is not read-only. Under the approval policy `never`, it refused `navigate` with `MCP tool call requires approval, but approval policy is never`, and `look` ran.
3688
+ - A client that ends its session ends the server before its teardown finishes. On Windows 11 no browser stayed running, and one `<pid>-<uuid>` profile folder without a `browse.json` record stayed; the next start on the same root removes it.
3689
+
3690
+ ### Run work in parallel
3691
+
3692
+ Acquire a holder when work needs a browser of its own beside the shared one, such as a subagent that checks a page while you drive another through the named tools. Each holder runs on its own pooled browser, with its own profile, isolated context, pages, cookies, storage, and downloads, so its calls run beside the shared browser's calls and beside every other holder's. The named tools, such as `navigate` and `look`, keep serving the shared browser unchanged.
3693
+
3694
+ The following list gives the holder tools that `BROWSER_SERVER_COPY` defines:
3695
+
3696
+ - `acquire { purpose }`: admits a holder and answers JSON with the server-minted `holder` id and its browser's `tools` catalog. The `purpose` text describes the work and names the holder in a capacity refusal. Hand the id to the agent that does the work.
3697
+ - `execute { holder, name, arguments }`: runs the tool `name` from the holder's catalog with that tool's own arguments inside `arguments`, and answers what the tool answers.
3698
+ - `tools { holder }`: lists the holder's catalog, including the page tools its current page registers.
3699
+ - `destroy { holder }`: ends the holder and destroys its browser. A call still running on that holder answers `BROWSER_SERVER_UNRESOLVED:`, and a repeated `destroy` of the same holder succeeds again.
3700
+
3701
+ The following fence shows one holder from `acquire` to `destroy`, one request and the text of its answer per line, with the view after the receipt left out; `HOLDER_ID` stands for the id that `acquire` returns.
3702
+
3703
+ ```ts
3704
+ // -> tools/call acquire { purpose: 'Check the cart while the main agent edits the catalog' }
3705
+ // <- {"holder":"HOLDER_ID","tools":[/* the definitions of look, read, plain, and the rest of the catalog */]}
3706
+ // -> tools/call execute { holder: 'HOLDER_ID', name: 'navigate', arguments: { url: 'https://shop.example/cart' } }
3707
+ // <- Navigated to https://shop.example/cart.
3708
+ // -> tools/call tools { holder: 'HOLDER_ID' }
3709
+ // <- {"holder":"HOLDER_ID","tools":[/* the same catalog, with the page tools the cart page registers */]}
3710
+ // -> tools/call destroy { holder: 'HOLDER_ID' }
3711
+ // <- Holder destroyed.
3712
+ ```
3713
+
3714
+ `destroy` ends the holder's browser process and removes its profile folder, so the holder's pages, cookies, storage, and downloads are gone, and the next holder starts on a fresh browser with a fresh profile. Each browser saves downloads in its own profile, under `ROOT/.profiles/PID-UUID/downloads/`, so copy a file out before you destroy its holder; the end of the server removes the shared browser's downloads the same way. The `contains downloads and destroys their process and profile before capacity is reused cleanly` case of [`tests/service/browse.test.ts`](../tests/service/browse.test.ts) asserts the download path, the exited process, the removed profile, and a clean replacement against a real Chromium.
3715
+
3716
+ `BROWSE_POOL`, or `pool.size` for `BrowserMCPServer`, counts every browser, the shared browser included, so a size of `3` admits two holders. At capacity, `acquire` answers immediately with `BROWSER_SERVER_BUSY:` and launches nothing; its text lists each holder by id and purpose, the shared browser as `shared (Shared browser)`, and tells the agent to destroy a holder it no longer needs or to call the named tools to share the shared browser. A holder that `destroy` is ending counts until its browser is gone. An unknown or ended id answers `BROWSER_SERVER_HOLDER:` and never falls back to the shared browser.
3717
+
3718
+ A holder whose browser is lost waits for a spare or a replacement launch, and the `BROWSER_SERVER_CRASH:` note reaches that holder's next call only. Replays of one journey run together across holders, each writing its own run. While a replay of a journey persists its run on any holder, `forget` of that journey answers `BROWSER_JOURNEY_LOCKED: Journey NAME is locked; call forget again.`, where `NAME` is the journey's name, and a replay that starts while `forget` runs answers the same refusal for `replay`.
3719
+
3720
+ The following list gives the limits of holders:
3721
+
3722
+ - The default `BROWSE_POOL` of `1` keeps only the shared browser, so `acquire` always answers `BROWSER_SERVER_BUSY:` and the named tools always work. [ROADMAP item 14](../ROADMAP.md) holds the contention measurement that rules the default.
3723
+ - `tools/list` mirrors only the shared browser's page tools. A holder's page tools appear only in the catalog that `acquire` and `tools` return, and run through `execute`.
3724
+ - A holder keeps its browser until `destroy` or the end of the server, with no idle timeout. An abandoned holder costs one warm browser and one place of capacity, and the `BROWSER_SERVER_BUSY:` text names it.
3725
+ - Journey admission covers the holders of one server. A second `browse` process on the same root can still race a replay against `forget`.
3726
+ - Codex asks approval for `execute` and `destroy`, because neither is advertised read-only, so under an approval policy that asks, every call a holder makes through `execute` prompts. `acquire` carries no read-only annotation either, and `tools` is advertised read-only.
3727
+
3517
3728
  ### Publish native tools to a page
3518
3729
 
3519
3730
  A page that runs a built-in browser agent reads tools from its WebMCP registry, and `@orkestrel/mcp`'s bridge publishes a tool manager there. Publish `toolset.native`, never `toolset.tools`: the manager also holds the page tools the toolset adopted from the same registry, and publishing them would register each one as a proxy of itself. The following fence drives a same-origin child document, adopts that document's page tools through the bridge, and publishes the five generic tools back to it.
@@ -3529,7 +3740,7 @@ if (driven !== null && bridge !== undefined) {
3529
3740
  const toolset = createDocumentToolset({ document: driven, source: bridge })
3530
3741
  await toolset.start() // adopts the document's registered tools, and again on each change
3531
3742
  const native = createToolManager()
3532
- for (const tool of toolset.native) native.add(tool) // look, read, click, type, wait
3743
+ for (const tool of toolset.native) native.add(tool) // look, read, plain, click, type, wait
3533
3744
  await bridge.publish(native)
3534
3745
  }
3535
3746
  ```
@@ -3558,6 +3769,8 @@ The following list names each test file and what it proves.
3558
3769
  - [`tests/setupServer.test.ts`](../tests/setupServer.test.ts): the ports, processes, scratch directories, CDP test server, fixture pages, the journey module stage, and the browse launch double and stdio pair the server and service suites share; the filesystem suite the file stores run, two processes over one directory included, lives in `tests/src/server/stores/suite.ts`.
3559
3770
  - [`tests/setupService.test.ts`](../tests/setupService.test.ts): the service project's browser flags, engine selection, and registry reading.
3560
3771
  - [`tests/service/browser.test.ts`](../tests/service/browser.test.ts): a real browser's launch, navigation, elements, frames, routes, snapshots, PDF, result limits, reattachment, transport loss, and shutdown; the out-of-process frame click, occlusion, hit-test, stale-reference, reading, and wait proofs; and the `WebMCP` domain reading and its live case.
3772
+
3773
+ - [`tests/service/browse.test.ts`](../tests/service/browse.test.ts): eager startup, process and renderer loss, forced exit of a hung Node stand-in, successor calls, and profile cleanup. The synthesized orphan case waits for the owned browser's process-exit event within the sweep's attach and close deadlines plus `BROWSER_KILL_GRACE_MS`.
3561
3774
  - [`tests/service/toolset.test.ts`](../tests/service/toolset.test.ts): one toolset task end to end through `createToolManager().execute`, the cart view in the receipt of a click whose form the server answers with a 303 redirect, the destination view after a form submission in a child frame, the `confirm()` and `beforeunload` dialogs, popups and tabs, and each receipt within its deadline; its `journey perform equality` block compares `perform` with a direct call for every native action, an editable combobox, a click that opens a dialog, a tab switch, a link that opens a popup, and a click in a same-origin child frame of the DOM placement.
3562
3775
  - [`tests/service/codegen.test.ts`](../tests/service/codegen.test.ts): the page recorder's steps for each gesture on Chromium against the fixture's own event log, the edit boundaries, and a password that never crosses the binding.
3563
3776
  - [`tests/service/journey.test.ts`](../tests/service/journey.test.ts): the `journey semantic replay` block, a changed page resolved by name with a duplicate refused before any input and a matching CSS selector refused; the `compiled module equality` block, each generated module and its replay reaching one page outcome with the same receipts, a gap, and the type check; and the `journey replay coordination, preparation, tools, and secrecy` block, the hold, a timeout, preparation before any side effect, the tools over the file stores, and a secret kept out of every artifact.
@@ -3601,7 +3814,7 @@ The following list names each test file and what it proves.
3601
3814
  - [`tests/src/core/recorders/BrowserRecorder.test.ts`](../tests/src/core/recorders/BrowserRecorder.test.ts): the toolset recorder's steps, the interrupted and child-frame gaps, the held journey's gap, secret bindings, and its lifecycle.
3602
3815
  - [`tests/src/core/BrowserReplay.test.ts`](../tests/src/core/BrowserReplay.test.ts): preparation before any hold, execution and stopping, the dialog continuation, abort, the run write and its bound, captures through the run store, output, and secrets.
3603
3816
  - [`tests/src/core/BrowserHold.test.ts`](../tests/src/core/BrowserHold.test.ts): the hold's token and its one release.
3604
- - [`tests/src/core/BrowserJourneyToolset.test.ts`](../tests/src/core/BrowserJourneyToolset.test.ts): the six tools, every result and refusal verbatim, the listing and its cut, `readonly`, the signal, the `ref` conversion, and destroy.
3817
+ - [`tests/src/core/BrowserJourneyToolset.test.ts`](../tests/src/core/BrowserJourneyToolset.test.ts): the journey tools, every result and refusal verbatim, the listing and its cut, `readonly`, the signal, the `ref` conversion, and destroy.
3605
3818
  - [`tests/src/core/stores/MemoryBrowserJourneyStore.test.ts`](../tests/src/core/stores/MemoryBrowserJourneyStore.test.ts) and [`tests/src/core/stores/MemoryBrowserRunStore.test.ts`](../tests/src/core/stores/MemoryBrowserRunStore.test.ts): the shared store suites over the memory twins, and a capture that keeps no bytes.
3606
3819
  - [`tests/src/core/validators.test.ts`](../tests/src/core/validators.test.ts): each journey invariant with a failing case, the step, parameter, and edit validators, and the run validator.
3607
3820
  - [`tests/src/core/BrowserDialog.test.ts`](../tests/src/core/BrowserDialog.test.ts): accepting and dismissing a dialog.
@@ -3612,7 +3825,7 @@ The following list names each test file and what it proves.
3612
3825
  - [`tests/src/core/helpers.test.ts`](../tests/src/core/helpers.test.ts): the pure decoders, validators, and renderers of `src/core`, the receipt and outline formats included, the exact-name filter, the journey edits, listing, triggers, secret names, run ids, and run render.
3613
3826
  - [`tests/src/core/errors.test.ts`](../tests/src/core/errors.test.ts): the guard that narrows a caught value to each core error.
3614
3827
  - [`tests/src/browser/BrowserDOMView.test.ts`](../tests/src/browser/BrowserDOMView.test.ts): reading, staleness on the Navigation API, following the window, text waits, and destroy.
3615
- - [`tests/src/browser/BrowserDOMWait.test.ts`](../tests/src/browser/BrowserDOMWait.test.ts): the mutation-parked wait across frames and shadow roots, its deadline, abort, and `pagehide`.
3828
+ - [`tests/src/browser/BrowserDOMWait.test.ts`](../tests/src/browser/BrowserDOMWait.test.ts): the wait parked on mutations and finished transitions and animations across frames and shadow roots, its deadline, abort, and `pagehide`.
3616
3829
  - [`tests/src/browser/elements/BrowserDOMElement.test.ts`](../tests/src/browser/elements/BrowserDOMElement.test.ts): untrusted click, fill, select, and submit, and each refusal they name.
3617
3830
  - [`tests/src/browser/elements/BrowserDOMElementManager.test.ts`](../tests/src/browser/elements/BrowserDOMElementManager.test.ts): the DOM outline, references, bindings, queries, and waits.
3618
3831
  - [`tests/src/browser/factories.test.ts`](../tests/src/browser/factories.test.ts): the in-page factories, the own-document refusal, and the composition with `@orkestrel/mcp`'s bridge over this package's WebMCP double.
@@ -3622,7 +3835,7 @@ The following list names each test file and what it proves.
3622
3835
  - [`tests/src/server/Browser.test.ts`](../tests/src/server/Browser.test.ts): the discover, connect, launch, adopt, disconnect, destroy, and close lifecycle against a spawned stand-in process, the endpoint read from standard error, and the launcher hand-off.
3623
3836
  - [`tests/src/server/helpers.test.ts`](../tests/src/server/helpers.test.ts): system-browser discovery, profiles, the endpoint read, and target fetching.
3624
3837
  - [`tests/src/server/factories.test.ts`](../tests/src/server/factories.test.ts): the server factories against real files and a real in-process CDP endpoint, the file store factories included.
3625
- - [`tests/src/server/BrowserMCPServer.test.ts`](../tests/src/server/BrowserMCPServer.test.ts): the vocabulary before any launch, one launch under concurrent first calls, profiles, forwarding with the signal, `dialog`, mirrored page tools, `readonly`, and teardown on the end of input, `SIGTERM`, and `SIGINT`.
3838
+ - [`tests/src/server/BrowserMCPServer.test.ts`](../tests/src/server/BrowserMCPServer.test.ts): the launch before any request and the vocabulary, the handshake gate, the onset refusal on each surface, the restart bound, failover and its shared acquire, the loss notes and unresolved calls, the sweep and the shutdown recheck, profiles, forwarding with the signal, `dialog`, mirrored page tools, `readonly`, and teardown on the end of input, `SIGTERM`, and `SIGINT`.
3626
3839
  - [`tests/src/server/stores/FileBrowserJourneyStore.test.ts`](../tests/src/server/stores/FileBrowserJourneyStore.test.ts), [`tests/src/server/stores/FileBrowserRunStore.test.ts`](../tests/src/server/stores/FileBrowserRunStore.test.ts), and [`tests/src/server/stores/FileBrowserStore.test.ts`](../tests/src/server/stores/FileBrowserStore.test.ts): the shared store suites and the filesystem suite over the file twins, symbolic links at each component, captures confined to an opened run directory, a failed write, and the lock.
3627
3840
  - [`tests/src/bin/main.test.ts`](../tests/src/bin/main.test.ts): the manifest's `bin.browse`, the built entry spawned with no browser, its exit on the end of input and on `SIGTERM`, and a malformed environment variable.
3628
3841
  - [`tests/src/server/errors.test.ts`](../tests/src/server/errors.test.ts): the guard that narrows a caught value to each server error.