# browser

> A browser on the iii bus - shared Chromium with persistent, restorable tabs and incognito tabs. Navigate, act, read the page console, pick elements. Also parses HTML natively without a browser (browser::* - css/xpath/regex, element search, markdown).

| field | value |
|-------|-------|
| version | 0.2.12 |
| type | binary |
| license | Apache-2.0 |
| repo | https://github.com/iii-hq/workers |
| supported_targets | x86_64-apple-darwin, aarch64-apple-darwin, i686-pc-windows-msvc, x86_64-pc-windows-msvc, aarch64-pc-windows-msvc, x86_64-unknown-linux-gnu, aarch64-unknown-linux-gnu, x86_64-unknown-linux-musl, armv7-unknown-linux-gnueabihf |
| author | iii |

## installation

```sh
iii trigger compose::add worker=browser@0.2.12
```

## readme

# browser

Interactive Chromium sessions on the [iii engine](https://github.com/iii-hq/iii)
bus. Agents start a session, read the page as an accessibility-tree outline,
click and type against element refs, and read the page's own console and
network history back as data. The single most important thing it gives you:
"why is my dev server page blank?" becomes answerable, because the page's
console errors are one `browser::console::read` away. The [console](https://github.com/iii-hq/workers/tree/main/console)
worker adds the human window: a live Browser page with a streaming viewport
(Chromium-pushed screencast frames), the console feed, and click-to-pick
elements into chat.

It also carries a native Rust scraping surface, `browser::*`: HTTP
and browser fetching, screenshots, persistent sessions and BFS crawling, plus
CSS/XPath/regex queries, element search and HTML→Markdown that run over any
HTML string with no browser at all. See
[Scraping and HTML parsing](#scraping-and-html-parsing-browser) below.

## In the console

An agent reads a page as an accessibility outline (`browser::snapshot`) while
you watch the live viewport and console feed:

<a href="https://raw.githubusercontent.com/iii-hq/workers/main/browser/assets/snapshot.png">
  <img src="https://raw.githubusercontent.com/iii-hq/workers/main/browser/assets/snapshot.png" alt="browser::snapshot rendered as an accessibility outline beside the live viewport" width="100%" />
</a>

`browser::screenshot` renders the captured image inline in the chat card:

<a href="https://raw.githubusercontent.com/iii-hq/workers/main/browser/assets/screenshot.png">
  <img src="https://raw.githubusercontent.com/iii-hq/workers/main/browser/assets/screenshot.png" alt="browser::screenshot rendered as an inline image in the chat card" width="100%" />
</a>

Pick mode highlights the element under the cursor and drops it into the chat
composer as an actionable ref:

<a href="https://raw.githubusercontent.com/iii-hq/workers/main/browser/assets/pick.png">
  <img src="https://raw.githubusercontent.com/iii-hq/workers/main/browser/assets/pick.png" alt="pick mode highlighting an element and inserting it into the chat composer" width="100%" />
</a>

## Install

```bash
iii trigger compose::add worker=browser
```

`iii trigger compose::add` resolves the worker and its dependencies, writes
exact declarations to `worker-compose.yaml`, and reconciles the Compose
project. The worker drives a Chromium/Chrome already installed on the
machine; point `executable` at a specific binary if auto-detection picks the
wrong one.

To watch sessions live, pick elements into chat, and follow the agent's
browsing from a UI, add the [console](https://github.com/iii-hq/workers/tree/main/console) worker as well:

```bash
iii trigger compose::add worker=console
```

## Quickstart

Start a session, read the page, act on it, then read the console:

```rust
use iii_sdk::protocol::TriggerRequest;
use iii_sdk::{register_worker, InitOptions};
use serde_json::json;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let iii = register_worker("ws://localhost:49134", InitOptions::default());

    let started = iii.trigger(TriggerRequest {
        function_id: "browser::sessions::start".into(),
        payload: json!({ "url": "http://localhost:3000" }),
        action: None,
        timeout_ms: Some(30_000),
    }).await?;
    let session_id = started["session_id"].as_str().unwrap();

    // The page as text: an a11y outline with [ref=eN] handles.
    let snapshot = iii.trigger(TriggerRequest {
        function_id: "browser::snapshot".into(),
        payload: json!({ "session_id": session_id }),
        action: None,
        timeout_ms: Some(15_000),
    }).await?;
    println!("{}", snapshot["tree"].as_str().unwrap());

    // What did the page log? Errors only, no dump.
    let console = iii.trigger(TriggerRequest {
        function_id: "browser::console::read".into(),
        payload: json!({ "session_id": session_id, "level": "error" }),
        action: None,
        timeout_ms: Some(10_000),
    }).await?;
    println!("{console:#}");
    Ok(())
}
```

The rest of the surface: `browser::act` (click/hover/type/press/scroll by
ref or coordinates, left/right/middle and double-click), `browser::evaluate`
(JS expression), `browser::screenshot` (viewable JPEG), `browser::history`
(back/forward/reload), `browser::history::list` (visited pages for a history
panel), `browser::find-in-page` (find bar: highlight matches, step
next/previous), `browser::zoom` (page zoom 50-200 %), `browser::pdf` (print
the page to a PDF), `browser::downloads::list` / `browser::download` /
`browser::download::remove` (files the session downloaded), `browser::clear-data`
(cookies, cache, storage), `browser::resize` (live viewport size / device
presets), `browser::cookies::list` / `set` / `clear` (import a cookie file),
`browser::network::read` (requests + failures),
`browser::dom::read` (DOM tree with refs), `browser::styles::read` /
`browser::styles::write` (computed styles + live inline edits, the design
panel backing), and `browser::sessions::list` / `browser::sessions::stop`.
Function ids and schemas live in the code and `iii worker info browser`.

File transfer functions:

| Function | Purpose |
|---|---|
| `browser::downloads::list` | List files the session downloaded |
| `browser::download` | Read one recorded download as base64 |
| `browser::download::remove` | Delete and forget one recorded download |
| `browser::upload` | Attach up to eight base64 files to exactly one `input[type=file]` selected by CSS |

Beyond single actions: `browser::execute` runs a multi-step async script in
the page — top-level await, `log(...)`, `sleep(ms)`, `waitFor(selector)`, and
a `state` object that persists across execute calls for the session — so one
call replaces a chain of act/evaluate round-trips. `browser::snapshot`
accepts `diff: true` to return only what changed since the previous
snapshot, and reports the document `generation` its refs belong to (ref
names are unique per snapshot and fail closed when stale, never resolving to
a different element). `browser::sessions::start` accepts `read_only: true`
for inspection-only sessions where act/evaluate/execute/styles::write are
rejected. `browser::doctor` reports the environment — detected Chromium,
version, capacity — with an `enable_how` string for anything degraded.

`browser::sessions::attach` binds a session to an already-running browser
over CDP (start Chrome with `--remote-debugging-port`) instead of launching
one, so it reaches the real profile with its logins and extensions. It opens
a fresh tab the session owns, or adopts an existing tab by URL substring and
releases it untouched on stop; `browser::tabs::list` enumerates a running
browser's tabs. Attach reaches logged-in state, so it is off unless
`allow_attach` is set in config, and adoption is exclusive per tab.

`browser::handoff` pauses a session for a step only a human can do (CAPTCHA,
2FA, payment): it mounts an in-page continue banner and blocks the call until
the human clicks it, a `browser::handoff::confirm` call resolves it, or the
timeout elapses, emitting `browser::handoff-requested` for the console to
surface. Human acknowledgment is not proof, so the caller verifies the
expected page state after it returns.

`browser::recording::start` / `browser::recording::stop` capture a session's
live viewport to a webm or mp4 file by piping the screencast through ffmpeg
(turning screencast on if needed); stop returns the path, duration, and
frame count. While screencast is active a human watching the viewport also
sees a ghost cursor following the agent's clicks and a session-status badge;
both are fixed-position in-page overlays that never touch page content.
`browser::doctor` reports whether ffmpeg (recording) and attach mode are
available.

## Scraping and HTML parsing (`browser::*`)

The worker also ships a native Rust port of the [scrapling](https://github.com/D4Vinci/Scrapling)
worker's surface: 19 functions covering HTTP and browser fetching, screenshots,
persistent sessions, crawling, and — the part that needs no browser at all —
parsing HTML you already have.

Start with the parse functions: they work on any HTML string with no browser
or network. Adaptive CSS/XPath/extract calls are the exception to statelessness:
they persist relocation identities in the configured SQLite database. They pair naturally with the session functions above
(navigate, read the page, then parse it), but they don't need one.

```bash
iii trigger browser::css --payload '{
  "html": "<ul><li><a class=\"product\" href=\"/sku/1\">Widget</a></li><li><a class=\"product\" href=\"/sku/2\">Gadget</a></li></ul>",
  "query": "a.product",
  "attr": "href",
  "first": true
}'
# → { "result": "/sku/1" }
```

`first` defaults to `false`, in which case `result` is an array of every match
instead of just the first.

```bash
iii trigger browser::extract --payload '{
  "html": "<div class=\"card\"><h3>Widget</h3><span class=\"price\">$19.99</span><a href=\"/sku/1\">buy</a></div>",
  "selectors": [
    { "name": "title", "css": "h3" },
    { "name": "price", "css": ".price" },
    { "name": "url", "css": "a", "attr": "href" }
  ]
}'
# → { "extracted": { "title": "Widget", "price": "$19.99", "url": "/sku/1" } }
```

The 10 parse functions: `extract`, `css`, `xpath`, `regex`, `find`,
`find-by-text`, `find-by-regex`, `find-similar`, `describe`, `to-markdown`.
Non-adaptive parsing has no operator-tunable defaults. The fixed limit,
`find` / `find-by-text` / `find-by-regex` capping
at 100 items per call (`limit` clamps to `[0, 100]`), mirrors the python
worker's hardcoded cap.

### Fetching, sessions and crawl

Nine more functions go out to the network. They share one response envelope —
`{status, url, headers, cookies, encoding}` plus, on request, `extracted`
(from `selectors`), `content`+`format` (`markdown`/`text`) and `html` — so the
parse layer above is reachable inline, without a second call.

Three fetch tiers, cheapest first; escalate only when the cheaper one fails:

| | engine | use when |
|---|---|---|
| `fetch` | safe: reqwest/rustls; compat: frozen curl-impersonate | static pages, APIs — no browser, fastest |
| `dynamic-fetch` | frozen Chrome over raw CDP | the page needs JavaScript to render |
| `stealthy-fetch` | frozen Chrome with the Patchright command/launch sequence | the site sniffs for automation |

```bash
iii trigger browser::fetch --json '{
  "url": "https://example.com/",
  "selectors": [{ "name": "title", "css": "h1" }],
  "format": "text"
}'
# → { "status": 200, "url": "...", "extracted": { "title": "Example Domain" }, ... }
```

All three take a single `url` or a bulk `urls` list (bulk returns
`{results: [...]}`, where a failed URL contributes `{url, error}` instead of
sinking the batch). `dynamic-fetch` and `stealthy-fetch` additionally accept
`wait_selector` (+ `wait_selector_state`), `network_idle`, and `wait`.

`browser::screenshot-url` captures a page as image content blocks the console renders
inline — downscaled to 1024px wide and split into at most six 1536px tiles,
with the caption saying so when a page is taller than that.

`session-open` / `session-fetch` / `session-close` / `session-list` keep state
in a private Scrapling registry. HTTP sessions retain one cookie jar/transport;
dynamic and stealthy sessions retain one browser process and context. All use
UUID4 hex ids and serialize requests FIFO per session. They never appear in
`browser::sessions::list`, and interactive ids are not accepted. One-shot
browser calls get a fresh process/profile; retries get a fresh page in that
process. Compat mode supports request proxies, remote `cdp_url`, and
`solve_cloudflare` on stealthy calls.

`crawl` walks links breadth-first from `start_urls`, extracting per page. It
stays on the seed domain by default (`www.` folded), strips URL fragments when
deduping, and stops at `max_pages` (20) or `max_depth` (2). Every page is
emitted on a stream; the RPC response carries only a ≤10-item sample plus the
stream name and group id to read the rest with `stream::on`.

**These functions take a caller-supplied URL, so they are an SSRF surface.**
Safe mode rejects caller proxies and checks every connection against private,
loopback, link-local (including cloud metadata), CGNAT, multicast and reserved
ranges. Set `browser.scrapling.allow_loopback: true` to scrape a local dev
server; every other private range stays blocked. Compat mode intentionally
reproduces the standalone worker's unrestricted network behavior and should be
enabled only for trusted calls. All nine functions remain at the
`needs_approval` default in `iii-permissions.yaml`, unlike the ten parse
functions.

The guarantee differs by tier, and the difference is worth knowing:

- **`fetch` (HTTP) — checked before every hop.** Redirects are followed by
  hand precisely so each hop is validated *before* the request is made, and
  each connection is pinned to the address that was validated, closing the DNS
  rebinding window between check and connect. `Authorization` and `Cookie` are
  dropped on a cross-origin redirect, as curl has done since CVE-2018-1000007.
- **Browser tiers — checked at the socket boundary.** Safe-mode Chrome is
  forced through an in-process HTTP/CONNECT gate. The gate resolves, checks,
  and pins every destination before dialing, including redirect destinations;
  direct bypass, QUIC and WebRTC are disabled.

Two more safe-mode limits worth stating: response bodies are bounded at 32 MiB
whether or not the server declares a content length, and a `fetch` call is
capped at three times its `timeout` in total. Compat mode preserves the frozen
worker's unbounded response and retry/redirect quirks.

### Compatibility modes and certification

Request/response schemas are golden-pinned to the frozen Python wrapper apart
from provider-id mapping. Native calls use `browser::<leaf>`; Python keeps
`scrapling::<leaf>`. Python `scrapling::screenshot` maps to native
`browser::screenshot-url`, while `browser::screenshot` remains the interactive
session screenshot. Crawl streams default to `browser::crawl`.

`security_mode: safe` is the default. It keeps SSRF checks and resource
ceilings, refuses network options the safe engine cannot enforce, rejects
`verify: false`, and bounds adaptive storage. `security_mode: compat` is only
eligible on Tier-1 Linux x86_64/aarch64 builds produced with the certified
curl-impersonate and Chromium artifacts. Other targets reject compat instead
of silently degrading. Eligibility is not a claim that an arbitrary local
build is certified: builds without the frozen artifacts return a capability
error, and callers should keep using safe mode or the standalone worker.

The parser/query core, CSS-to-XPath translation, XPath 1.0 evaluation, Python
regex behavior, Markdown conversion, selector generation, and adaptive
relocation are repository-owned compatibility implementations covered by
exact differential fixtures. Adaptive queries persist element identities in
SQLite at `adaptive_storage_path`; parse functions remain auto-allowed, so
operators should treat that path as durable worker state. Safe mode enforces
`adaptive_max_bytes` (256 MiB by default) and rolls back a write that would
exceed it. Compat mode keeps the frozen worker's unbounded behavior.

Safe HTTP uses the bounded native engine. Compat HTTP is linked to the frozen
curl-impersonate archive; compat browser calls use the certified Chrome build
through raw pipe/WebSocket CDP and reproduce the frozen Playwright/Patchright
sequences. Persistent browser sessions, proxy rotation, remote CDP,
Cloudflare handling and screenshot transforms use that same private runtime.
Certified builds fail when pinned artifacts are absent or mismatched; there is
no silent fallback from compat to safe.

The standalone worker remains the oracle and production fallback during
rollout. Migrate calls to `browser::<leaf>` (with screenshot mapped to
`browser::screenshot-url`) only after draining its sessions, then compare both
providers through one stable release and at least 30 days without an
untriaged mismatch. Removing the standalone worker is a separate change.

### Regenerating the parse goldens

`tests/golden/schemas/browser.*.json` and `tests/golden/behavior/**`
are written **only** by `scripts/gen_goldens.py`, run against the reference
Python implementation — never by `UPDATE_GOLDENS=1`, so a passing test always
means "Rust still agrees with Python":

```bash
~/.iii/managed/scrapling/usr/local/bin/python3.12 scripts/gen_goldens.py schemas
~/.iii/managed/scrapling/usr/local/bin/python3.12 scripts/gen_goldens.py behavior
```

## Configuration

Stored in the `configuration` worker under the `browser` key. Existing
interactive-browser settings retain their current behavior. Scrapling settings
live in an isolated nested block: bulk/default policy can be read per call,
while the session cap, idle timeout, and adaptive database path are snapshotted
at worker startup. Restart after changing a startup-snapshotted value.

```yaml
browser:
  executable: ''            # empty = auto-detect Chrome/Chromium/Edge
  user_data_dir: ''         # set a path to persist cookies/logins across sessions
  headless: true            # false shows a real window locally
  max_sessions: 4           # concurrent Chromium processes
  console_buffer: 500       # per-session console ring buffer (entries)
  network_buffer: 500       # per-session network ring buffer (entries)
  viewport_width: 1280
  viewport_height: 800
  default_timeout_ms: 30000 # navigation/act/evaluate default
  max_timeout_ms: 120000    # ceiling; caller timeout_ms clamped DOWN to this
  idle_stop_ms: 300000      # stop sessions idle this long; 0 disables
  screenshot_quality: 60    # JPEG quality 1-100
  allowed_schemes: [http, https, file]  # `file` lets a local document be rendered; see below
  max_snapshot_nodes: 2000  # a11y outline size cap
  default_origin_policy:    # omitted fields default to allow
    access: allow
    downloads: allow
    uploads: allow
    scripting: allow
  origin_policies:
    'https://app.example.com:8443':
      uploads: deny
    app.example.com:
      scripting: deny
  allow_history_access: true
  allow_cookie_import: true
  allow_attach: false       # true = allow sessions::attach into a running browser's real profile

  scrapling:
    security_mode: safe        # safe | compat; compat is Tier-1 certified builds only
    chromium_executable: ''    # certified Chrome path; empty = discovery
    allow_loopback: false      # true = permit 127.0.0.1 / ::1 in outbound calls

    defaults:
      impersonate: chrome
      headless: true
      network_idle: false
      proxy: ''
      include_html: false

    max_bulk_concurrency: 5
    max_sessions: 8
    session_idle_timeout_s: 900
    adaptive_storage_path: data/scrapling/elements.db # relative to III_COMPOSE_DIR
    adaptive_max_bytes: 268435456 # safe only; compat preserves unbounded oracle behavior
```

`file` is on the default scheme list so a local document can be opened and
rendered, which is how `document::ocr` gets pixels out of a scanned PDF. It is
worth knowing what that permits: navigation is not checked against a session's
filesystem scope the way the workers that read files directly are, so anything
that can reach `browser::navigate` can open any file this process can read.
Narrow the list on a shared machine.

Origin policy keys do not accept wildcards. An exact origin, including its
scheme and non-default port, wins over a bare host; a bare host matches any
scheme or port. Origin keys are URL-normalized before matching, including
lowercased hosts and removal of explicit default ports; bare-host keys match
case-insensitively. URLs with no matching key use `default_origin_policy`.
Each policy field defaults to `allow` when omitted.

Sessions started while any origin policy is configured reload the policy on
every top-document request, so edits apply to their later navigations. A
session started with no origin policy does not enable interception; adding the
first policy later applies the navigation gate to new sessions.

The compatibility fields are part of the stable configuration surface.
Non-Tier-1 or artifact-free builds retain safe mode and reject compat
explicitly instead of approximating it.

The declared production envelope is 4 GiB memory and 2 CPUs. Tier-1 release
validation budgets for five concurrent browser processes; that is a release
test envelope, not permission to exceed configured session caps.

## Custom trigger types

Sibling workers (and the console UI) can subscribe to session activity. All
bindings accept an optional `{ "session_id": "..." }` filter.

| Trigger type | Fires when | Payload to subscribers |
|---|---|---|
| `browser::session-started` | A session is up and ready | `{ session_id, url, headless, timestamp }` |
| `browser::session-stopped` | A session ended | `{ session_id, reason: "stopped" \| "idle" \| "crashed", timestamp }` |
| `browser::navigated` | The page committed a navigation | `{ session_id, url, timestamp }` |
| `browser::console-event` | A console/log/exception entry was captured | `{ session_id, entry }` |
| `browser::picked` | The human picked an element in inspect mode | `{ session_id, element, timestamp }` |
| `browser::handoff-requested` | A session paused for a human step (CAPTCHA, 2FA, payment) | `{ session_id, handoff_id, instructions, timestamp }` |

`browser::console-event` is high-volume; bind it with a `session_id` filter
and treat `browser::console::read` as the durable record. `browser::picked`
elements carry a `ref` that `browser::act` accepts directly, so a human pick
flows straight into agent action.

## Element picking

`browser::pick::start` puts the page in DevTools inspect mode (native hover
highlight); the human's click resolves to tag, attributes, outer HTML, text,
bounds, and recent console errors, emitted as `browser::picked`. The pick,
hint, screencast, and frame functions are internal: console-UI plumbing, not
agent surface, and they stay out of agent tool lists.

## api reference

```json
{
  "functions": [
    {
      "description": "Interact with the page: click (left/right/middle, single or double), hover, type, press, scroll, or drag (press at the start point, glide to x2/y2, release). Address elements with a [ref=eN] handle from browser::snapshot (or a pick), or raw viewport coordinates.",
      "metadata": {},
      "name": "browser::act",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "action": {
            "description": "`click`, `hover`, `type`, `press`, `scroll`, or `drag`.",
            "type": "string"
          },
          "button": {
            "default": null,
            "description": "Mouse button for `click`: `left` (default), `right`, or `middle`.",
            "type": [
              "string",
              "null"
            ]
          },
          "click_count": {
            "default": null,
            "description": "Clicks in the gesture: 2 double-clicks (`click` only, default 1).",
            "format": "uint32",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "delta_y": {
            "default": null,
            "description": "Scroll distance in pixels; positive scrolls down (`scroll`).",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "key": {
            "default": null,
            "description": "Key name for `press`: Enter, Tab, Escape, Backspace, Delete, ArrowUp/Down/Left/Right, Home, End, PageUp, PageDown.",
            "type": [
              "string",
              "null"
            ]
          },
          "ref": {
            "default": null,
            "description": "Element ref from `browser::snapshot` (`e3`) or `browser::picked` (`p1`). Refs die on navigation; re-snapshot after.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "text": {
            "default": null,
            "description": "Text to insert (`type`).",
            "type": [
              "string",
              "null"
            ]
          },
          "x": {
            "default": null,
            "description": "Viewport x, when acting by coordinates instead of ref.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "x2": {
            "default": null,
            "description": "Drag end x, in viewport pixels (`drag`). The start is `x`/`y` or a `ref`; the end is `x2`/`y2`.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "y": {
            "default": null,
            "description": "Viewport y, when acting by coordinates instead of ref.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "y2": {
            "default": null,
            "description": "Drag end y, in viewport pixels (`drag`).",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          }
        },
        "required": [
          "action",
          "session_id"
        ],
        "title": "ActInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "detail": {
            "description": "What was done, for the transcript.",
            "type": "string"
          },
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "detail",
          "ok"
        ],
        "title": "ActOutput",
        "type": "object"
      }
    },
    {
      "description": "Clear the session's browsing data (cookies, cache, storage), like the browser's Clear browsing data. Scoped to this session's browser context.",
      "metadata": {},
      "name": "browser::clear-data",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "cache": {
            "default": null,
            "description": "Clear the HTTP cache. Default true.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "cookies": {
            "default": null,
            "description": "Clear cookies. Default true.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "storage": {
            "default": null,
            "description": "Clear localStorage / sessionStorage / IndexedDB for the current origin. Default true.",
            "type": [
              "boolean",
              "null"
            ]
          }
        },
        "required": [
          "session_id"
        ],
        "title": "ClearDataInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "cleared": {
            "description": "What was cleared, for the confirmation message.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "cleared",
          "ok"
        ],
        "title": "ClearDataOutput",
        "type": "object"
      }
    },
    {
      "description": "Read the session's captured console: console.* calls, uncaught exceptions, and browser-level log entries. Filter with pattern/level and page with since_seq instead of dumping everything.",
      "metadata": {},
      "name": "browser::console::read",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "level": {
            "default": null,
            "description": "Only entries at this level: `log`, `info`, `warning`, `error`, `debug`, `exception`. `error` also matches `exception`.",
            "type": [
              "string",
              "null"
            ]
          },
          "limit": {
            "default": null,
            "description": "Maximum entries returned, newest kept (default 100).",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "pattern": {
            "default": null,
            "description": "Regex applied to entry text. Use it: dumping an unfiltered console wastes the caller's context.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "since_seq": {
            "default": null,
            "description": "Only entries with `seq` greater than this; resume from the cursor returned as `last_seq`.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "session_id"
        ],
        "title": "ConsoleReadInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "ConsoleEntry": {
            "description": "One captured console/log/exception entry.",
            "properties": {
              "level": {
                "description": "`log`, `info`, `warning`, `error`, `debug`, or `exception`.",
                "type": "string"
              },
              "seq": {
                "description": "Monotonic per-session cursor; pass back as `since_seq`.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "source": {
                "description": "`url:line` of the emitting frame, when known.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "text": {
                "type": "string"
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              }
            },
            "required": [
              "level",
              "seq",
              "text",
              "timestamp"
            ],
            "type": "object"
          }
        },
        "properties": {
          "dropped": {
            "description": "Entries evicted from the ring buffer since session start.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "entries": {
            "items": {
              "$ref": "#/definitions/ConsoleEntry"
            },
            "type": "array"
          },
          "last_seq": {
            "description": "Cursor for the next `since_seq`.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "dropped",
          "entries",
          "last_seq"
        ],
        "title": "ConsoleReadOutput",
        "type": "object"
      }
    },
    {
      "description": "Clear all of the session's cookies.",
      "metadata": {},
      "name": "browser::cookies::clear",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "CookiesClearInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "CookiesClearOutput",
        "type": "object"
      }
    },
    {
      "description": "The cookies visible to the session's current page (name, value, domain, path, flags).",
      "metadata": {},
      "name": "browser::cookies::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "CookiesListInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "CookieSpec": {
            "description": "One cookie as read from or written to the session. A subset of the CDP cookie shape: what a person setting a cookie actually provides.",
            "properties": {
              "domain": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "expires": {
                "description": "Seconds since the Unix epoch; omitted for a session cookie.",
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "http_only": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "path": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "same_site": {
                "description": "`Strict`, `Lax`, or `None`.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "secure": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "value": {
                "type": "string"
              }
            },
            "required": [
              "name",
              "value"
            ],
            "type": "object"
          }
        },
        "properties": {
          "cookies": {
            "items": {
              "$ref": "#/definitions/CookieSpec"
            },
            "type": "array"
          }
        },
        "required": [
          "cookies"
        ],
        "title": "CookiesListOutput",
        "type": "object"
      }
    },
    {
      "description": "Set cookies on the session, like importing a cookie file. A cookie without a domain is scoped to the current page's URL. same_site is Strict, Lax, or None.",
      "metadata": {},
      "name": "browser::cookies::set",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "CookieSpec": {
            "description": "One cookie as read from or written to the session. A subset of the CDP cookie shape: what a person setting a cookie actually provides.",
            "properties": {
              "domain": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "expires": {
                "description": "Seconds since the Unix epoch; omitted for a session cookie.",
                "format": "double",
                "type": [
                  "number",
                  "null"
                ]
              },
              "http_only": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "path": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "same_site": {
                "description": "`Strict`, `Lax`, or `None`.",
                "type": [
                  "string",
                  "null"
                ]
              },
              "secure": {
                "type": [
                  "boolean",
                  "null"
                ]
              },
              "value": {
                "type": "string"
              }
            },
            "required": [
              "name",
              "value"
            ],
            "type": "object"
          }
        },
        "properties": {
          "cookies": {
            "description": "Cookies to set. A cookie without a domain is scoped to the current page's URL.",
            "items": {
              "$ref": "#/definitions/CookieSpec"
            },
            "type": "array"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "cookies",
          "session_id"
        ],
        "title": "CookiesSetInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "count": {
            "description": "How many cookies were sent.",
            "format": "uint",
            "minimum": 0,
            "type": "integer"
          },
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "count",
          "ok"
        ],
        "title": "CookiesSetOutput",
        "type": "object"
      }
    },
    {
      "description": "BFS-crawl from start_urls (follow same-domain links), extract per page, stream items.",
      "metadata": {},
      "name": "browser::crawl",
      "request_schema": {
        "properties": {
          "allowed_domains": {
            "description": "only follow links on these hosts",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "concurrency": {
            "type": "integer"
          },
          "css_selector": {
            "description": "scope the render to this CSS subtree (e.g. a page's content div)",
            "type": "string"
          },
          "download_delay": {
            "description": "seconds to wait between crawl rounds",
            "type": "number"
          },
          "fetcher": {
            "enum": [
              "http",
              "stealthy",
              "dynamic"
            ],
            "type": "string"
          },
          "format": {
            "description": "render page body to this format",
            "enum": [
              "markdown",
              "text"
            ],
            "type": "string"
          },
          "impersonate": {
            "type": "string"
          },
          "include_html": {
            "type": "boolean"
          },
          "main_content_only": {
            "description": "strip nav/scripts/hidden before rendering",
            "type": "boolean"
          },
          "max_depth": {
            "type": "integer"
          },
          "max_pages": {
            "type": "integer"
          },
          "same_domain": {
            "description": "follow only same-host links (default true)",
            "type": "boolean"
          },
          "selectors": {
            "items": {
              "properties": {
                "all": {
                  "description": "return every match as a list",
                  "type": "boolean"
                },
                "attr": {
                  "description": "extract this attribute instead of text",
                  "type": "string"
                },
                "css": {
                  "type": "string"
                },
                "html": {
                  "description": "extract inner HTML instead of text",
                  "type": "boolean"
                },
                "name": {
                  "type": "string"
                },
                "regex": {
                  "type": "string"
                },
                "xpath": {
                  "type": "string"
                }
              },
              "required": [
                "name"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "start_urls": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "stream_name": {
            "description": "stream to emit items on (default browser::crawl)",
            "type": "string"
          },
          "url": {
            "description": "single start URL (alternative to start_urls)",
            "type": "string"
          }
        },
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "items": {
            "description": "a small sample of streamed items",
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "stats": {
            "properties": {
              "crawled": {
                "type": "integer"
              },
              "errors": {
                "type": "integer"
              },
              "items": {
                "type": "integer"
              },
              "stopped": {
                "type": "string"
              }
            },
            "type": "object"
          },
          "stream": {
            "description": "read the full item stream via stream::on with this name + group_id",
            "properties": {
              "group_id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            },
            "type": "object"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "One CSS query over HTML; first-or-all; `attr` pulls an attribute else text.",
      "metadata": {},
      "name": "browser::css",
      "request_schema": {
        "properties": {
          "adaptive": {
            "description": "relocate elements after a site change via saved identities",
            "type": "boolean"
          },
          "adaptive_domain": {
            "description": "page URL/domain that keys saved identities",
            "type": "string"
          },
          "attr": {
            "type": "string"
          },
          "auto_save": {
            "description": "save matched identities (defaults on when adaptive)",
            "type": "boolean"
          },
          "first": {
            "type": "boolean"
          },
          "html": {
            "type": "string"
          },
          "identifier": {
            "description": "stable key for the saved element",
            "type": "string"
          },
          "query": {
            "type": "string"
          }
        },
        "required": [
          "html",
          "query"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "result": {
            "items": {
              "type": [
                "string",
                "null"
              ]
            },
            "type": [
              "array",
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Describe the first css/xpath match: attrs, generated selectors, class list, DOM context.",
      "metadata": {},
      "name": "browser::describe",
      "request_schema": {
        "properties": {
          "html": {
            "type": "string"
          },
          "kind": {
            "enum": [
              "css",
              "xpath"
            ],
            "type": "string"
          },
          "query": {
            "type": "string"
          }
        },
        "required": [
          "html",
          "query"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "element": {
            "properties": {
              "attrs": {
                "type": "object"
              },
              "children": {
                "type": "integer"
              },
              "classes": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "css": {
                "type": "string"
              },
              "full_css": {
                "type": "string"
              },
              "full_xpath": {
                "type": "string"
              },
              "html": {
                "type": "string"
              },
              "parent_tag": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "siblings": {
                "type": "integer"
              },
              "tag": {
                "type": "string"
              },
              "text": {
                "type": "string"
              },
              "xpath": {
                "type": "string"
              }
            },
            "type": "object"
          },
          "found": {
            "type": "boolean"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Read-only environment diagnostics: which Chromium the worker would launch, its version, session capacity, and any degraded capability with how to enable it. Never starts a browser.",
      "metadata": {},
      "name": "browser::doctor",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "DoctorInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "DoctorIssue": {
            "description": "One degraded capability plus the way to enable it.",
            "properties": {
              "enable_how": {
                "type": "string"
              },
              "what": {
                "type": "string"
              }
            },
            "required": [
              "enable_how",
              "what"
            ],
            "type": "object"
          }
        },
        "properties": {
          "active_sessions": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "allow_cookie_import": {
            "type": "boolean"
          },
          "allow_history_access": {
            "type": "boolean"
          },
          "allowed_schemes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "attach_enabled": {
            "description": "Whether attach mode is enabled (allow_attach).",
            "type": "boolean"
          },
          "chromium_path": {
            "type": [
              "string",
              "null"
            ]
          },
          "chromium_version": {
            "type": [
              "string",
              "null"
            ]
          },
          "configured_origin_policies": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "default_origin_policy_set": {
            "type": "boolean"
          },
          "headless_default": {
            "type": "boolean"
          },
          "issues": {
            "items": {
              "$ref": "#/definitions/DoctorIssue"
            },
            "type": "array"
          },
          "max_sessions": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "ok": {
            "description": "True when sessions can start right now.",
            "type": "boolean"
          },
          "recording_available": {
            "description": "Whether ffmpeg is on PATH, which browser::recording requires.",
            "type": "boolean"
          }
        },
        "required": [
          "active_sessions",
          "allow_cookie_import",
          "allow_history_access",
          "allowed_schemes",
          "attach_enabled",
          "configured_origin_policies",
          "default_origin_policy_set",
          "headless_default",
          "issues",
          "max_sessions",
          "ok",
          "recording_available"
        ],
        "title": "DoctorOutput",
        "type": "object"
      }
    },
    {
      "description": "Read the DOM as a tree of tags with id/class and refs. Structure-oriented complement to browser::snapshot; read deep subtrees by passing a ref.",
      "metadata": {},
      "name": "browser::dom::read",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "depth": {
            "default": null,
            "description": "Levels of children to include (default 3).",
            "format": "uint32",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "ref": {
            "default": null,
            "description": "Subtree root from an earlier ref (`e3`/`p1`) or dom node. Omit for the document root.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "DomReadInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "DomNode": {
            "description": "One DOM node in the outline. `ref` resolves in `browser::act`, `browser::styles::read`, and `browser::styles::write`.",
            "properties": {
              "child_count": {
                "description": "Total children in the document, which may exceed `children` returned at this depth.",
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "children": {
                "items": {
                  "$ref": "#/definitions/DomNode"
                },
                "type": "array"
              },
              "classes": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "ref": {
                "type": "string"
              },
              "tag": {
                "description": "Lowercase tag (`div`, `button`) or node name (`#text`).",
                "type": "string"
              },
              "text": {
                "description": "Trimmed text content for text nodes.",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "child_count",
              "ref",
              "tag"
            ],
            "type": "object"
          }
        },
        "properties": {
          "root": {
            "$ref": "#/definitions/DomNode"
          },
          "truncated": {
            "description": "True when the node cap cut the tree short; read a subtree via `ref`.",
            "type": "boolean"
          }
        },
        "required": [
          "root",
          "truncated"
        ],
        "title": "DomReadOutput",
        "type": "object"
      }
    },
    {
      "description": "Read one downloaded file's bytes by guid (from browser::downloads::list), base64, for saving or attaching to the chat.",
      "metadata": {},
      "name": "browser::download",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "guid": {
            "description": "The download's CDP guid, from `browser::downloads::list`.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "guid",
          "session_id"
        ],
        "title": "DownloadInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "data": {
            "description": "The file, base64.",
            "type": "string"
          },
          "file_name": {
            "type": "string"
          },
          "ok": {
            "type": "boolean"
          },
          "size_bytes": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "data",
          "file_name",
          "ok",
          "size_bytes"
        ],
        "title": "DownloadOutput",
        "type": "object"
      }
    },
    {
      "description": "Forget a download and delete its file from the session's download dir.",
      "metadata": {},
      "name": "browser::download::remove",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "guid": {
            "description": "The download to forget, and delete from disk.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "guid",
          "session_id"
        ],
        "title": "DownloadRemoveInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "DownloadRemoveOutput",
        "type": "object"
      }
    },
    {
      "description": "The files this session downloaded (name, url, size, state), newest first. Downloads are allowed and named per session; read one with browser::download.",
      "metadata": {},
      "name": "browser::downloads::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "DownloadsListInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "DownloadRecord": {
            "description": "A download Chromium started, tracked by its CDP guid.",
            "properties": {
              "file_name": {
                "type": "string"
              },
              "guid": {
                "type": "string"
              },
              "received_bytes": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "started_ms": {
                "format": "int64",
                "type": "integer"
              },
              "state": {
                "description": "`in_progress`, `completed`, or `canceled`.",
                "type": "string"
              },
              "total_bytes": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "url": {
                "type": "string"
              }
            },
            "required": [
              "file_name",
              "guid",
              "received_bytes",
              "started_ms",
              "state",
              "total_bytes",
              "url"
            ],
            "type": "object"
          }
        },
        "properties": {
          "downloads": {
            "description": "Newest first.",
            "items": {
              "$ref": "#/definitions/DownloadRecord"
            },
            "type": "array"
          }
        },
        "required": [
          "downloads"
        ],
        "title": "DownloadsListOutput",
        "type": "object"
      }
    },
    {
      "description": "Playwright/Chromium fetch: JS render, waits, XHR capture, CDP; extraction + bulk.",
      "metadata": {},
      "name": "browser::dynamic-fetch",
      "request_schema": {
        "properties": {
          "block_ads": {
            "type": "boolean"
          },
          "blocked_domains": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "capture_xhr": {
            "type": "string"
          },
          "cdp_url": {
            "type": "string"
          },
          "cookies": {
            "type": "object"
          },
          "css_selector": {
            "description": "scope the render to this CSS subtree (e.g. a page's content div)",
            "type": "string"
          },
          "disable_resources": {
            "type": "boolean"
          },
          "dns_over_https": {
            "type": "boolean"
          },
          "extra_flags": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "extra_headers": {
            "type": "object"
          },
          "format": {
            "description": "render page body to this format",
            "enum": [
              "markdown",
              "text"
            ],
            "type": "string"
          },
          "google_search": {
            "type": "boolean"
          },
          "headless": {
            "type": "boolean"
          },
          "include_html": {
            "type": "boolean"
          },
          "load_dom": {
            "type": "boolean"
          },
          "locale": {
            "type": "string"
          },
          "main_content_only": {
            "description": "strip nav/scripts/hidden before rendering",
            "type": "boolean"
          },
          "max_pages": {
            "type": "integer"
          },
          "network_idle": {
            "type": "boolean"
          },
          "proxy": {
            "type": "string"
          },
          "real_chrome": {
            "type": "boolean"
          },
          "retries": {
            "type": "integer"
          },
          "retry_delay": {
            "type": "number"
          },
          "selectors": {
            "items": {
              "properties": {
                "all": {
                  "description": "return every match as a list",
                  "type": "boolean"
                },
                "attr": {
                  "description": "extract this attribute instead of text",
                  "type": "string"
                },
                "css": {
                  "type": "string"
                },
                "html": {
                  "description": "extract inner HTML instead of text",
                  "type": "boolean"
                },
                "name": {
                  "type": "string"
                },
                "regex": {
                  "type": "string"
                },
                "xpath": {
                  "type": "string"
                }
              },
              "required": [
                "name"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "timeout": {
            "description": "milliseconds (browser fetcher)",
            "type": "number"
          },
          "timezone_id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "urls": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "useragent": {
            "type": "string"
          },
          "wait": {
            "description": "extra ms to wait after load",
            "type": "number"
          },
          "wait_selector": {
            "type": "string"
          },
          "wait_selector_state": {
            "enum": [
              "attached",
              "detached",
              "visible",
              "hidden"
            ],
            "type": "string"
          }
        },
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "captured_xhr": {
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "content": {
            "description": "markdown/text render when `format` requested",
            "type": "string"
          },
          "cookies": {
            "type": "object"
          },
          "encoding": {
            "type": [
              "string",
              "null"
            ]
          },
          "error": {
            "type": "string"
          },
          "extracted": {
            "type": "object"
          },
          "format": {
            "type": "string"
          },
          "headers": {
            "type": "object"
          },
          "html": {
            "type": "string"
          },
          "results": {
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "status": {
            "type": [
              "integer",
              "null"
            ]
          },
          "url": {
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Evaluate a JavaScript expression in the page and return its completion value. Use for reads the snapshot can't express; prefer browser::act for interactions.",
      "metadata": {},
      "name": "browser::evaluate",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "expression": {
            "description": "JavaScript expression evaluated in the page. The completion value is returned by value; wrap statements in an IIFE.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          },
          "timeout_ms": {
            "default": null,
            "description": "Upper bound on evaluation; clamped to `max_timeout_ms`.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "expression",
          "session_id"
        ],
        "title": "EvaluateInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "error": {
            "description": "Exception text when not `ok`.",
            "type": [
              "string",
              "null"
            ]
          },
          "ok": {
            "type": "boolean"
          },
          "value": {
            "description": "JSON completion value when `ok`."
          }
        },
        "required": [
          "ok"
        ],
        "title": "EvaluateOutput",
        "type": "object"
      }
    },
    {
      "description": "Run a multi-step async JavaScript script in the page: top-level await and return work, with log(...), sleep(ms), waitFor(selector), and a state object that persists across execute calls for the session. One call replaces a chain of act/evaluate round-trips; returns { result, logs, state }.",
      "metadata": {},
      "name": "browser::execute",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "code": {
            "description": "Async JavaScript body run in the page; `state`, `log(...)`, `sleep(ms)` and `waitFor(selector, { timeout })` are in scope. Return plain JSON.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          },
          "timeout_ms": {
            "default": null,
            "description": "Upper bound on the run; clamped to `max_timeout_ms`.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "code",
          "session_id"
        ],
        "title": "ExecuteInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "error": {
            "description": "Exception text when not `ok`. A \"context destroyed\" error usually means the script navigated; split the script at the navigation.",
            "type": [
              "string",
              "null"
            ]
          },
          "logs": {
            "description": "`log(...)` output collected during the run, in order.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "ok": {
            "type": "boolean"
          },
          "result": {
            "description": "The script's return value when `ok`."
          },
          "state": {
            "description": "Session state after the run; the next execute call sees this as `state`."
          }
        },
        "required": [
          "logs",
          "ok",
          "state"
        ],
        "title": "ExecuteOutput",
        "type": "object"
      }
    },
    {
      "description": "Parse HTML with a selector list (css/xpath/regex, text/attr/html, all-or-first).",
      "metadata": {},
      "name": "browser::extract",
      "request_schema": {
        "properties": {
          "adaptive": {
            "description": "relocate elements after a site change via saved identities",
            "type": "boolean"
          },
          "adaptive_domain": {
            "description": "page URL/domain that keys saved identities",
            "type": "string"
          },
          "auto_save": {
            "description": "save matched identities (defaults on when adaptive)",
            "type": "boolean"
          },
          "html": {
            "type": "string"
          },
          "selectors": {
            "items": {
              "properties": {
                "all": {
                  "description": "return every match as a list",
                  "type": "boolean"
                },
                "attr": {
                  "description": "extract this attribute instead of text",
                  "type": "string"
                },
                "css": {
                  "type": "string"
                },
                "html": {
                  "description": "extract inner HTML instead of text",
                  "type": "boolean"
                },
                "name": {
                  "type": "string"
                },
                "regex": {
                  "type": "string"
                },
                "xpath": {
                  "type": "string"
                }
              },
              "required": [
                "name"
              ],
              "type": "object"
            },
            "type": "array"
          }
        },
        "required": [
          "html",
          "selectors"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "extracted": {
            "type": "object"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Fast HTTP fetch, TLS impersonation: get/post/put/delete, inline extraction, bulk `urls`.",
      "metadata": {},
      "name": "browser::fetch",
      "request_schema": {
        "properties": {
          "cookies": {
            "type": "object"
          },
          "css_selector": {
            "description": "scope the render to this CSS subtree (e.g. a page's content div)",
            "type": "string"
          },
          "data": {
            "type": "object"
          },
          "follow_redirects": {
            "type": "boolean"
          },
          "format": {
            "description": "render page body to this format",
            "enum": [
              "markdown",
              "text"
            ],
            "type": "string"
          },
          "headers": {
            "type": "object"
          },
          "http3": {
            "type": "boolean"
          },
          "impersonate": {
            "description": "TLS/UA fingerprint, e.g. 'chrome'",
            "type": "string"
          },
          "include_html": {
            "type": "boolean"
          },
          "json": {
            "type": "object"
          },
          "main_content_only": {
            "description": "strip nav/scripts/hidden before rendering",
            "type": "boolean"
          },
          "max_redirects": {
            "type": "integer"
          },
          "method": {
            "enum": [
              "get",
              "post",
              "put",
              "delete"
            ],
            "type": "string"
          },
          "params": {
            "type": "object"
          },
          "proxies": {
            "description": "per-scheme proxies, e.g. {\"https\": \"http://...\"}",
            "type": "object"
          },
          "proxy": {
            "type": "string"
          },
          "proxy_auth": {
            "description": "[user, password]",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "retries": {
            "type": "integer"
          },
          "retry_delay": {
            "type": "number"
          },
          "selectors": {
            "items": {
              "properties": {
                "all": {
                  "description": "return every match as a list",
                  "type": "boolean"
                },
                "attr": {
                  "description": "extract this attribute instead of text",
                  "type": "string"
                },
                "css": {
                  "type": "string"
                },
                "html": {
                  "description": "extract inner HTML instead of text",
                  "type": "boolean"
                },
                "name": {
                  "type": "string"
                },
                "regex": {
                  "type": "string"
                },
                "xpath": {
                  "type": "string"
                }
              },
              "required": [
                "name"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "stealthy_headers": {
            "type": "boolean"
          },
          "timeout": {
            "description": "seconds (HTTP fetcher)",
            "type": "number"
          },
          "url": {
            "type": "string"
          },
          "urls": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "verify": {
            "type": "boolean"
          }
        },
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "captured_xhr": {
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "content": {
            "description": "markdown/text render when `format` requested",
            "type": "string"
          },
          "cookies": {
            "type": "object"
          },
          "encoding": {
            "type": [
              "string",
              "null"
            ]
          },
          "error": {
            "type": "string"
          },
          "extracted": {
            "type": "object"
          },
          "format": {
            "type": "string"
          },
          "headers": {
            "type": "object"
          },
          "html": {
            "type": "string"
          },
          "results": {
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "status": {
            "type": [
              "integer",
              "null"
            ]
          },
          "url": {
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Find elements by tag/attribute filters (+ optional text regex); BeautifulSoup-style.",
      "metadata": {},
      "name": "browser::find",
      "request_schema": {
        "properties": {
          "attrs": {
            "description": "attribute filters, e.g. {\"class\": \"card\"}",
            "type": "object"
          },
          "first": {
            "type": "boolean"
          },
          "html": {
            "type": "string"
          },
          "limit": {
            "type": "integer"
          },
          "tag": {
            "description": "tag name or list of tag names",
            "items": {
              "type": "string"
            },
            "type": [
              "string",
              "array"
            ]
          },
          "text_regex": {
            "description": "keep only elements whose text matches this regex",
            "type": "string"
          }
        },
        "required": [
          "html"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "count": {
            "type": "integer"
          },
          "items": {
            "items": {
              "properties": {
                "attrs": {
                  "type": "object"
                },
                "css": {
                  "type": "string"
                },
                "html": {
                  "type": "string"
                },
                "tag": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                },
                "xpath": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Find elements whose visible text matches a regex pattern.",
      "metadata": {},
      "name": "browser::find-by-regex",
      "request_schema": {
        "properties": {
          "case_sensitive": {
            "type": "boolean"
          },
          "clean_match": {
            "type": "boolean"
          },
          "first": {
            "type": "boolean"
          },
          "html": {
            "type": "string"
          },
          "limit": {
            "type": "integer"
          },
          "pattern": {
            "type": "string"
          }
        },
        "required": [
          "html",
          "pattern"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "count": {
            "type": "integer"
          },
          "items": {
            "items": {
              "properties": {
                "attrs": {
                  "type": "object"
                },
                "css": {
                  "type": "string"
                },
                "html": {
                  "type": "string"
                },
                "tag": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                },
                "xpath": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Find elements whose visible text matches a string (exact or `partial`).",
      "metadata": {},
      "name": "browser::find-by-text",
      "request_schema": {
        "properties": {
          "case_sensitive": {
            "type": "boolean"
          },
          "clean_match": {
            "description": "ignore surrounding/collapsing whitespace",
            "type": "boolean"
          },
          "first": {
            "type": "boolean"
          },
          "html": {
            "type": "string"
          },
          "limit": {
            "type": "integer"
          },
          "partial": {
            "description": "match elements that contain the text",
            "type": "boolean"
          },
          "text": {
            "type": "string"
          }
        },
        "required": [
          "html",
          "text"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "count": {
            "type": "integer"
          },
          "items": {
            "items": {
              "properties": {
                "attrs": {
                  "type": "object"
                },
                "css": {
                  "type": "string"
                },
                "html": {
                  "type": "string"
                },
                "tag": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                },
                "xpath": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Find text in the page like the browser's find bar: highlights every match in the live document, scrolls the current one into view, and steps with next / previous. close clears the highlights. Returns count and the 1-based index.",
      "metadata": {},
      "name": "browser::find-in-page",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "action": {
            "default": null,
            "description": "`search` (default: run the query from the top), `next`, `previous`, or `close`.",
            "type": [
              "string",
              "null"
            ]
          },
          "case_sensitive": {
            "default": null,
            "description": "Match case. Default false.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "query": {
            "default": "",
            "description": "Text to look for. Empty with `action: close` clears the search.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "FindInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "count": {
            "description": "Number of matches in the visible text of the page.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "index": {
            "description": "1-based index of the highlighted match; 0 when there is none.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "ok": {
            "type": "boolean"
          },
          "query": {
            "description": "The query the counts refer to.",
            "type": "string"
          }
        },
        "required": [
          "count",
          "index",
          "ok",
          "query"
        ],
        "title": "FindOutput",
        "type": "object"
      }
    },
    {
      "description": "Structural auto-match: given one example element, return it plus similar elements.",
      "metadata": {},
      "name": "browser::find-similar",
      "request_schema": {
        "properties": {
          "anchor": {
            "description": "CSS selector to one example element",
            "type": "string"
          },
          "html": {
            "type": "string"
          },
          "match_text": {
            "type": "boolean"
          },
          "selectors": {
            "items": {
              "properties": {
                "all": {
                  "description": "return every match as a list",
                  "type": "boolean"
                },
                "attr": {
                  "description": "extract this attribute instead of text",
                  "type": "string"
                },
                "css": {
                  "type": "string"
                },
                "html": {
                  "description": "extract inner HTML instead of text",
                  "type": "boolean"
                },
                "name": {
                  "type": "string"
                },
                "regex": {
                  "type": "string"
                },
                "xpath": {
                  "type": "string"
                }
              },
              "required": [
                "name"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "similarity_threshold": {
            "type": "number"
          }
        },
        "required": [
          "html",
          "anchor"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "count": {
            "type": "integer"
          },
          "items": {
            "items": {
              "type": "object"
            },
            "type": "array"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Internal: newest screencast frame, or nothing when since_frame is still current. No capture round-trip; poll fast. Not an agent function.",
      "metadata": {
        "internal": true
      },
      "name": "browser::frame",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          },
          "since_frame": {
            "default": null,
            "description": "Frame cursor from the previous read; the response omits `frame` while the newest frame still has this seq.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "session_id"
        ],
        "title": "FrameInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "active": {
            "description": "False when no screencast is running (call screencast::start first).",
            "type": "boolean"
          },
          "frame": {
            "description": "Base64 JPEG of the newest frame; absent when `since_frame` is still current or no frame has arrived yet.",
            "type": [
              "string",
              "null"
            ]
          },
          "frame_seq": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "height": {
            "description": "Page-viewport height the frame maps to.",
            "format": "uint32",
            "minimum": 0,
            "type": "integer"
          },
          "timestamp": {
            "format": "int64",
            "type": "integer"
          },
          "width": {
            "description": "Page-viewport width the frame maps to (input coordinate space).",
            "format": "uint32",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "active",
          "frame_seq",
          "height",
          "timestamp",
          "width"
        ],
        "title": "FrameOutput",
        "type": "object"
      }
    },
    {
      "description": "Pause a session for a step only a human can do (CAPTCHA, 2FA, payment): show an in-page continue banner and block until the human clicks it, a browser::handoff::confirm call resolves it, or the timeout elapses. Human acknowledgment is not proof — verify the expected page state after it returns.",
      "metadata": {},
      "name": "browser::handoff",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "instructions": {
            "description": "What the human must do before the call continues. Shown in the in-page banner and the handoff-requested event.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          },
          "timeout_ms": {
            "default": null,
            "description": "Give up after this many ms and return `via: \"timeout\"` (clamped to `max_timeout_ms`); set generously, a human is slow.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "instructions",
          "session_id"
        ],
        "title": "HandoffInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "confirmed": {
            "description": "True when a human confirmed; false when the wait timed out.",
            "type": "boolean"
          },
          "handoff_id": {
            "type": "string"
          },
          "url": {
            "description": "The page URL when the wait ended, so the caller can verify the step actually landed (human acknowledgment is not proof).",
            "type": "string"
          },
          "via": {
            "description": "How the confirmation arrived: `in_page`, `confirm_call`, or `timeout`.",
            "type": "string"
          }
        },
        "required": [
          "confirmed",
          "handoff_id",
          "url",
          "via"
        ],
        "title": "HandoffOutput",
        "type": "object"
      }
    },
    {
      "description": "Resolve a paused browser::handoff by handoff_id, or the one pending handoff for a session_id. The console calls this when the human confirms outside the page.",
      "metadata": {},
      "name": "browser::handoff::confirm",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "handoff_id": {
            "default": null,
            "description": "Confirm a specific handoff by id. Omit to confirm the one pending handoff for `session_id`.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "default": null,
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "HandoffConfirmInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "handoff_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "ok": {
            "description": "True when a pending handoff matched and was resolved.",
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "HandoffConfirmOutput",
        "type": "object"
      }
    },
    {
      "description": "Go back, go forward, or reload the session's page. Back/forward at the history edge is a no-op with moved=false.",
      "metadata": {},
      "name": "browser::history",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "action": {
            "description": "`back`, `forward`, or `reload`.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "action",
          "session_id"
        ],
        "title": "HistoryInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "moved": {
            "description": "False when back/forward had no entry to move to.",
            "type": "boolean"
          },
          "ok": {
            "type": "boolean"
          },
          "url": {
            "description": "URL after the action. `back`/`forward` at the history edge is a no-op with ok=true.",
            "type": "string"
          }
        },
        "required": [
          "moved",
          "ok",
          "url"
        ],
        "title": "HistoryOutput",
        "type": "object"
      }
    },
    {
      "description": "The session's visited pages, newest first, for a history panel or address-bar suggestions. Filter with query. Distinct from browser::history, which moves back / forward / reloads.",
      "metadata": {},
      "name": "browser::history::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "limit": {
            "default": null,
            "description": "Cap on returned entries. Default 100.",
            "format": "uint",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "query": {
            "default": null,
            "description": "Only entries whose url or title contains this (case-insensitive).",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "HistoryListInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "HistoryVisit": {
            "description": "One entry in a session's navigation history.",
            "properties": {
              "timestamp": {
                "format": "int64",
                "type": "integer"
              },
              "title": {
                "type": "string"
              },
              "url": {
                "type": "string"
              }
            },
            "required": [
              "timestamp",
              "title",
              "url"
            ],
            "type": "object"
          }
        },
        "properties": {
          "visits": {
            "items": {
              "$ref": "#/definitions/HistoryVisit"
            },
            "type": "array"
          }
        },
        "required": [
          "visits"
        ],
        "title": "HistoryListOutput",
        "type": "object"
      }
    },
    {
      "description": "Internal: appends browser::* scraping and HTML parsing guidance to the agent system prompt.",
      "metadata": {
        "internal": true
      },
      "name": "browser::inject-guidance",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "GenerateContext": {
            "properties": {
              "system_prompt": {
                "default": "",
                "type": "string"
              }
            },
            "type": "object"
          }
        },
        "properties": {
          "generate": {
            "$ref": "#/definitions/GenerateContext"
          }
        },
        "title": "PreGenerateEvent",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "PreGenerateMutations": {
            "properties": {
              "system_prompt": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          }
        },
        "properties": {
          "mutations": {
            "$ref": "#/definitions/PreGenerateMutations"
          }
        },
        "required": [
          "mutations"
        ],
        "title": "PreGenerateResponse",
        "type": "object"
      }
    },
    {
      "description": "Navigate a session to a URL and wait for the page to load. Element refs from earlier snapshots are invalidated by navigation.",
      "metadata": {},
      "name": "browser::navigate",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          },
          "timeout_ms": {
            "default": null,
            "description": "Upper bound on the navigation wait; clamped to `max_timeout_ms`.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "url": {
            "description": "Absolute URL; scheme must be on the configured allowlist.",
            "type": "string"
          }
        },
        "required": [
          "session_id",
          "url"
        ],
        "title": "NavigateInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "timed_out": {
            "description": "True when the load event did not fire inside the timeout; the page may still be usable; snapshot to check.",
            "type": "boolean"
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "url": {
            "description": "URL after redirects.",
            "type": "string"
          }
        },
        "required": [
          "ok",
          "timed_out",
          "url"
        ],
        "title": "NavigateOutput",
        "type": "object"
      }
    },
    {
      "description": "Read the session's captured network requests (method, URL, status, failures). failed_only=true is the fast path for 'what broke'.",
      "metadata": {},
      "name": "browser::network::read",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "failed_only": {
            "default": null,
            "description": "Only failed requests (network error or status >= 400).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "limit": {
            "default": null,
            "description": "Maximum entries returned, newest kept (default 100).",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "pattern": {
            "default": null,
            "description": "Regex applied to the request URL.",
            "type": [
              "string",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "since_seq": {
            "default": null,
            "description": "Only entries with `seq` greater than this.",
            "format": "uint64",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "session_id"
        ],
        "title": "NetworkReadInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "NetworkEntry": {
            "description": "One captured network request.",
            "properties": {
              "error": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "failed": {
                "type": "boolean"
              },
              "method": {
                "type": "string"
              },
              "mime_type": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "seq": {
                "description": "Monotonic per-session cursor; pass back as `since_seq`.",
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "status": {
                "format": "int64",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "timestamp": {
                "format": "int64",
                "type": "integer"
              },
              "url": {
                "type": "string"
              }
            },
            "required": [
              "failed",
              "method",
              "seq",
              "timestamp",
              "url"
            ],
            "type": "object"
          }
        },
        "properties": {
          "dropped": {
            "description": "Entries evicted from the ring buffer since session start.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "entries": {
            "items": {
              "$ref": "#/definitions/NetworkEntry"
            },
            "type": "array"
          },
          "last_seq": {
            "description": "Cursor for the next `since_seq`.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "dropped",
          "entries",
          "last_seq"
        ],
        "title": "NetworkReadOutput",
        "type": "object"
      }
    },
    {
      "description": "Internal: reload browser settings from the authoritative configuration on change.",
      "metadata": {
        "internal": true
      },
      "name": "browser::on-config-change",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "OnConfigChangeRequest",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "OnConfigChangeResponse",
        "type": "object"
      }
    },
    {
      "description": "Print the page to a PDF (the browser's Print -> Save as PDF) and return it base64 with a file name from the title.",
      "metadata": {},
      "name": "browser::pdf",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "landscape": {
            "default": null,
            "description": "Landscape orientation. Default portrait.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "print_background": {
            "default": null,
            "description": "Print background colours and images. Default true (what the page looks like, not what a printer would save ink on).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "scale": {
            "default": null,
            "description": "Page scale, 0.1–2. Default 1.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "PdfInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "data": {
            "description": "The PDF, base64.",
            "type": "string"
          },
          "file_name": {
            "description": "Suggested file name, from the page title.",
            "type": "string"
          },
          "ok": {
            "type": "boolean"
          },
          "size_bytes": {
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "data",
          "file_name",
          "ok",
          "size_bytes",
          "url"
        ],
        "title": "PdfOutput",
        "type": "object"
      }
    },
    {
      "description": "Internal: element preview at a viewport point (tag, id, classes, bounds) so the console UI can draw a hover highlight in pick mode. Not an agent function.",
      "metadata": {
        "internal": true
      },
      "name": "browser::pick::hint",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          },
          "x": {
            "description": "Viewport x of the cursor.",
            "format": "double",
            "type": "number"
          },
          "y": {
            "description": "Viewport y of the cursor.",
            "format": "double",
            "type": "number"
          }
        },
        "required": [
          "session_id",
          "x",
          "y"
        ],
        "title": "PickHintInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "Bounds": {
            "properties": {
              "height": {
                "format": "double",
                "type": "number"
              },
              "width": {
                "format": "double",
                "type": "number"
              },
              "x": {
                "format": "double",
                "type": "number"
              },
              "y": {
                "format": "double",
                "type": "number"
              }
            },
            "required": [
              "height",
              "width",
              "x",
              "y"
            ],
            "type": "object"
          }
        },
        "properties": {
          "bounds": {
            "anyOf": [
              {
                "$ref": "#/definitions/Bounds"
              },
              {
                "type": "null"
              }
            ],
            "description": "Viewport-space box to draw the highlight over."
          },
          "classes": {
            "type": [
              "string",
              "null"
            ]
          },
          "hit": {
            "description": "False when no element sits at the point.",
            "type": "boolean"
          },
          "id": {
            "type": [
              "string",
              "null"
            ]
          },
          "tag": {
            "description": "Lowercase tag name.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "hit"
        ],
        "title": "PickHintOutput",
        "type": "object"
      }
    },
    {
      "description": "Internal: resolve the element at a clicked viewport point and emit browser::picked. The console calls this on a pick-mode click. Not an agent function.",
      "metadata": {
        "internal": true
      },
      "name": "browser::pick::resolve",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          },
          "x": {
            "description": "Viewport x of the click.",
            "format": "double",
            "type": "number"
          },
          "y": {
            "description": "Viewport y of the click.",
            "format": "double",
            "type": "number"
          }
        },
        "required": [
          "session_id",
          "x",
          "y"
        ],
        "title": "PickResolveInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Neutral acknowledgement returned by the fire-and-forget internal functions (pick start/stop/resolve, screencast start/stop): they emit their result as a trigger event, so the direct return is just `{ ok }`.",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "AckOutput",
        "type": "object"
      }
    },
    {
      "description": "Internal: enter pick mode so the human can select an element in the console UI. Not an agent function.",
      "metadata": {
        "internal": true
      },
      "name": "browser::pick::start",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "PickStartInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Neutral acknowledgement returned by the fire-and-forget internal functions (pick start/stop/resolve, screencast start/stop): they emit their result as a trigger event, so the direct return is just `{ ok }`.",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "AckOutput",
        "type": "object"
      }
    },
    {
      "description": "Internal: leave DevTools inspect mode without picking. Idempotent. Not an agent function.",
      "metadata": {
        "internal": true
      },
      "name": "browser::pick::stop",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "description": "Cancelling pick mode on an unknown session succeeds.",
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "PickStopInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Neutral acknowledgement returned by the fire-and-forget internal functions (pick start/stop/resolve, screencast start/stop): they emit their result as a trigger event, so the direct return is just `{ ok }`.",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "AckOutput",
        "type": "object"
      }
    },
    {
      "description": "Record a session's live viewport to a video file (webm or mp4) by piping the screencast through ffmpeg. Turns screencast on if needed. Requires ffmpeg on PATH; browser::doctor reports whether it is available.",
      "metadata": {},
      "name": "browser::recording::start",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "format": {
            "default": null,
            "description": "`webm` (VP9) or `mp4` (H.264). Defaults to webm.",
            "type": [
              "string",
              "null"
            ]
          },
          "path": {
            "description": "Output file path. The extension should match `format`.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "path",
          "session_id"
        ],
        "title": "RecordingStartInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "format": {
            "type": "string"
          },
          "ok": {
            "type": "boolean"
          },
          "path": {
            "type": "string"
          }
        },
        "required": [
          "format",
          "ok",
          "path"
        ],
        "title": "RecordingStartOutput",
        "type": "object"
      }
    },
    {
      "description": "Stop a session's recording, finalize the file, and return its path, duration, and frame count. Idempotent: stopping when nothing is recording returns ok=false.",
      "metadata": {},
      "name": "browser::recording::stop",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "RecordingStopInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "duration_ms": {
            "description": "Wall-clock duration captured, milliseconds.",
            "format": "int64",
            "type": "integer"
          },
          "frames": {
            "description": "Frames written to the encoder.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "ok": {
            "description": "False when no recording was running.",
            "type": "boolean"
          },
          "path": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "duration_ms",
          "frames",
          "ok"
        ],
        "title": "RecordingStopOutput",
        "type": "object"
      }
    },
    {
      "description": "Run a regex over the visible text of provided HTML; `first` returns the first match, else all.",
      "metadata": {},
      "name": "browser::regex",
      "request_schema": {
        "properties": {
          "first": {
            "type": "boolean"
          },
          "html": {
            "type": "string"
          },
          "pattern": {
            "type": "string"
          }
        },
        "required": [
          "html",
          "pattern"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "result": {
            "items": {
              "type": [
                "string",
                "null"
              ]
            },
            "type": [
              "array",
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Set the session's live viewport size (CSS pixels). The console calls this as its browser pane resizes so the streamed frame fills the pane with no letterboxing and clicks map 1:1; the device toolbar calls it with a preset. Clamped 200..4000.",
      "metadata": {},
      "name": "browser::resize",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "device_scale_factor": {
            "default": null,
            "description": "Device pixel ratio. Default 1.",
            "format": "double",
            "type": [
              "number",
              "null"
            ]
          },
          "fit": {
            "default": null,
            "description": "Mark this resize as a pane auto-fit; a fit is refused (current size returned) while more than one viewer watches the session.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "height": {
            "description": "Viewport height in CSS pixels (clamped 200..4000).",
            "format": "uint32",
            "minimum": 0,
            "type": "integer"
          },
          "mobile": {
            "default": null,
            "description": "Emulate a mobile device (viewport meta, overlay scrollbars, touch). Default false. The device toolbar sets this for phone presets.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          },
          "width": {
            "description": "Viewport width in CSS pixels (clamped 200..4000).",
            "format": "uint32",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "height",
          "session_id",
          "width"
        ],
        "title": "ResizeInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "height": {
            "format": "uint32",
            "minimum": 0,
            "type": "integer"
          },
          "ok": {
            "type": "boolean"
          },
          "width": {
            "description": "The clamped size actually applied.",
            "format": "uint32",
            "minimum": 0,
            "type": "integer"
          }
        },
        "required": [
          "height",
          "ok",
          "width"
        ],
        "title": "ResizeOutput",
        "type": "object"
      }
    },
    {
      "description": "Internal: start pushing live viewport frames for browser::frame. Console-UI plumbing; agents use browser::screenshot. Not an agent function.",
      "metadata": {
        "internal": true
      },
      "name": "browser::screencast::start",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "ScreencastStartInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Neutral acknowledgement returned by the fire-and-forget internal functions (pick start/stop/resolve, screencast start/stop): they emit their result as a trigger event, so the direct return is just `{ ok }`.",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "AckOutput",
        "type": "object"
      }
    },
    {
      "description": "Internal: stop the live frame push. Idempotent. Not an agent function.",
      "metadata": {
        "internal": true
      },
      "name": "browser::screencast::stop",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "description": "Stopping the screencast on an unknown session succeeds.",
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "ScreencastStopInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Neutral acknowledgement returned by the fire-and-forget internal functions (pick start/stop/resolve, screencast start/stop): they emit their result as a trigger event, so the direct return is just `{ ok }`.",
        "properties": {
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "ok"
        ],
        "title": "AckOutput",
        "type": "object"
      }
    },
    {
      "description": "Capture the session viewport as a viewable JPEG. Use browser::snapshot for machine-readable structure; screenshot when layout or rendering matters.",
      "metadata": {
        "display": true
      },
      "name": "browser::screenshot",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "full_page": {
            "default": null,
            "description": "Capture the full scrollable page instead of the viewport.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "ScreenshotInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "ContentBlock": {
            "description": "One block of a viewable response: an image block plus a text line.",
            "properties": {
              "data": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "mime": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "text": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "type": {
                "type": "string"
              }
            },
            "required": [
              "type"
            ],
            "type": "object"
          },
          "ScreenshotDetails": {
            "properties": {
              "height": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              },
              "session_id": {
                "type": "string"
              },
              "url": {
                "type": "string"
              },
              "width": {
                "format": "uint32",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "height",
              "session_id",
              "url",
              "width"
            ],
            "type": "object"
          }
        },
        "properties": {
          "content": {
            "items": {
              "$ref": "#/definitions/ContentBlock"
            },
            "type": "array"
          },
          "details": {
            "$ref": "#/definitions/ScreenshotDetails"
          }
        },
        "required": [
          "content",
          "details"
        ],
        "title": "ScreenshotOutput",
        "type": "object"
      }
    },
    {
      "description": "Capture a page screenshot as image content blocks via a browser fetcher (dynamic or stealthy).",
      "metadata": {},
      "name": "browser::screenshot-url",
      "request_schema": {
        "properties": {
          "fetcher": {
            "enum": [
              "dynamic",
              "stealthy"
            ],
            "type": "string"
          },
          "format": {
            "enum": [
              "png",
              "jpeg"
            ],
            "type": "string"
          },
          "full_page": {
            "type": "boolean"
          },
          "headless": {
            "type": "boolean"
          },
          "network_idle": {
            "type": "boolean"
          },
          "proxy": {
            "type": "string"
          },
          "timeout": {
            "type": "number"
          },
          "url": {
            "type": "string"
          },
          "wait_selector": {
            "type": "string"
          }
        },
        "required": [
          "url"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "content": {
            "description": "image blocks (one per tile, width<=1024/height<=1536) + a text caption",
            "items": {
              "properties": {
                "data": {
                  "description": "base64 image bytes (image blocks)",
                  "type": "string"
                },
                "mime": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                },
                "type": {
                  "enum": [
                    "image",
                    "text"
                  ],
                  "type": "string"
                }
              },
              "required": [
                "type"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "mime": {
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Close a session and free its browser/connection.",
      "metadata": {},
      "name": "browser::session-close",
      "request_schema": {
        "properties": {
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "closed": {
            "type": "boolean"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Fetch a URL on an open scraping session (reuses its cookies/state); returns page content, shows nothing. For a page the user should see, use browser::sessions::start + browser::navigate.",
      "metadata": {},
      "name": "browser::session-fetch",
      "request_schema": {
        "properties": {
          "css_selector": {
            "description": "scope the render to this CSS subtree (e.g. a page's content div)",
            "type": "string"
          },
          "data": {
            "type": "object"
          },
          "format": {
            "description": "render page body to this format",
            "enum": [
              "markdown",
              "text"
            ],
            "type": "string"
          },
          "headers": {
            "type": "object"
          },
          "include_html": {
            "type": "boolean"
          },
          "json": {
            "type": "object"
          },
          "main_content_only": {
            "description": "strip nav/scripts/hidden before rendering",
            "type": "boolean"
          },
          "method": {
            "enum": [
              "get",
              "post",
              "put",
              "delete"
            ],
            "type": "string"
          },
          "params": {
            "type": "object"
          },
          "selectors": {
            "items": {
              "properties": {
                "all": {
                  "description": "return every match as a list",
                  "type": "boolean"
                },
                "attr": {
                  "description": "extract this attribute instead of text",
                  "type": "string"
                },
                "css": {
                  "type": "string"
                },
                "html": {
                  "description": "extract inner HTML instead of text",
                  "type": "boolean"
                },
                "name": {
                  "type": "string"
                },
                "regex": {
                  "type": "string"
                },
                "xpath": {
                  "type": "string"
                }
              },
              "required": [
                "name"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "session_id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "wait_selector": {
            "type": "string"
          }
        },
        "required": [
          "session_id",
          "url"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "captured_xhr": {
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "content": {
            "description": "markdown/text render when `format` requested",
            "type": "string"
          },
          "cookies": {
            "type": "object"
          },
          "encoding": {
            "type": [
              "string",
              "null"
            ]
          },
          "error": {
            "type": "string"
          },
          "extracted": {
            "type": "object"
          },
          "format": {
            "type": "string"
          },
          "headers": {
            "type": "object"
          },
          "html": {
            "type": "string"
          },
          "results": {
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "status": {
            "type": [
              "integer",
              "null"
            ]
          },
          "url": {
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "List open sessions with their type and idle time.",
      "metadata": {},
      "name": "browser::session-list",
      "request_schema": {
        "properties": {
          "type": {
            "description": "filter by type",
            "enum": [
              "http",
              "dynamic",
              "stealthy"
            ],
            "type": "string"
          }
        },
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "sessions": {
            "items": {
              "properties": {
                "created_at": {
                  "type": "number"
                },
                "idle_s": {
                  "type": "number"
                },
                "last_used": {
                  "type": "number"
                },
                "session_id": {
                  "type": "string"
                },
                "type": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Open a persistent scraping session (HTTP or headless fetcher) whose session_id reuses cookies and state across fetches. Renders nothing the user can see; to open a page in the visible browser use browser::sessions::start.",
      "metadata": {},
      "name": "browser::session-open",
      "request_schema": {
        "properties": {
          "capture_xhr": {
            "description": "regex; capture matching XHRs (browser sessions)",
            "type": "string"
          },
          "headers": {
            "type": "object"
          },
          "headless": {
            "type": "boolean"
          },
          "impersonate": {
            "type": "string"
          },
          "proxies": {
            "type": "object"
          },
          "proxy": {
            "type": "string"
          },
          "real_chrome": {
            "type": "boolean"
          },
          "solve_cloudflare": {
            "type": "boolean"
          },
          "timeout": {
            "type": "number"
          },
          "type": {
            "description": "session engine",
            "enum": [
              "http",
              "dynamic",
              "stealthy"
            ],
            "type": "string"
          },
          "useragent": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "session_id": {
            "type": "string"
          },
          "type": {
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Attach a session to an already-running browser over CDP (Chrome started with --remote-debugging-port): opens a fresh tab the session owns, or adopts a user tab by URL substring and releases it untouched on stop. Reaches the real profile and its logins; requires allow_attach in config.",
      "metadata": {},
      "name": "browser::sessions::attach",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "adopt_url_substring": {
            "default": null,
            "description": "Adopt the one open tab whose URL contains this substring (released untouched on stop); omit to open a fresh tab the session owns.",
            "type": [
              "string",
              "null"
            ]
          },
          "cdp_url": {
            "description": "CDP endpoint of the running browser: `http://127.0.0.1:9222` (resolved via `/json/version`) or a `ws://` debugger URL.",
            "type": "string"
          },
          "read_only": {
            "default": null,
            "description": "Inspection-only session; see browser::sessions::start.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "url": {
            "default": null,
            "description": "URL to open in the fresh tab (ignored when adopting). Omit for about:blank.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "cdp_url"
        ],
        "title": "AttachInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "adopted": {
            "description": "True when the session adopted an existing user tab (released, not closed, on stop); false when it opened a fresh tab it owns.",
            "type": "boolean"
          },
          "read_only": {
            "type": "boolean"
          },
          "session_id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "adopted",
          "read_only",
          "session_id",
          "url"
        ],
        "title": "AttachOutput",
        "type": "object"
      }
    },
    {
      "description": "List live browser sessions with their current URL and activity.",
      "metadata": {},
      "name": "browser::sessions::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "title": "ListInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "SessionInfo": {
            "properties": {
              "console_entries": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              },
              "created_ms": {
                "format": "int64",
                "type": "integer"
              },
              "headless": {
                "type": "boolean"
              },
              "last_used_ms": {
                "format": "int64",
                "type": "integer"
              },
              "read_only": {
                "type": "boolean"
              },
              "session_id": {
                "type": "string"
              },
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "url": {
                "type": "string"
              }
            },
            "required": [
              "console_entries",
              "created_ms",
              "headless",
              "last_used_ms",
              "read_only",
              "session_id",
              "url"
            ],
            "type": "object"
          }
        },
        "properties": {
          "sessions": {
            "items": {
              "$ref": "#/definitions/SessionInfo"
            },
            "type": "array"
          }
        },
        "required": [
          "sessions"
        ],
        "title": "ListOutput",
        "type": "object"
      }
    },
    {
      "description": "Start an interactive Chromium session and return its session_id. Sessions keep console and network history; stop them with browser::sessions::stop when done.",
      "metadata": {},
      "name": "browser::sessions::start",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "headful": {
            "default": null,
            "description": "Force a visible window for this session, overriding the configured `headless` default.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "read_only": {
            "default": null,
            "description": "Inspection-only session for its whole lifetime: act, evaluate, execute and styles::write are rejected; navigation and reads work.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "url": {
            "default": null,
            "description": "URL to open immediately. Omit to start on about:blank.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "StartInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "headless": {
            "type": "boolean"
          },
          "read_only": {
            "type": "boolean"
          },
          "session_id": {
            "description": "Pass this to every other browser function.",
            "type": "string"
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "headless",
          "read_only",
          "session_id",
          "url"
        ],
        "title": "StartOutput",
        "type": "object"
      }
    },
    {
      "description": "Stop a browser session and its Chromium process. Idempotent: stopping an unknown or already-stopped session succeeds with was_running=false.",
      "metadata": {},
      "name": "browser::sessions::stop",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "session_id": {
            "description": "Session to stop. Stopping an unknown or already-stopped id succeeds.",
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "StopInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "ok": {
            "type": "boolean"
          },
          "was_running": {
            "description": "False when the session was already gone.",
            "type": "boolean"
          }
        },
        "required": [
          "ok",
          "was_running"
        ],
        "title": "StopOutput",
        "type": "object"
      }
    },
    {
      "description": "Read the page as an accessibility-tree outline. Lines carry [ref=eN] handles that browser::act accepts; refs stay valid until the next navigation. Prefer this over browser::screenshot; it is cheaper and machine-readable.",
      "metadata": {},
      "name": "browser::snapshot",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "diff": {
            "default": null,
            "description": "Return only what changed since the previous snapshot; a full outline when there is no baseline (first snapshot or after a navigation).",
            "type": [
              "boolean",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "SnapshotInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "SnapshotDiff": {
            "description": "Changes since the previous snapshot. Lines are compared without their `[ref=eN]` suffix (ref names are unique per snapshot); `added` lines carry current refs and are directly actionable.",
            "properties": {
              "added": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "removed": {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "unchanged": {
                "format": "uint64",
                "minimum": 0,
                "type": "integer"
              }
            },
            "required": [
              "added",
              "removed",
              "unchanged"
            ],
            "type": "object"
          }
        },
        "properties": {
          "diff": {
            "anyOf": [
              {
                "$ref": "#/definitions/SnapshotDiff"
              },
              {
                "type": "null"
              }
            ],
            "description": "Present when the caller asked for `diff: true` and a baseline existed. Covers only the emitted nodes of both snapshots; check `truncated` before trusting it as a complete change set."
          },
          "generation": {
            "description": "Document generation the refs belong to; navigation advances it and kills every ref from earlier generations.",
            "format": "uint64",
            "minimum": 0,
            "type": "integer"
          },
          "title": {
            "type": [
              "string",
              "null"
            ]
          },
          "tree": {
            "description": "Indented outline; lines carry `[ref=eN]` handles for `browser::act`. Empty when `diff` is populated.",
            "type": "string"
          },
          "truncated": {
            "description": "True when the tree hit `max_snapshot_nodes` and was cut short. Also the signal that a `diff` may be incomplete: the diff is computed over emitted nodes only, so when either snapshot was truncated a node that was emitted before and capped out now can show up in `removed` even though it still exists (and vice versa for `added`).",
            "type": "boolean"
          },
          "url": {
            "type": "string"
          }
        },
        "required": [
          "generation",
          "tree",
          "truncated",
          "url"
        ],
        "title": "SnapshotOutput",
        "type": "object"
      }
    },
    {
      "description": "Camoufox stealth browser: solves Cloudflare, hardens WebRTC/canvas; extraction + bulk.",
      "metadata": {},
      "name": "browser::stealthy-fetch",
      "request_schema": {
        "properties": {
          "allow_webgl": {
            "type": "boolean"
          },
          "block_ads": {
            "type": "boolean"
          },
          "block_webrtc": {
            "type": "boolean"
          },
          "blocked_domains": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "capture_xhr": {
            "type": "string"
          },
          "cookies": {
            "type": "object"
          },
          "css_selector": {
            "description": "scope the render to this CSS subtree (e.g. a page's content div)",
            "type": "string"
          },
          "disable_resources": {
            "type": "boolean"
          },
          "dns_over_https": {
            "type": "boolean"
          },
          "extra_flags": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "extra_headers": {
            "type": "object"
          },
          "format": {
            "description": "render page body to this format",
            "enum": [
              "markdown",
              "text"
            ],
            "type": "string"
          },
          "google_search": {
            "type": "boolean"
          },
          "headless": {
            "type": "boolean"
          },
          "hide_canvas": {
            "type": "boolean"
          },
          "include_html": {
            "type": "boolean"
          },
          "load_dom": {
            "type": "boolean"
          },
          "locale": {
            "type": "string"
          },
          "main_content_only": {
            "description": "strip nav/scripts/hidden before rendering",
            "type": "boolean"
          },
          "max_pages": {
            "type": "integer"
          },
          "network_idle": {
            "type": "boolean"
          },
          "proxy": {
            "type": "string"
          },
          "retries": {
            "type": "integer"
          },
          "retry_delay": {
            "type": "number"
          },
          "selectors": {
            "items": {
              "properties": {
                "all": {
                  "description": "return every match as a list",
                  "type": "boolean"
                },
                "attr": {
                  "description": "extract this attribute instead of text",
                  "type": "string"
                },
                "css": {
                  "type": "string"
                },
                "html": {
                  "description": "extract inner HTML instead of text",
                  "type": "boolean"
                },
                "name": {
                  "type": "string"
                },
                "regex": {
                  "type": "string"
                },
                "xpath": {
                  "type": "string"
                }
              },
              "required": [
                "name"
              ],
              "type": "object"
            },
            "type": "array"
          },
          "solve_cloudflare": {
            "type": "boolean"
          },
          "timeout": {
            "description": "milliseconds (browser fetcher)",
            "type": "number"
          },
          "timezone_id": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "urls": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "useragent": {
            "type": "string"
          },
          "wait": {
            "description": "extra ms to wait after load",
            "type": "number"
          },
          "wait_selector": {
            "type": "string"
          },
          "wait_selector_state": {
            "enum": [
              "attached",
              "detached",
              "visible",
              "hidden"
            ],
            "type": "string"
          }
        },
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "captured_xhr": {
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "content": {
            "description": "markdown/text render when `format` requested",
            "type": "string"
          },
          "cookies": {
            "type": "object"
          },
          "encoding": {
            "type": [
              "string",
              "null"
            ]
          },
          "error": {
            "type": "string"
          },
          "extracted": {
            "type": "object"
          },
          "format": {
            "type": "string"
          },
          "headers": {
            "type": "object"
          },
          "html": {
            "type": "string"
          },
          "results": {
            "items": {
              "type": "object"
            },
            "type": "array"
          },
          "status": {
            "type": [
              "integer",
              "null"
            ]
          },
          "url": {
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Read an element's computed styles (curated design set by default, or named properties) plus its inline style attribute.",
      "metadata": {},
      "name": "browser::styles::read",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "properties": {
            "default": null,
            "description": "Computed property names to return. Omit for a curated design-panel set; pass `[\"*\"]` for every computed property.",
            "items": {
              "type": "string"
            },
            "type": [
              "array",
              "null"
            ]
          },
          "ref": {
            "description": "Element ref from `browser::snapshot`, `browser::dom::read`, or a pick.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "ref",
          "session_id"
        ],
        "title": "StylesReadInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "StyleProperty": {
            "properties": {
              "name": {
                "type": "string"
              },
              "value": {
                "type": "string"
              }
            },
            "required": [
              "name",
              "value"
            ],
            "type": "object"
          }
        },
        "properties": {
          "inline_style": {
            "description": "The element's inline `style` attribute, when present.",
            "type": [
              "string",
              "null"
            ]
          },
          "properties": {
            "items": {
              "$ref": "#/definitions/StyleProperty"
            },
            "type": "array"
          },
          "ref": {
            "type": "string"
          }
        },
        "required": [
          "properties",
          "ref"
        ],
        "title": "StylesReadOutput",
        "type": "object"
      }
    },
    {
      "description": "Set one inline CSS property on an element, live in the page. Visual experiment only: the page's source files are untouched, and the edit dies with the next navigation.",
      "metadata": {},
      "name": "browser::styles::write",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "important": {
            "default": null,
            "description": "Apply with `!important`.",
            "type": [
              "boolean",
              "null"
            ]
          },
          "property": {
            "description": "CSS property name (`background-color`).",
            "type": "string"
          },
          "ref": {
            "description": "Element ref to edit.",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          },
          "value": {
            "description": "CSS value (`#101418`). Empty string removes the inline property.",
            "type": "string"
          }
        },
        "required": [
          "property",
          "ref",
          "session_id",
          "value"
        ],
        "title": "StylesWriteInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "inline_style": {
            "description": "The element's inline `style` attribute after the edit.",
            "type": "string"
          },
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "inline_style",
          "ok"
        ],
        "title": "StylesWriteOutput",
        "type": "object"
      }
    },
    {
      "description": "List the open tabs of a running browser reachable at a CDP endpoint (url, title, and whether a session already adopted each). Read-only; adopt one with browser::sessions::attach.",
      "metadata": {},
      "name": "browser::tabs::list",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "cdp_url": {
            "description": "CDP endpoint of the running browser, as in browser::sessions::attach.",
            "type": "string"
          }
        },
        "required": [
          "cdp_url"
        ],
        "title": "TabsListInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "TabInfo": {
            "description": "One open tab reported by `browser::tabs::list`.",
            "properties": {
              "adopted": {
                "description": "True when a session already adopted this tab; it cannot be adopted again until that session stops.",
                "type": "boolean"
              },
              "title": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "url": {
                "type": "string"
              }
            },
            "required": [
              "adopted",
              "url"
            ],
            "type": "object"
          }
        },
        "properties": {
          "tabs": {
            "items": {
              "$ref": "#/definitions/TabInfo"
            },
            "type": "array"
          }
        },
        "required": [
          "tabs"
        ],
        "title": "TabsListOutput",
        "type": "object"
      }
    },
    {
      "description": "Convert HTML to compact Markdown (or text/html); optional CSS scope + main-content clean.",
      "metadata": {},
      "name": "browser::to-markdown",
      "request_schema": {
        "properties": {
          "css_selector": {
            "description": "convert only the subtree matching this CSS selector",
            "type": "string"
          },
          "format": {
            "enum": [
              "markdown",
              "text",
              "html"
            ],
            "type": "string"
          },
          "html": {
            "type": "string"
          },
          "main_content_only": {
            "description": "strip nav/scripts/hidden nodes first",
            "type": "boolean"
          }
        },
        "required": [
          "html"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "content": {
            "type": "string"
          },
          "format": {
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Serve the browser worker's injected console UI assets (content function for its console:script / console:style triggers).",
      "metadata": {
        "internal": true
      },
      "name": "browser::ui-content",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Input of the content function: the console asks for one asset by path.",
        "properties": {
          "path": {
            "description": "The asset path from the trigger config (e.g. `state/page.js`).",
            "type": "string"
          }
        },
        "required": [
          "path"
        ],
        "title": "UiContentInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "description": "Output of the content function.",
        "properties": {
          "content": {
            "description": "The asset source, verbatim.",
            "type": "string"
          },
          "content_type": {
            "description": "MIME type the console should serve the asset with.",
            "type": "string"
          }
        },
        "required": [
          "content",
          "content_type"
        ],
        "title": "UiContentResult",
        "type": "object"
      }
    },
    {
      "description": "Attach up to eight base64 files to exactly one input[type=file] selected by CSS. Files are staged privately for the session and removed when it stops.",
      "metadata": {},
      "name": "browser::upload",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "definitions": {
          "UploadFile": {
            "properties": {
              "data": {
                "description": "File bytes, base64.",
                "type": "string"
              },
              "name": {
                "description": "File name exposed to the page. Path components are rejected.",
                "type": "string"
              }
            },
            "required": [
              "data",
              "name"
            ],
            "type": "object"
          }
        },
        "properties": {
          "files": {
            "description": "Up to eight files, each at most 25 MB decoded.",
            "items": {
              "$ref": "#/definitions/UploadFile"
            },
            "type": "array"
          },
          "selector": {
            "description": "CSS selector that must match exactly one input[type=file].",
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "files",
          "selector",
          "session_id"
        ],
        "title": "UploadInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "attached": {
            "format": "uint",
            "minimum": 0,
            "type": "integer"
          },
          "file_names": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "attached",
          "file_names",
          "ok"
        ],
        "title": "UploadOutput",
        "type": "object"
      }
    },
    {
      "description": "One XPath query over HTML; first-or-all; `attr` pulls an attribute else text.",
      "metadata": {},
      "name": "browser::xpath",
      "request_schema": {
        "properties": {
          "adaptive": {
            "description": "relocate elements after a site change via saved identities",
            "type": "boolean"
          },
          "adaptive_domain": {
            "description": "page URL/domain that keys saved identities",
            "type": "string"
          },
          "attr": {
            "type": "string"
          },
          "auto_save": {
            "description": "save matched identities (defaults on when adaptive)",
            "type": "boolean"
          },
          "first": {
            "type": "boolean"
          },
          "html": {
            "type": "string"
          },
          "identifier": {
            "description": "stable key for the saved element",
            "type": "string"
          },
          "query": {
            "type": "string"
          }
        },
        "required": [
          "html",
          "query"
        ],
        "type": "object"
      },
      "response_schema": {
        "properties": {
          "result": {
            "items": {
              "type": [
                "string",
                "null"
              ]
            },
            "type": [
              "array",
              "string",
              "null"
            ]
          }
        },
        "type": "object"
      }
    },
    {
      "description": "Zoom the page in, out, to a level (50-200 %) or back to 100 %, the way the browser's zoom menu does. The viewport keeps its size; the page scales inside it. The level belongs to the loaded document and resets on navigation.",
      "metadata": {},
      "name": "browser::zoom",
      "request_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "action": {
            "default": null,
            "description": "`in`, `out`, `reset`, `set` (default when `level` is given), or `read` to report the current level without changing it.",
            "type": [
              "string",
              "null"
            ]
          },
          "level": {
            "default": null,
            "description": "Explicit level in percent (50–200); snapped to the ladder.",
            "format": "uint32",
            "minimum": 0,
            "type": [
              "integer",
              "null"
            ]
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "session_id"
        ],
        "title": "ZoomInput",
        "type": "object"
      },
      "response_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "properties": {
          "level": {
            "description": "Level in percent now applied to the document.",
            "format": "uint32",
            "minimum": 0,
            "type": "integer"
          },
          "ok": {
            "type": "boolean"
          }
        },
        "required": [
          "level",
          "ok"
        ],
        "title": "ZoomOutput",
        "type": "object"
      }
    }
  ],
  "triggers": [
    {
      "description": "A console/log/exception entry was captured on a session's page.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by every `browser::*` trigger binding. The only filter is an optional session-id equality match; unknown fields fail at registration so a misspelled filter key fails loudly instead of silently receiving nothing.",
        "properties": {
          "session_id": {
            "description": "Only deliver events for this browser session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "browser::console-event",
      "return_schema": {}
    },
    {
      "description": "A download started, progressed, or finished in a session.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by every `browser::*` trigger binding. The only filter is an optional session-id equality match; unknown fields fail at registration so a misspelled filter key fails loudly instead of silently receiving nothing.",
        "properties": {
          "session_id": {
            "description": "Only deliver events for this browser session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "browser::download-changed",
      "return_schema": {}
    },
    {
      "description": "A session is paused waiting for a human to complete a step (CAPTCHA, 2FA, payment).",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by every `browser::*` trigger binding. The only filter is an optional session-id equality match; unknown fields fail at registration so a misspelled filter key fails loudly instead of silently receiving nothing.",
        "properties": {
          "session_id": {
            "description": "Only deliver events for this browser session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "browser::handoff-requested",
      "return_schema": {}
    },
    {
      "description": "A paused handoff finished (confirmed in page, by call, or timed out).",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by every `browser::*` trigger binding. The only filter is an optional session-id equality match; unknown fields fail at registration so a misspelled filter key fails loudly instead of silently receiving nothing.",
        "properties": {
          "session_id": {
            "description": "Only deliver events for this browser session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "browser::handoff-resolved",
      "return_schema": {}
    },
    {
      "description": "The session's page committed a navigation.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by every `browser::*` trigger binding. The only filter is an optional session-id equality match; unknown fields fail at registration so a misspelled filter key fails loudly instead of silently receiving nothing.",
        "properties": {
          "session_id": {
            "description": "Only deliver events for this browser session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "browser::navigated",
      "return_schema": {}
    },
    {
      "description": "A network request was captured (completed or failed) on a session's page.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by every `browser::*` trigger binding. The only filter is an optional session-id equality match; unknown fields fail at registration so a misspelled filter key fails loudly instead of silently receiving nothing.",
        "properties": {
          "session_id": {
            "description": "Only deliver events for this browser session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "browser::network-event",
      "return_schema": {}
    },
    {
      "description": "The human picked an element in inspect mode.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by every `browser::*` trigger binding. The only filter is an optional session-id equality match; unknown fields fail at registration so a misspelled filter key fails loudly instead of silently receiving nothing.",
        "properties": {
          "session_id": {
            "description": "Only deliver events for this browser session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "browser::picked",
      "return_schema": {}
    },
    {
      "description": "A Chromium session is up and ready.",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by every `browser::*` trigger binding. The only filter is an optional session-id equality match; unknown fields fail at registration so a misspelled filter key fails loudly instead of silently receiving nothing.",
        "properties": {
          "session_id": {
            "description": "Only deliver events for this browser session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "browser::session-started",
      "return_schema": {}
    },
    {
      "description": "A Chromium session ended (stopped, idle, or crashed).",
      "invocation_schema": {
        "$schema": "http://json-schema.org/draft-07/schema#",
        "additionalProperties": false,
        "description": "Config accepted by every `browser::*` trigger binding. The only filter is an optional session-id equality match; unknown fields fail at registration so a misspelled filter key fails loudly instead of silently receiving nothing.",
        "properties": {
          "session_id": {
            "description": "Only deliver events for this browser session.",
            "type": [
              "string",
              "null"
            ]
          }
        },
        "title": "BindingConfig",
        "type": "object"
      },
      "metadata": {},
      "name": "browser::session-stopped",
      "return_schema": {}
    }
  ]
}
```
