a789495a98
FreeBSD Smoke / FreeBSD Smoke (x86_64) (push) Has been cancelled
CI / Quality Guardrails (push) Has been cancelled
CI / Build & Test (macos-latest) (push) Has been cancelled
CI / Build & Test (ubuntu-latest) (push) Has been cancelled
CI / Build & Test (windows-latest) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / PowerShell Syntax (push) Has been cancelled
CI / Windows Cross-Target Check (Linux) (push) Has been cancelled
818 lines
17 KiB
Markdown
818 lines
17 KiB
Markdown
# Browser Provider Protocol
|
|
|
|
Status: draft
|
|
Owner: jcode
|
|
Audience: jcode core, browser bridge authors, adapter authors
|
|
|
|
## Why this exists
|
|
|
|
jcode should expose a single first-class `browser` tool while remaining compatible with multiple browser automation backends:
|
|
|
|
- Firefox Agent Bridge
|
|
- Chrome Agent Bridge
|
|
- Chrome remote debugging / CDP adapters
|
|
- WebDriver / BiDi adapters
|
|
- Safari automation adapters
|
|
- other third-party browser control systems
|
|
|
|
The protocol in this document defines the **normalized contract** between jcode and a browser provider.
|
|
|
|
This is intentionally **not** a demand that every bridge speak exactly the same native command language. Instead:
|
|
|
|
- jcode defines a **core semantic layer** it can rely on
|
|
- providers declare the capabilities and commands they support
|
|
- providers may expose **provider-specific commands** beyond the core
|
|
- adapters can translate a provider's native model into this protocol
|
|
|
|
That gives us both consistency and room for bridge-specific power features.
|
|
|
|
---
|
|
|
|
## Design goals
|
|
|
|
1. **One first-class tool in jcode**
|
|
- The model should use a single `browser` tool.
|
|
|
|
2. **Multiple provider implementations**
|
|
- Firefox, Chrome, Safari, Edge, WebDriver, and other systems should fit.
|
|
|
|
3. **Capability negotiation**
|
|
- jcode should know what each provider can and cannot do.
|
|
|
|
4. **Extensibility without fragmentation**
|
|
- We need a standard core, but providers must have room for browser-specific features.
|
|
|
|
5. **Stable session and element references**
|
|
- The model should be able to snapshot a page, then act on returned references.
|
|
|
|
6. **Transport-neutral semantics**
|
|
- The semantic protocol should be the same whether the provider is in-process, over stdio, over a socket, or wrapped through another adapter.
|
|
|
|
---
|
|
|
|
## Non-goals
|
|
|
|
1. Standardizing every low-level browser primitive.
|
|
2. Forcing all providers to support deep DOM, network, or JS introspection.
|
|
3. Requiring all providers to attach to the user's existing browser profile.
|
|
4. Making provider-specific commands part of the required core.
|
|
|
|
---
|
|
|
|
## Terminology
|
|
|
|
- **browser tool**: the user/model-facing jcode tool.
|
|
- **provider**: a backend implementation that satisfies this protocol.
|
|
- **bridge**: an external browser integration such as Firefox Agent Bridge.
|
|
- **adapter**: glue code that translates a bridge's native API into this protocol.
|
|
- **browser session**: the provider's isolated session or attachment scope for a jcode session.
|
|
- **page**: a tab, target, or browsing surface under a session.
|
|
- **element ref**: an opaque provider-issued handle for an actionable element.
|
|
|
|
---
|
|
|
|
## Conformance model
|
|
|
|
Providers do not need to implement everything.
|
|
|
|
### Core required for certification
|
|
|
|
A provider should support these normalized operations to be considered `certified`:
|
|
|
|
- `provider.describe`
|
|
- `provider.status`
|
|
- `session.ensure`
|
|
- `session.close`
|
|
- `page.open`
|
|
- `page.snapshot`
|
|
- `page.click`
|
|
- `page.type`
|
|
- `page.wait`
|
|
- `page.screenshot`
|
|
|
|
### Optional but recommended
|
|
|
|
- `page.go_back`
|
|
- `page.go_forward`
|
|
- `page.reload`
|
|
- `tab.list`
|
|
- `tab.activate`
|
|
- `tab.close`
|
|
- `page.eval`
|
|
- `page.press`
|
|
- `page.scroll`
|
|
- `page.select`
|
|
- `download.list`
|
|
|
|
### Provider-specific extensions
|
|
|
|
Providers may expose additional commands such as:
|
|
|
|
- `firefox.install_extension`
|
|
- `chrome.attach_debug_target`
|
|
- `cdp.send`
|
|
- `webdriver.perform_actions`
|
|
|
|
These are allowed, but they are not part of the required core.
|
|
|
|
---
|
|
|
|
## Transport model
|
|
|
|
This protocol defines **message semantics**, not one required wire format.
|
|
|
|
Supported implementation styles may include:
|
|
|
|
- direct Rust trait calls inside jcode
|
|
- stdio JSON request/response
|
|
- local socket RPC
|
|
- wrapped remote API
|
|
|
|
For external-process integrations, the recommended envelope is a JSON-RPC-like shape.
|
|
|
|
---
|
|
|
|
## Message envelope
|
|
|
|
For external providers, requests and responses should use a stable envelope.
|
|
|
|
### Request
|
|
|
|
```json
|
|
{
|
|
"protocol_version": "0.1",
|
|
"id": "req_123",
|
|
"method": "page.open",
|
|
"params": {
|
|
"session_id": "sess_abc",
|
|
"url": "https://example.com"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Success response
|
|
|
|
```json
|
|
{
|
|
"protocol_version": "0.1",
|
|
"id": "req_123",
|
|
"ok": true,
|
|
"result": {
|
|
"page_id": "page_1",
|
|
"url": "https://example.com",
|
|
"title": "Example Domain"
|
|
},
|
|
"warnings": []
|
|
}
|
|
```
|
|
|
|
### Error response
|
|
|
|
```json
|
|
{
|
|
"protocol_version": "0.1",
|
|
"id": "req_123",
|
|
"ok": false,
|
|
"error": {
|
|
"code": "unsupported_method",
|
|
"message": "This provider does not implement page.eval",
|
|
"retryable": false,
|
|
"details": {}
|
|
}
|
|
}
|
|
```
|
|
|
|
### Event envelope
|
|
|
|
If a provider emits async events, use:
|
|
|
|
```json
|
|
{
|
|
"protocol_version": "0.1",
|
|
"event": "page.navigated",
|
|
"payload": {
|
|
"session_id": "sess_abc",
|
|
"page_id": "page_1",
|
|
"url": "https://example.com/next"
|
|
}
|
|
}
|
|
```
|
|
|
|
Events are optional in v1.
|
|
|
|
---
|
|
|
|
## Discovery and handshake
|
|
|
|
### `provider.describe`
|
|
|
|
Returns static and semi-static metadata about the provider.
|
|
|
|
Example:
|
|
|
|
```json
|
|
{
|
|
"provider_id": "firefox_agent_bridge",
|
|
"provider_label": "Firefox Agent Bridge",
|
|
"provider_version": "1.2.3",
|
|
"protocol_version": "0.1",
|
|
"browser_families": ["firefox"],
|
|
"transport": "stdio-json",
|
|
"certification_tier": "candidate",
|
|
"capabilities": {
|
|
"core_methods": [
|
|
"session.ensure",
|
|
"session.close",
|
|
"page.open",
|
|
"page.snapshot",
|
|
"page.click",
|
|
"page.type",
|
|
"page.wait",
|
|
"page.screenshot"
|
|
],
|
|
"optional_methods": [
|
|
"tab.list",
|
|
"tab.activate",
|
|
"page.eval"
|
|
],
|
|
"features": [
|
|
"element_refs",
|
|
"a11y_snapshot",
|
|
"attach_existing_browser",
|
|
"persistent_profile"
|
|
],
|
|
"custom_methods": [
|
|
{
|
|
"name": "firefox.install_extension",
|
|
"stability": "experimental",
|
|
"description": "Install or verify the Firefox extension"
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
### `provider.status`
|
|
|
|
Returns current availability and setup state.
|
|
|
|
Example fields:
|
|
|
|
```json
|
|
{
|
|
"availability": "ready",
|
|
"browser_detected": true,
|
|
"browser_running": true,
|
|
"setup_state": "complete",
|
|
"requires_manual_setup": false,
|
|
"recommended_browser": "firefox",
|
|
"manual_steps": [],
|
|
"diagnostics": [
|
|
{
|
|
"level": "info",
|
|
"code": "native_host_detected",
|
|
"message": "Native host manifest found"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Suggested enums:
|
|
|
|
- `availability`: `ready | degraded | unavailable`
|
|
- `setup_state`: `complete | partial | required | broken`
|
|
|
|
---
|
|
|
|
## Session model
|
|
|
|
jcode should not care whether a provider uses tabs, contexts, profiles, or remote targets internally.
|
|
It only needs a stable handle it can reuse.
|
|
|
|
### `session.ensure`
|
|
|
|
Creates or reuses a browser session for a jcode session.
|
|
|
|
Request:
|
|
|
|
```json
|
|
{
|
|
"client_session_id": "jcode_session_123",
|
|
"browser_preference": "auto",
|
|
"isolation": "per_jcode_session",
|
|
"attach": "prefer",
|
|
"persist": true,
|
|
"metadata": {
|
|
"owner": "agent",
|
|
"purpose": "browser_tool"
|
|
}
|
|
}
|
|
```
|
|
|
|
Response:
|
|
|
|
```json
|
|
{
|
|
"session_id": "browser_sess_1",
|
|
"browser_family": "firefox",
|
|
"browser_label": "Firefox",
|
|
"attached_to_existing_browser": true,
|
|
"isolation": "per_jcode_session",
|
|
"default_page_id": "page_1"
|
|
}
|
|
```
|
|
|
|
### `session.close`
|
|
|
|
Closes or detaches the provider session.
|
|
|
|
Providers may choose whether this closes tabs, detaches from a target, or merely releases provider-side state. The behavior should be documented in `provider.describe` or `provider.status` diagnostics.
|
|
|
|
---
|
|
|
|
## Resource identifiers
|
|
|
|
All resource identifiers are opaque strings.
|
|
|
|
Examples:
|
|
|
|
- `session_id`
|
|
- `page_id`
|
|
- `tab_id`
|
|
- `element_ref`
|
|
- `download_id`
|
|
|
|
jcode must not assume identifier shape or encode browser semantics into them.
|
|
|
|
---
|
|
|
|
## Normalized core methods
|
|
|
|
These are the semantics jcode can rely on.
|
|
|
|
### `page.open`
|
|
|
|
Open a URL in the current page or a new page.
|
|
|
|
Request fields:
|
|
|
|
- `session_id` required
|
|
- `url` required
|
|
- `page_id` optional
|
|
- `new_page` optional
|
|
- `foreground` optional
|
|
- `wait_until` optional: `load | domcontentloaded | networkidle | provider_default`
|
|
|
|
Response fields:
|
|
|
|
- `page_id`
|
|
- `url`
|
|
- `title` optional
|
|
- `navigation_state` optional
|
|
|
|
### `page.snapshot`
|
|
|
|
Return a normalized view of the current page for agent reasoning.
|
|
|
|
This is the most important method for model use.
|
|
|
|
Request fields:
|
|
|
|
- `session_id` required
|
|
- `page_id` optional
|
|
- `include_screenshot` optional
|
|
- `include_html` optional
|
|
- `include_dom` optional
|
|
- `include_a11y` optional
|
|
- `include_text` optional
|
|
- `max_nodes` optional
|
|
|
|
Response fields:
|
|
|
|
- `page_id`
|
|
- `url`
|
|
- `title`
|
|
- `snapshot`
|
|
- `elements`
|
|
- `text`
|
|
- `screenshot_ref` optional
|
|
- `provider_data` optional
|
|
|
|
#### Snapshot shape
|
|
|
|
Providers may use different internal representations, but `page.snapshot` should normalize into a common minimum format:
|
|
|
|
```json
|
|
{
|
|
"snapshot": {
|
|
"format": "jcode.page_snapshot.v1",
|
|
"root": {
|
|
"node_id": "n1",
|
|
"role": "document",
|
|
"name": "Example Domain",
|
|
"children": ["n2", "n3"]
|
|
},
|
|
"nodes": [
|
|
{
|
|
"node_id": "n2",
|
|
"role": "heading",
|
|
"name": "Example Domain",
|
|
"text": "Example Domain",
|
|
"element_ref": "el_1",
|
|
"actionable": false
|
|
},
|
|
{
|
|
"node_id": "n3",
|
|
"role": "link",
|
|
"name": "More information...",
|
|
"text": "More information...",
|
|
"element_ref": "el_2",
|
|
"actionable": true
|
|
}
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
#### Element list
|
|
|
|
For agent convenience, providers should also return a flattened actionable list when possible:
|
|
|
|
```json
|
|
{
|
|
"elements": [
|
|
{
|
|
"element_ref": "el_2",
|
|
"role": "link",
|
|
"name": "More information...",
|
|
"text": "More information...",
|
|
"actionable": true,
|
|
"enabled": true,
|
|
"selector_hint": "a"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
A provider that cannot produce rich DOM/a11y data may still return a weaker snapshot, but it should say so in capabilities.
|
|
|
|
### `page.click`
|
|
|
|
Click an element.
|
|
|
|
Request should support multiple targeting modes:
|
|
|
|
- `element_ref`
|
|
- `selector`
|
|
- `text_query`
|
|
- `position`
|
|
|
|
At least one must be provided.
|
|
|
|
Response fields:
|
|
|
|
- `page_id`
|
|
- `clicked` boolean
|
|
- `navigation_occurred` optional
|
|
- `url` optional
|
|
|
|
Providers should prefer `element_ref` when available.
|
|
|
|
### `page.type`
|
|
|
|
Type or set text into an input-like target.
|
|
|
|
Request fields:
|
|
|
|
- `element_ref` optional
|
|
- `selector` optional
|
|
- `text` required
|
|
- `replace` optional
|
|
- `submit` optional
|
|
|
|
Response fields:
|
|
|
|
- `page_id`
|
|
- `typed` boolean
|
|
|
|
### `page.wait`
|
|
|
|
Wait for a condition.
|
|
|
|
Request fields may include:
|
|
|
|
- `text_present`
|
|
- `text_absent`
|
|
- `selector_present`
|
|
- `selector_absent`
|
|
- `element_ref_present`
|
|
- `url_matches`
|
|
- `navigation_complete`
|
|
- `timeout_ms`
|
|
|
|
Response fields:
|
|
|
|
- `satisfied` boolean
|
|
- `matched_condition` optional
|
|
- `url` optional
|
|
|
|
### `page.screenshot`
|
|
|
|
Capture a screenshot.
|
|
|
|
Request fields:
|
|
|
|
- `session_id`
|
|
- `page_id` optional
|
|
- `full_page` optional
|
|
- `clip` optional
|
|
- `element_ref` optional
|
|
|
|
Response fields:
|
|
|
|
- `page_id`
|
|
- `image` or `image_ref`
|
|
- `media_type`
|
|
- `width`
|
|
- `height`
|
|
|
|
Providers may return inline base64 data or a provider-managed image reference depending on transport constraints.
|
|
|
|
---
|
|
|
|
## Optional normalized methods
|
|
|
|
These methods are standardized when present, but not required for certification in the first pass.
|
|
|
|
### Navigation
|
|
|
|
- `page.go_back`
|
|
- `page.go_forward`
|
|
- `page.reload`
|
|
|
|
### Keyboard and form interaction
|
|
|
|
- `page.press`
|
|
- `page.select`
|
|
- `page.hover`
|
|
- `page.scroll`
|
|
|
|
### Tabs and pages
|
|
|
|
- `tab.list`
|
|
- `tab.activate`
|
|
- `tab.close`
|
|
- `tab.new`
|
|
|
|
### Introspection and debugging
|
|
|
|
- `page.eval`
|
|
- `network.list`
|
|
- `console.list`
|
|
- `storage.get`
|
|
- `cookie.list`
|
|
|
|
### Files and downloads
|
|
|
|
- `download.list`
|
|
- `download.wait`
|
|
- `upload.set_files`
|
|
|
|
---
|
|
|
|
## Extensibility model
|
|
|
|
This is the key part that allows leeway for provider-specific commands.
|
|
|
|
### Rule 1: providers may expose custom methods
|
|
|
|
Custom methods should use a namespaced method name, for example:
|
|
|
|
- `firefox.install_extension`
|
|
- `chrome.attach_debug_target`
|
|
- `cdp.send`
|
|
- `webdriver.actions`
|
|
|
|
### Rule 2: providers must advertise custom methods
|
|
|
|
Every custom method should appear in `provider.describe.capabilities.custom_methods` with:
|
|
|
|
- `name`
|
|
- `description`
|
|
- `stability`: `stable | experimental | deprecated`
|
|
- optional `input_schema`
|
|
- optional `output_schema`
|
|
|
|
### Rule 3: jcode core should only rely on normalized methods by default
|
|
|
|
The main `browser` tool should prefer the standard core and optional normalized methods.
|
|
Provider-specific methods should only be used when:
|
|
|
|
- the user explicitly asks for them
|
|
- a jcode-side adapter knows how to use them safely
|
|
- or a future advanced/debug mode is enabled
|
|
|
|
### Rule 4: provider-native passthrough is allowed, but should be explicit
|
|
|
|
If we want an escape hatch, the browser tool can support something like:
|
|
|
|
```json
|
|
{
|
|
"action": "provider_command",
|
|
"provider_method": "cdp.send",
|
|
"params": {
|
|
"method": "Network.enable"
|
|
}
|
|
}
|
|
```
|
|
|
|
This should be considered advanced/debug behavior, not the primary UX.
|
|
|
|
---
|
|
|
|
## Capability schema
|
|
|
|
Providers should report both methods and higher-level features.
|
|
|
|
### Methods
|
|
|
|
Concrete callable operations:
|
|
|
|
- `page.open`
|
|
- `page.snapshot`
|
|
- `tab.list`
|
|
|
|
### Features
|
|
|
|
Semantics or qualities that influence jcode behavior:
|
|
|
|
- `element_refs`
|
|
- `a11y_snapshot`
|
|
- `dom_snapshot`
|
|
- `html_snapshot`
|
|
- `full_page_screenshot`
|
|
- `attach_existing_browser`
|
|
- `persistent_profile`
|
|
- `isolated_contexts`
|
|
- `js_eval`
|
|
- `network_observe`
|
|
- `console_observe`
|
|
- `file_upload`
|
|
- `download_observe`
|
|
- `manual_setup_required`
|
|
- `extension_required`
|
|
- `remote_debugging_required`
|
|
|
|
### Stability
|
|
|
|
Each feature or method may optionally include a stability tag:
|
|
|
|
- `stable`
|
|
- `experimental`
|
|
- `deprecated`
|
|
|
|
---
|
|
|
|
## Setup and diagnostics
|
|
|
|
A browser provider often requires manual setup. The protocol should make that machine-readable.
|
|
|
|
### Diagnostic item
|
|
|
|
```json
|
|
{
|
|
"level": "warning",
|
|
"code": "extension_missing",
|
|
"message": "Firefox extension is not installed",
|
|
"manual_steps": [
|
|
"Open Firefox",
|
|
"Install the extension from /path/to/bridge.xpi",
|
|
"Restart Firefox if prompted"
|
|
]
|
|
}
|
|
```
|
|
|
|
### Recommended setup-oriented methods
|
|
|
|
- `provider.status`
|
|
- `provider.setup_guide` optional
|
|
- `provider.verify` optional
|
|
|
|
`provider.setup_guide` may return browser-specific instructions, URLs, file paths, permissions, or troubleshooting steps.
|
|
|
|
---
|
|
|
|
## Error model
|
|
|
|
Standard error codes should include:
|
|
|
|
- `unsupported_method`
|
|
- `unsupported_target`
|
|
- `invalid_request`
|
|
- `invalid_selector`
|
|
- `element_not_found`
|
|
- `element_not_actionable`
|
|
- `navigation_timeout`
|
|
- `not_ready`
|
|
- `setup_required`
|
|
- `permission_denied`
|
|
- `browser_not_running`
|
|
- `session_not_found`
|
|
- `page_not_found`
|
|
- `internal_error`
|
|
|
|
Providers may add provider-specific detail codes in `error.details`.
|
|
|
|
---
|
|
|
|
## Versioning
|
|
|
|
The protocol should be versioned independently from provider versions.
|
|
|
|
### Rules
|
|
|
|
- `protocol_version` identifies the semantic protocol version.
|
|
- Providers should declare the protocol version they implement.
|
|
- Minor additive changes should not break existing certified providers.
|
|
- Breaking changes require a new protocol version.
|
|
|
|
For now use:
|
|
|
|
- `protocol_version = "0.1"`
|
|
|
|
---
|
|
|
|
## Certification guidance
|
|
|
|
A provider can be classified as:
|
|
|
|
### Certified
|
|
|
|
- passes conformance tests for required core methods
|
|
- returns stable identifiers and normalized results
|
|
- reports setup/diagnostics correctly
|
|
- behaves predictably across repeated runs
|
|
|
|
### Compatible
|
|
|
|
- supports some or most normalized methods
|
|
- may have missing features or partial behavior
|
|
- useful, but not yet fully certified
|
|
|
|
### Experimental
|
|
|
|
- adapter exists, but semantics are incomplete or unstable
|
|
|
|
---
|
|
|
|
## Minimal conformance scenarios
|
|
|
|
A future conformance suite should verify at least:
|
|
|
|
1. `provider.describe` succeeds
|
|
2. `provider.status` reports a coherent state
|
|
3. `session.ensure` creates or reuses a session
|
|
4. `page.open` navigates to a test page
|
|
5. `page.snapshot` returns usable text and at least one actionable reference when applicable
|
|
6. `page.click` can activate a known element
|
|
7. `page.type` can fill a known input
|
|
8. `page.wait` observes a deterministic page change
|
|
9. `page.screenshot` returns an image
|
|
10. `session.close` cleans up or detaches cleanly
|
|
|
|
---
|
|
|
|
## Recommended jcode integration policy
|
|
|
|
The jcode `browser` tool should:
|
|
|
|
1. prefer normalized core methods
|
|
2. choose a provider based on user preference, availability, and capability quality
|
|
3. expose provider-specific methods only behind an explicit advanced path
|
|
4. return setup guidance when no ready provider is available
|
|
5. avoid baking Firefox-specific or Chrome-specific assumptions into the core tool API
|
|
|
|
---
|
|
|
|
## Open questions
|
|
|
|
These are intentionally left open for the next iteration.
|
|
|
|
1. Should screenshots always be inline, or can providers return file/image handles?
|
|
2. Should event streaming be required for advanced integrations?
|
|
3. How much of raw HTML/DOM should be normalized versus returned as provider data?
|
|
4. Should `page.snapshot` support multiple named formats beyond `jcode.page_snapshot.v1`?
|
|
5. Should provider-specific methods be invokable through the same `browser` tool or only via debug mode?
|
|
6. Should setup/install flows themselves be standardized beyond status and diagnostics?
|
|
|
|
---
|
|
|
|
## Proposed next steps
|
|
|
|
1. Review this document and tighten the core method set.
|
|
2. Decide the exact normalized `page.snapshot` format.
|
|
3. Define a Rust trait matching this protocol.
|
|
4. Implement the first provider adapter for Firefox Agent Bridge.
|
|
5. Build a conformance test harness.
|
|
6. Add README browser setup and compatibility documentation after the protocol stabilizes.
|