browser-pilot-cli 0.1.6 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +193 -27
- package/dist/cli.js +3882 -850
- package/dist/daemon.js +13749 -145
- package/dist/managed-target-janitor.js +490 -0
- package/docs/architecture/browser-pilot-platform-spec.md +965 -0
- package/docs/integration/stdio-bridge.md +614 -0
- package/docs/integration/stdio-conformance.md +51 -0
- package/docs/plans/browser-capability-evolution.md +410 -0
- package/docs/plans/universal-agent-integration.md +337 -0
- package/package.json +39 -6
- package/scripts/run-stdio-conformance.mjs +698 -0
- package/dist/chunk-77SA2ZLI.js +0 -18
- package/dist/defuddle-bundle-B7XUXIMB.js +0 -7
|
@@ -0,0 +1,965 @@
|
|
|
1
|
+
# Browser Pilot Platform Specification
|
|
2
|
+
|
|
3
|
+
Status: **Authoritative, approved for implementation**
|
|
4
|
+
Baseline: `0c5661ccb133b2c9feda15732892f66ce947f232`
|
|
5
|
+
Last updated: 2026-07-25
|
|
6
|
+
|
|
7
|
+
This document is the source of truth for turning Browser Pilot from a
|
|
8
|
+
single-agent CLI with global state into a user-level browser control runtime
|
|
9
|
+
that any local Agent can install or embed. The two execution plans in
|
|
10
|
+
`docs/plans/` derive from this specification.
|
|
11
|
+
|
|
12
|
+
## Purpose and Reader
|
|
13
|
+
|
|
14
|
+
This specification is for Browser Pilot maintainers, Agent-product integrators,
|
|
15
|
+
security reviewers, and test authors. It defines observable behavior and
|
|
16
|
+
compatibility boundaries before implementation. Internal component names near
|
|
17
|
+
the end are implementation boundaries required to preserve those behaviors;
|
|
18
|
+
they are not third-party APIs.
|
|
19
|
+
|
|
20
|
+
## Evidence and Assumptions
|
|
21
|
+
|
|
22
|
+
Evidence from the baseline repository:
|
|
23
|
+
|
|
24
|
+
- The npm package currently publishes CLI binaries but no library exports.
|
|
25
|
+
- High-level actions, output formatting, file writes, and process exits are
|
|
26
|
+
combined in `src/cli.ts`.
|
|
27
|
+
- `src/state.ts` persists one active target, CDP session, and frame context.
|
|
28
|
+
- `src/snapshot.ts` persists one target's refs in a global file.
|
|
29
|
+
- `src/daemon.ts` exposes arbitrary CDP and keeps auth, network, dialog, and
|
|
30
|
+
popup state globally.
|
|
31
|
+
- Existing fixtures prove the current browser operations are worth preserving.
|
|
32
|
+
|
|
33
|
+
Evidence from the browser-use comparison is recorded in
|
|
34
|
+
`docs/plans/browser-capability-evolution.md` at the pinned research commit.
|
|
35
|
+
|
|
36
|
+
Assumptions used by this specification:
|
|
37
|
+
|
|
38
|
+
- Supported Agent runtimes can spawn a local child process and read protected
|
|
39
|
+
local Artifact files.
|
|
40
|
+
- Browser Pilot and embedded Agents execute under the same OS user account.
|
|
41
|
+
- Chrome continues to require an explicit user action to enable or authorize
|
|
42
|
+
remote debugging.
|
|
43
|
+
- An Agent product can map its own active lifecycle to Workspace and Lease
|
|
44
|
+
without Broker knowledge of that product's domain nouns.
|
|
45
|
+
|
|
46
|
+
## Decision Summary
|
|
47
|
+
|
|
48
|
+
- **DEC-1:** Browser Pilot is an Agent-neutral, per-OS-user Browser Broker. It
|
|
49
|
+
is not a Tenon component and does not model conversations, runs, tasks, or
|
|
50
|
+
workers.
|
|
51
|
+
- **DEC-2:** Root Chrome DevTools Protocol (CDP) is the only browser connector.
|
|
52
|
+
Browser extensions are never required or supported.
|
|
53
|
+
- **DEC-3:** The public product surface is one official CLI executable. It
|
|
54
|
+
supports human one-shot commands and a persistent `bridge --stdio` machine
|
|
55
|
+
mode. Native SDK and MCP surfaces are out of scope.
|
|
56
|
+
- **DEC-4:** Existing one-shot `bp` commands remain a first-class integration
|
|
57
|
+
path. Embedded products bundle the same executable and use the stdio bridge.
|
|
58
|
+
- **DEC-5:** The production machine interface exposes controlled browser tools,
|
|
59
|
+
not arbitrary CDP forwarding. Raw CDP is internal. JavaScript evaluation is
|
|
60
|
+
an explicit developer capability.
|
|
61
|
+
- **DEC-6:** Invoking Browser Pilot grants the Agent full control of all
|
|
62
|
+
eligible current and future tabs in the selected BrowserInstance. Browser
|
|
63
|
+
Pilot does not implement task-intent approval, selected-tab grants, or
|
|
64
|
+
per-action confirmation. An Agent host may remove operations when launching
|
|
65
|
+
the Broker, and owns any higher-level approval UX it wants.
|
|
66
|
+
- **DEC-7:** Browser profile state is shared because controlled targets run in
|
|
67
|
+
the user's browser profile. Target assignments, commands, refs, rules, and
|
|
68
|
+
artifacts are isolated by Broker objects.
|
|
69
|
+
|
|
70
|
+
## Objective, Constraints, and Selected Target
|
|
71
|
+
|
|
72
|
+
- **OBJ-1:** Any local Agent that can execute a process must be able to control
|
|
73
|
+
the user's real browser reliably, while preserving the user's profiles,
|
|
74
|
+
logins, cookies, and installed extensions.
|
|
75
|
+
- **OBJ-2:** Multiple unrelated Agent products must be able to use Browser Pilot
|
|
76
|
+
concurrently without overwriting each other's target, frame, ref, auth, or
|
|
77
|
+
network state.
|
|
78
|
+
- **OBJ-3:** Agents that already install and call `bp` themselves must continue
|
|
79
|
+
to work after the platform migration.
|
|
80
|
+
- **Minimum acceptable outcome:** The compatibility requirements in this spec
|
|
81
|
+
all pass. A partial SDK, Tenon-only adapter, or globally shared target state
|
|
82
|
+
does not count.
|
|
83
|
+
- **Clean-slate answer:** A signed, self-contained executable with a local
|
|
84
|
+
Broker, versioned stdio protocol, complete browser control, strong runtime
|
|
85
|
+
isolation, and a conformance kit.
|
|
86
|
+
- **Selected brownfield target:** Evolve the current TypeScript/npm CLI into
|
|
87
|
+
that architecture without replacing proven CDP capabilities or breaking the
|
|
88
|
+
current command workflow.
|
|
89
|
+
|
|
90
|
+
### Constraints
|
|
91
|
+
|
|
92
|
+
- **CON-1 hard:** No browser extension may be used.
|
|
93
|
+
- **CON-2 hard:** All eligible ordinary Chrome tabs in the selected
|
|
94
|
+
BrowserInstance are visible and controllable. DevTools, unsupported internal
|
|
95
|
+
pages, and Browser Pilot's own internal targets remain excluded.
|
|
96
|
+
- **CON-3 hard:** Browser Pilot must not depend on Agent-specific lifecycle
|
|
97
|
+
concepts or model-provider APIs.
|
|
98
|
+
- **CON-4 hard:** Production clients cannot invoke arbitrary root CDP methods.
|
|
99
|
+
- **CON-5 hard:** Sensitive browser data and media must not be emitted to logs
|
|
100
|
+
or world-readable files.
|
|
101
|
+
- **CON-6 legacy:** Existing `bp` commands, JSON output, npm installation, and
|
|
102
|
+
the current Agent skill must remain usable during migration.
|
|
103
|
+
- **CON-7 platform:** Without an extension, root CDP exposes the browser to any
|
|
104
|
+
process that can independently reach its debugging endpoint. Broker
|
|
105
|
+
isolation protects Broker clients from each other; it is not an OS sandbox.
|
|
106
|
+
- **CON-8 scope:** The universal integration target is local Agents that can
|
|
107
|
+
spawn a process and access local files. Hosted Agents without a local
|
|
108
|
+
execution bridge are not supported by CLI-only distribution.
|
|
109
|
+
|
|
110
|
+
### Rejected Alternatives
|
|
111
|
+
|
|
112
|
+
- **OPT-1 MCP as the canonical interface:** Rejected because it creates a
|
|
113
|
+
second public product surface and runtime dependency. An Agent adapter may
|
|
114
|
+
translate the stdio bridge to MCP outside Browser Pilot.
|
|
115
|
+
- **OPT-2 Native SDKs:** Rejected because every language binding would create a
|
|
116
|
+
versioned compatibility obligation. The executable protocol is the SDK.
|
|
117
|
+
- **OPT-3 One-shot CLI only:** Rejected because it cannot efficiently deliver
|
|
118
|
+
events, cancellation, leases, or repeated tool calls to an embedded Agent.
|
|
119
|
+
- **OPT-4 Agent-specific embedding:** Rejected because Tenon and OpenClaw are
|
|
120
|
+
clients and conformance fixtures, not Broker domain concepts.
|
|
121
|
+
|
|
122
|
+
### Revisit Triggers
|
|
123
|
+
|
|
124
|
+
Reconsider MCP or a remote protocol only if Browser Pilot must support Agents
|
|
125
|
+
that cannot spawn a local process. Reconsider SDKs only if the stdio protocol
|
|
126
|
+
cannot provide required performance or type safety after measured use.
|
|
127
|
+
|
|
128
|
+
## Preserved and Changed Behavior
|
|
129
|
+
|
|
130
|
+
### Preserved
|
|
131
|
+
|
|
132
|
+
- Agent-managed installation via npm and direct `bp` invocation.
|
|
133
|
+
- Chrome remote-debugging discovery and connection.
|
|
134
|
+
- A distinct visible Pilot window using the user's browser profile.
|
|
135
|
+
- AX snapshots and numbered refs.
|
|
136
|
+
- Navigation, click, type, keyboard, upload, tabs, frames, dialogs, HTTP auth,
|
|
137
|
+
screenshots, PDF, cookies, and network tooling.
|
|
138
|
+
- Human-readable terminal output and JSON output for scripts.
|
|
139
|
+
- The existing skill and Playwright fixture coverage.
|
|
140
|
+
|
|
141
|
+
### Changed
|
|
142
|
+
|
|
143
|
+
- CLI handlers become presentation adapters over reusable Broker services.
|
|
144
|
+
- Global active target/session/frame state becomes isolated Workspace and Lease
|
|
145
|
+
state.
|
|
146
|
+
- The single refs file becomes observation-scoped Broker state.
|
|
147
|
+
- The daemon's arbitrary `/cdp` endpoint becomes private implementation wiring.
|
|
148
|
+
- Dialogs become explicit events and decisions; they are not auto-accepted.
|
|
149
|
+
- Popup adoption requires a verified owned opener chain.
|
|
150
|
+
- Existing user tabs and newly opened tabs are included automatically in the
|
|
151
|
+
Workspace inventory; invoking the tool is the authorization boundary.
|
|
152
|
+
- Auth, network rules, request journals, and artifacts are scoped and cleaned up
|
|
153
|
+
by the owning Workspace or Lease.
|
|
154
|
+
- Screenshots and PDFs become mode-restricted, owner-scoped Artifact results
|
|
155
|
+
with quotas and expiry. The human CLI may export an Artifact to a
|
|
156
|
+
caller-selected path.
|
|
157
|
+
|
|
158
|
+
## Product Model
|
|
159
|
+
|
|
160
|
+
### ClientPrincipal
|
|
161
|
+
|
|
162
|
+
A stable identity for an installed Agent product or direct CLI user. It owns
|
|
163
|
+
Workspaces and their transient resources. It is used for correlation and
|
|
164
|
+
isolation, not as proof that an Agent's semantic decision is correct. A
|
|
165
|
+
Principal is not a conversation or task.
|
|
166
|
+
|
|
167
|
+
### ClientConnection
|
|
168
|
+
|
|
169
|
+
One live `bridge --stdio` process connection. It is authenticated by the local
|
|
170
|
+
Broker and associated with exactly one ClientPrincipal after initialization.
|
|
171
|
+
|
|
172
|
+
### BrowserInstance
|
|
173
|
+
|
|
174
|
+
One running, discoverable Chromium-family browser process identified by a
|
|
175
|
+
process-stable identity, product, profile path, debugging endpoint, and
|
|
176
|
+
connection generation.
|
|
177
|
+
|
|
178
|
+
### BrowserWorkspace
|
|
179
|
+
|
|
180
|
+
A logical browser working set owned by one ClientPrincipal. It owns one or more
|
|
181
|
+
ManagedTabSets and transient scoped state. Workspaces live in Broker memory by
|
|
182
|
+
default and are recreated after Broker restart; Agent adapters map their own
|
|
183
|
+
active lifecycle to this object.
|
|
184
|
+
|
|
185
|
+
### ManagedTabSet
|
|
186
|
+
|
|
187
|
+
The logical collection of Broker-created tabs used for isolated Agent work. It
|
|
188
|
+
is normally backed by a dedicated visible Pilot window because Browser Pilot
|
|
189
|
+
does not use extension-only native tab-group APIs. New task navigation and
|
|
190
|
+
owned popups stay in this set by default. Workspace cleanup may close this set,
|
|
191
|
+
but never user-owned tabs outside it.
|
|
192
|
+
|
|
193
|
+
### ControlLease
|
|
194
|
+
|
|
195
|
+
A time-bounded command session in a Workspace. It carries negotiated
|
|
196
|
+
capabilities, heartbeat expiry, and explicit target control assignments. Agent
|
|
197
|
+
adapters map their own active work lifecycle to this object.
|
|
198
|
+
|
|
199
|
+
### BrowserControlPolicy
|
|
200
|
+
|
|
201
|
+
An optional launch-time reduction of Browser Pilot operations configured by
|
|
202
|
+
the Agent host, for example disabling `network.modify` or `tabs.close`. The
|
|
203
|
+
default policy allows every supported operation. This is tool exposure, not a
|
|
204
|
+
Browser Pilot approval lifecycle, and it cannot be expanded through a tool call
|
|
205
|
+
inside the running bridge.
|
|
206
|
+
|
|
207
|
+
### ControlledTarget
|
|
208
|
+
|
|
209
|
+
A target addressable by a Workspace. Its origin is `managed`, `managed_popup`,
|
|
210
|
+
or `user_tab`, and it records an optional ManagedTabSet. A user tab retains user
|
|
211
|
+
ownership: releasing a Workspace removes Broker mappings without closing the
|
|
212
|
+
tab. Every result identifies its Workspace, Lease, opaque controlled-target ID,
|
|
213
|
+
URL, origin, and browser connection generation. Raw CDP target IDs are not a
|
|
214
|
+
public identifier.
|
|
215
|
+
|
|
216
|
+
### Observation
|
|
217
|
+
|
|
218
|
+
An immutable, bounded view of a ControlledTarget at a point in time. Public element
|
|
219
|
+
handles are `observationId + ref`. Observations are never shared between
|
|
220
|
+
Workspaces.
|
|
221
|
+
|
|
222
|
+
### AgentHint
|
|
223
|
+
|
|
224
|
+
A bounded, discriminated browser-state signal attached to an Observation or
|
|
225
|
+
event. A hint has a stable `code`, `source`, `confidence`, and
|
|
226
|
+
`recommendedAction`, plus code-specific public data. Hints report browser
|
|
227
|
+
evidence and a useful next inspection strategy; they never approve an action,
|
|
228
|
+
assert that the task succeeded, or replace fresh Observation and event state.
|
|
229
|
+
|
|
230
|
+
### Command
|
|
231
|
+
|
|
232
|
+
A requested operation with a unique command ID, idempotency key, deadline,
|
|
233
|
+
capability requirement, and target assignment. Each target serializes its
|
|
234
|
+
commands through one actor.
|
|
235
|
+
|
|
236
|
+
### Artifact
|
|
237
|
+
|
|
238
|
+
A Broker-managed binary result such as a screenshot, preview, PDF, or download.
|
|
239
|
+
Artifacts have metadata, sensitivity, ownership, size limits, retention state,
|
|
240
|
+
and expiry.
|
|
241
|
+
|
|
242
|
+
### BrowserEvent
|
|
243
|
+
|
|
244
|
+
A typed, ordered event in a bounded per-Workspace journal. Events can be pushed
|
|
245
|
+
over stdio and replayed with a cursor. Every event carries the browser connection
|
|
246
|
+
generation of its source. Ordinary events from a retired generation are dropped;
|
|
247
|
+
Command terminal state and explicit reconnect cleanup remain replayable with
|
|
248
|
+
their historical generation.
|
|
249
|
+
|
|
250
|
+
## Public Executable Surface
|
|
251
|
+
|
|
252
|
+
The official distribution exposes one executable under both `browser-pilot`
|
|
253
|
+
and the compatible `bp` alias.
|
|
254
|
+
|
|
255
|
+
```text
|
|
256
|
+
browser-pilot
|
|
257
|
+
broker serve
|
|
258
|
+
bridge --stdio
|
|
259
|
+
tool list
|
|
260
|
+
tool call
|
|
261
|
+
artifact export|release
|
|
262
|
+
browsers|connect|disconnect|open|snapshot|click|type|keyboard|press
|
|
263
|
+
read|eval|upload|screenshot|pdf|cookies|frame|auth|tabs|tab|close|net
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Three distribution modes are equivalent:
|
|
267
|
+
|
|
268
|
+
1. User or Agent global installation.
|
|
269
|
+
2. Project-local installation and `npx browser-pilot` invocation.
|
|
270
|
+
3. Product-bundled official executable launched by an Agent adapter.
|
|
271
|
+
|
|
272
|
+
Embedded products must not import `src/*`, depend on daemon socket details, or
|
|
273
|
+
parse human-readable output.
|
|
274
|
+
|
|
275
|
+
The npm distribution contains bundled JavaScript entry points for the CLI,
|
|
276
|
+
Broker, and managed-target janitor and requires Node 18 or newer. The native
|
|
277
|
+
distribution is one Node SEA executable containing the runtime and JavaScript
|
|
278
|
+
dependencies. It re-executes itself with reserved private role arguments for
|
|
279
|
+
Broker and janitor processes; it neither downloads a runtime nor falls back to
|
|
280
|
+
system Node. Both layouts derive executable installation identity from the
|
|
281
|
+
public entry point, so private child roles do not create false version
|
|
282
|
+
boundaries.
|
|
283
|
+
|
|
284
|
+
Native artifacts are built and verified on their target OS and architecture.
|
|
285
|
+
Each archive includes an actual-state signature descriptor, file sizes and
|
|
286
|
+
SHA-256 hashes, runtime/dependency licenses, and an archive checksum. macOS uses
|
|
287
|
+
Developer ID signing with hardened runtime and explicit JIT entitlements when
|
|
288
|
+
credentials exist, otherwise ad-hoc signing. Windows uses Authenticode when a
|
|
289
|
+
certificate exists, otherwise records unsigned state. Linux records unsigned
|
|
290
|
+
state. Build or release automation must fail on incomplete credentials and
|
|
291
|
+
must never describe an artifact as signed when signing did not run.
|
|
292
|
+
|
|
293
|
+
### Broker Locator and Startup
|
|
294
|
+
|
|
295
|
+
The executable, not an embedding Host, resolves the per-user Broker endpoint.
|
|
296
|
+
On Unix it uses an owner-only domain socket and falls back to a deterministic
|
|
297
|
+
short owner-specific runtime directory when the state path would exceed
|
|
298
|
+
portable socket limits. On Windows it uses a named pipe derived from the OS
|
|
299
|
+
user identity. Persistent state defaults to the Browser Pilot user directory
|
|
300
|
+
(`%LOCALAPPDATA%\\Browser Pilot` on Windows). An explicit absolute
|
|
301
|
+
`BROWSER_PILOT_HOME` is the cross-platform installation-level isolation
|
|
302
|
+
override. It is never selected automatically.
|
|
303
|
+
|
|
304
|
+
State/runtime directories are mode `0700` and regular metadata files are mode
|
|
305
|
+
`0600` where POSIX modes apply. The socket is mode `0600`; Windows relies on the
|
|
306
|
+
creating user's process-token DACL for its local named pipe. Symlinked final
|
|
307
|
+
directories and metadata, foreign ownership, unexpected file types, and
|
|
308
|
+
overly-permissive metadata are rejected.
|
|
309
|
+
|
|
310
|
+
The versioned locator records PID, endpoint/transport, start time, Broker
|
|
311
|
+
process identity, service version, executable installation identity/path, and
|
|
312
|
+
the supported protocol range. A separate owner-only `broker-versions.json`
|
|
313
|
+
keeps only the current and immediately previous executable metadata for
|
|
314
|
+
diagnosis and explicit rollback; it does not preserve an executable or any
|
|
315
|
+
browser, target, Workspace, Lease, ref, credential, rule, or command state. An
|
|
316
|
+
atomic owner-recorded startup lock surrounds discovery and daemon launch. Every
|
|
317
|
+
contender health-checks before and after the lock; therefore exactly one
|
|
318
|
+
process starts the Broker and all others reuse it. Broker startup and discovery
|
|
319
|
+
are passive and do not open a browser WebSocket.
|
|
320
|
+
A lock whose owner is dead can be reclaimed; a live owner is never displaced
|
|
321
|
+
merely because startup is slow. During Broker startup, the daemon writes an
|
|
322
|
+
owner-only `starting` process record. Chrome authorization begins only after an
|
|
323
|
+
explicit `browser.connect`; all concurrent callers share its single in-flight
|
|
324
|
+
connection attempt. A dead
|
|
325
|
+
locator/socket is removed without signaling its recorded PID. If a ready PID is
|
|
326
|
+
alive but its endpoint is unresponsive, Browser Pilot returns structured
|
|
327
|
+
restart remediation and never silently kills or replaces the process.
|
|
328
|
+
|
|
329
|
+
## Primary Flows
|
|
330
|
+
|
|
331
|
+
### FLOW-1 Agent-managed one-shot use
|
|
332
|
+
|
|
333
|
+
An Agent installs Browser Pilot globally or in its project and runs `bp connect`.
|
|
334
|
+
The CLI starts or reuses the compatible per-user Broker, creates its
|
|
335
|
+
compatibility Workspace and Lease, then explicitly requests the browser
|
|
336
|
+
connection. Other browser commands require that connection and never trigger
|
|
337
|
+
authorization implicitly.
|
|
338
|
+
Existing and future eligible user tabs are available immediately. The command
|
|
339
|
+
returns the existing JSON shape during migration. Failures include a stable
|
|
340
|
+
machine code in addition to compatible human guidance. One-shot processes use
|
|
341
|
+
a fixed daemon-internal Connection, idempotently keyed Workspace, and renewable
|
|
342
|
+
Lease with a maximum five-minute TTL. Normal process exit leaves that transient
|
|
343
|
+
daemon-memory state available to the next command; expiry invalidates refs and
|
|
344
|
+
releases target control. No target, frame, session, Observation, ref, auth, or
|
|
345
|
+
network mapping is persisted to disk. `bp disconnect` explicitly releases the
|
|
346
|
+
compatibility Workspace and closes only its managed targets. It stops the
|
|
347
|
+
daemon only when called by the matching executable installation and no live
|
|
348
|
+
embedded Connection remains; otherwise it returns `protocol_incompatible` or
|
|
349
|
+
`broker_in_use` without replacing or terminating the Broker. JavaScript dialogs
|
|
350
|
+
remain pending and are handled explicitly with `bp dialogs` and `bp dialog`;
|
|
351
|
+
Workspace isolation prevents access to other clients' dialogs.
|
|
352
|
+
|
|
353
|
+
### FLOW-2 Product-embedded use
|
|
354
|
+
|
|
355
|
+
An Agent product bundles or resolves the official executable and starts
|
|
356
|
+
`browser-pilot bridge --stdio`. It initializes, negotiates protocol and
|
|
357
|
+
capabilities, creates or resumes a Workspace, acquires a Lease, discovers tools,
|
|
358
|
+
calls `browser.connect` when the selected browser is not ready, and maps the
|
|
359
|
+
remaining tools into its own runtime. Bridge launch, initialization, discovery,
|
|
360
|
+
and Workspace creation stay passive. It calls tools, consumes ordered
|
|
361
|
+
events, converts Artifact files into native media content, heartbeats while
|
|
362
|
+
active, then releases the Lease. A process crash is recovered by Lease expiry.
|
|
363
|
+
|
|
364
|
+
### FLOW-3 Browser disconnect and recovery
|
|
365
|
+
|
|
366
|
+
The Broker emits connection loss, stops dispatching target commands, and marks
|
|
367
|
+
commands whose effects are uncertain as `unknown_outcome`. It never reconnects
|
|
368
|
+
on a timer. A client explicitly calls `browser.connect` when recovery is
|
|
369
|
+
appropriate. After that succeeds, the Broker
|
|
370
|
+
creates a new browser connection generation, invalidates old CDP sessions,
|
|
371
|
+
ControlledTarget mappings, frames, and Observations, and emits structured recovery
|
|
372
|
+
state. The daemon rediscovers only the originally selected browser profile; it
|
|
373
|
+
does not silently switch to another running browser. Consumers rebuild inventory
|
|
374
|
+
with `browser.tabs.list`. Browser Pilot never replays a mutating command
|
|
375
|
+
automatically.
|
|
376
|
+
|
|
377
|
+
### FLOW-4 Concurrent clients
|
|
378
|
+
|
|
379
|
+
Two unrelated Principals create separate Workspaces and Pilot targets. Their
|
|
380
|
+
actions may execute concurrently on different target actors. Any attempt to use
|
|
381
|
+
the other Principal's target, ref, rule, Artifact, or Workspace fails closed.
|
|
382
|
+
Releasing or crashing one client does not close or mutate the other's targets.
|
|
383
|
+
|
|
384
|
+
### FLOW-5 Existing and future user tabs
|
|
385
|
+
|
|
386
|
+
When a Host exposes Browser Pilot to an Agent, that invocation authorizes the
|
|
387
|
+
Agent to use the selected BrowserInstance. `tabs.list` immediately returns the
|
|
388
|
+
Workspace's ManagedTabSets plus all eligible user tabs, tagged by origin. Tabs
|
|
389
|
+
opened later appear on the next inventory refresh. The Agent may switch to and
|
|
390
|
+
operate any listed tab, including a form the user opened before invoking it.
|
|
391
|
+
|
|
392
|
+
Browser Pilot does not ask the Agent to request access and does not display a
|
|
393
|
+
grant UI. If a product needs confirmation or restricted tool exposure, the
|
|
394
|
+
Agent host implements that policy before launching the bridge or maps it to a
|
|
395
|
+
launch-time BrowserControlPolicy. Releasing a Lease or Workspace removes
|
|
396
|
+
transient mappings and rules but leaves user tabs open. Closing a user tab
|
|
397
|
+
always requires an explicit target-specific command; bulk cleanup applies only
|
|
398
|
+
to ManagedTabSets.
|
|
399
|
+
|
|
400
|
+
## Machine Protocol
|
|
401
|
+
|
|
402
|
+
`bridge --stdio` uses JSON-RPC 2.0 over newline-delimited UTF-8 JSON. Each line
|
|
403
|
+
contains one complete message. Stdout is protocol-only. Logs go to stderr and
|
|
404
|
+
must redact secrets. The bridge terminates on malformed framing after returning
|
|
405
|
+
a protocol error when possible.
|
|
406
|
+
|
|
407
|
+
Required methods:
|
|
408
|
+
|
|
409
|
+
```text
|
|
410
|
+
initialize
|
|
411
|
+
tools/list
|
|
412
|
+
tools/call
|
|
413
|
+
workspaces/create|get|release
|
|
414
|
+
leases/create|heartbeat|release
|
|
415
|
+
commands/cancel|get
|
|
416
|
+
events/poll
|
|
417
|
+
artifacts/import|get|export|retain|release
|
|
418
|
+
shutdown
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Asynchronous events use best-effort `events/event` JSON-RPC notifications.
|
|
422
|
+
Polling with a cursor is the authoritative recovery path after reconnect,
|
|
423
|
+
notification loss, or backpressure. Notifications and responses may interleave.
|
|
424
|
+
|
|
425
|
+
### Initialization
|
|
426
|
+
|
|
427
|
+
The client sends its product identity, instance identity, supported protocol
|
|
428
|
+
range, requested capabilities, launch mode, and optional protocol 1.1 transport
|
|
429
|
+
limits. The response includes:
|
|
430
|
+
|
|
431
|
+
- service and executable versions;
|
|
432
|
+
- selected protocol version;
|
|
433
|
+
- supported and granted capabilities;
|
|
434
|
+
- Broker process identity and connection ID;
|
|
435
|
+
- browser discovery and authorization state;
|
|
436
|
+
- transport and result size limits.
|
|
437
|
+
|
|
438
|
+
Initialization must fail with a structured incompatibility error when no
|
|
439
|
+
protocol overlap exists. A newer executable must not silently replace an
|
|
440
|
+
incompatible Broker that has live clients.
|
|
441
|
+
|
|
442
|
+
Protocol 1.0 clients use the service transport ceilings. Protocol 1.1 clients
|
|
443
|
+
may declare maximum message and result byte sizes; the Broker selects the lower
|
|
444
|
+
client/service value per Connection. Initialization itself uses fixed bootstrap
|
|
445
|
+
ceilings, and pipelined messages after initialize are not parsed until the
|
|
446
|
+
selected limits take effect. Artifact and journal capacities remain service
|
|
447
|
+
resource limits. Pending ordinary and out-of-band control calls have separate
|
|
448
|
+
bounds so overload cannot create an unbounded Promise queue or prevent dialog
|
|
449
|
+
and cancellation control from overtaking a blocked action.
|
|
450
|
+
|
|
451
|
+
### Tool Contract
|
|
452
|
+
|
|
453
|
+
`tools/list` is the canonical machine-readable manifest. Every tool declares:
|
|
454
|
+
|
|
455
|
+
- stable name and description;
|
|
456
|
+
- JSON input schema;
|
|
457
|
+
- output schema and possible Artifact kinds;
|
|
458
|
+
- required capabilities;
|
|
459
|
+
- whether it may mutate browser state;
|
|
460
|
+
- cancellation and idempotency semantics;
|
|
461
|
+
- sensitivity classification.
|
|
462
|
+
|
|
463
|
+
The tool-level `sensitivity.input` and `sensitivity.output` arrays declare every
|
|
464
|
+
classification that may occur in that direction. Content-bearing input and
|
|
465
|
+
output schema nodes use `x-browser-pilot-sensitivity` to identify the specific
|
|
466
|
+
fields an adapter must taint when it maps values into model text, image, or file
|
|
467
|
+
content. The manifest validator rejects unknown, duplicate, or field-level
|
|
468
|
+
classifications missing from the tool-level declaration. Schema annotations do
|
|
469
|
+
not change the call or result value shape.
|
|
470
|
+
|
|
471
|
+
`tools/call` returns `{ command, result?, error? }`; each manifest output schema
|
|
472
|
+
describes the inner `result`. Callers may provide an opaque Command ID,
|
|
473
|
+
idempotency key, and relative deadline. `commands/get` and `commands/cancel`
|
|
474
|
+
accept a Command ID plus its Workspace ID when applicable. They authorize by
|
|
475
|
+
ClientPrincipal ownership so a replacement Connection can inspect known state
|
|
476
|
+
without inheriting the original Lease.
|
|
477
|
+
|
|
478
|
+
Action results include bounded typed evidence where Browser Pilot can observe
|
|
479
|
+
an effect. Ref clicks combine local control state and composed focus changes
|
|
480
|
+
with Broker-owned navigation, normalized document, dialog, and attributable
|
|
481
|
+
popup signals. `verified` means at least one supported effect was observed,
|
|
482
|
+
`mismatch` means an observable control did not reach its expected state, and
|
|
483
|
+
`unavailable` means dispatch completed without conclusive evidence. Evidence is
|
|
484
|
+
not a claim that the Agent's higher-level business goal succeeded.
|
|
485
|
+
Input evidence is discriminated as `type` or `keyboard`; press evidence uses the
|
|
486
|
+
focused backend node plus bounded control-state signatures and Broker-owned
|
|
487
|
+
signals. Upload evidence reads the selected file count and compares its browser
|
|
488
|
+
filename without returning the local source path.
|
|
489
|
+
|
|
490
|
+
Observation-producing tools also return `hints`. Observation-derived codes
|
|
491
|
+
cover explicit autocomplete surfaces, modal overlays, explicit filter controls,
|
|
492
|
+
and authentication surface transitions; action results may add a repeated
|
|
493
|
+
observable no-progress hint. Hint refs are numbered refs from that Observation
|
|
494
|
+
only. Page collection returns counts and refs, never page text, input values,
|
|
495
|
+
passwords, selectors, raw nodes, or CDP identifiers for this classification.
|
|
496
|
+
Blocked main-document responses and download lifecycle hints are event-derived.
|
|
497
|
+
|
|
498
|
+
`hints` is an additive schema field under protocol 1.0 and 1.1. The built-in
|
|
499
|
+
Browser tool implementation always returns the array, including an empty array;
|
|
500
|
+
the manifest leaves the field optional so compatible older executors remain
|
|
501
|
+
valid. Existing clients already ignore unknown response fields. No new
|
|
502
|
+
capability is negotiated because hints expose no operation and contain only
|
|
503
|
+
bounded derivatives of browser data already authorized by `observation.read`
|
|
504
|
+
or `event.read`.
|
|
505
|
+
|
|
506
|
+
Composite input actions pin the ControlledTarget, CDP session, selected frame,
|
|
507
|
+
loader, Document identity, and browser connection generation for the lifetime
|
|
508
|
+
of the action. After focus is established, `type` and `keyboard` also pin the
|
|
509
|
+
deep composed active element. Browser Pilot checks this identity before every
|
|
510
|
+
remaining semantic step, including select-all, deletion, each keyboard
|
|
511
|
+
character, and optional submit. A change before the first browser mutation is
|
|
512
|
+
a retryable `action_not_verified`; a change after any step was dispatched is
|
|
513
|
+
`unknown_outcome` with bounded `action`, `step`, `reason`, `dispatchedSteps`,
|
|
514
|
+
and `remainingStepsStopped` context. No remaining step is sent to the changed
|
|
515
|
+
page and the command is never replayed automatically.
|
|
516
|
+
|
|
517
|
+
The initial controlled tool families are browser discovery/status, Workspace
|
|
518
|
+
and Lease lifecycle, open/observe/read, click/type/keyboard/press,
|
|
519
|
+
capture/upload, tabs/frames, dialogs, auth/cookies, network, events, and
|
|
520
|
+
Artifacts. Raw CDP is never listed. `eval` requires `developer.eval`.
|
|
521
|
+
|
|
522
|
+
## Access and Isolation Rules
|
|
523
|
+
|
|
524
|
+
- **BR-1:** A public command can address a ControlledTarget only through its
|
|
525
|
+
Workspace and a valid ControlLease.
|
|
526
|
+
- **BR-2:** Managed targets enter a Workspace through Broker creation and a
|
|
527
|
+
verified managed-popup opener chain. Eligible user tabs enter through target
|
|
528
|
+
inventory. Public commands use opaque ControlledTarget IDs; Agent-supplied
|
|
529
|
+
raw CDP identifiers are never accepted as public handles.
|
|
530
|
+
- **BR-3:** Closing or releasing a Workspace may close its ManagedTabSets, but
|
|
531
|
+
must not close user tabs merely because they were visible or controlled. It
|
|
532
|
+
affects only its own mappings, rules, credentials, journals, and Artifacts.
|
|
533
|
+
- **BR-4:** Network and auth configuration is not global. Precedence and cleanup
|
|
534
|
+
are deterministic within the owning Workspace.
|
|
535
|
+
- **BR-5:** Each physical browser target serializes state-changing commands.
|
|
536
|
+
Reads that depend on document state join that same actor even when separate
|
|
537
|
+
Workspaces address the target through different opaque ControlledTarget IDs.
|
|
538
|
+
- **BR-6:** A physical target has at most one controlling Lease at a time.
|
|
539
|
+
Multiple Workspaces may inventory it under different opaque IDs, but a
|
|
540
|
+
conflicting acquisition reports `target_busy` and never silently steals
|
|
541
|
+
control. The controlling Lease may call `browser.tabs.release` with its own
|
|
542
|
+
opaque target ID. The Broker retires its target session and scoped state
|
|
543
|
+
before a different Lease can acquire control with that Lease's own opaque ID.
|
|
544
|
+
No handoff call accepts a foreign Lease or target ID.
|
|
545
|
+
- **BR-7:** The Pilot window visibly identifies the controlling client without
|
|
546
|
+
injecting mutable content into the page DOM.
|
|
547
|
+
- **BR-21:** Exposing the CLI or bridge to an Agent is the product-level
|
|
548
|
+
browser-control authorization boundary. Chrome's own remote-debugging
|
|
549
|
+
authorization is requested only by explicit `bp connect`/`browser.connect`.
|
|
550
|
+
Browser Pilot does not infer task intent, ask for per-tab grants, or perform
|
|
551
|
+
per-action confirmation.
|
|
552
|
+
- **BR-22:** The default BrowserControlPolicy permits all supported operations.
|
|
553
|
+
A Host may remove operations at launch; a running Agent cannot expand that
|
|
554
|
+
fixed policy through the browser tool protocol.
|
|
555
|
+
- **BR-23:** Every Workspace can inventory the same eligible user tab under a
|
|
556
|
+
distinct opaque ID. The single controlling-Lease rule in **BR-6** resolves
|
|
557
|
+
concurrent mutation.
|
|
558
|
+
- **BR-24:** Releasing a Lease or Workspace removes its user-target mappings and
|
|
559
|
+
invalidates their Observations without closing those tabs.
|
|
560
|
+
- **BR-25:** Eligible popups created from user tabs appear as ordinary user tabs.
|
|
561
|
+
Managed popup inheritance remains restricted to a complete verified opener
|
|
562
|
+
chain rooted in the same ManagedTabSet.
|
|
563
|
+
- **BR-26:** `tabs.list` returns eligible current and future tabs, tagging each
|
|
564
|
+
with origin and ManagedTabSet membership. Browser Pilot internal targets,
|
|
565
|
+
DevTools, and unsupported browser-internal targets remain excluded.
|
|
566
|
+
- **BR-27:** Bulk cleanup and `close --all` default to the ManagedTabSet. No
|
|
567
|
+
bulk operation closes user tabs outside it. Each user tab requires an
|
|
568
|
+
explicit target-specific close command.
|
|
569
|
+
|
|
570
|
+
## Command Reliability
|
|
571
|
+
|
|
572
|
+
Mutating commands follow this runtime state model:
|
|
573
|
+
|
|
574
|
+
```text
|
|
575
|
+
accepted -> dispatched -> completed
|
|
576
|
+
\-> unknown_outcome
|
|
577
|
+
accepted -> cancelled
|
|
578
|
+
accepted -> expired
|
|
579
|
+
```
|
|
580
|
+
|
|
581
|
+
- **BR-8:** Every command has a caller-provided or Broker-generated idempotency
|
|
582
|
+
key scoped to Principal and Workspace.
|
|
583
|
+
- **BR-9:** A duplicate completed command returns its recorded result. A
|
|
584
|
+
duplicate dispatched command returns its status and is not dispatched again.
|
|
585
|
+
- **BR-10:** If the Broker loses certainty after dispatch, it reports
|
|
586
|
+
`unknown_outcome`. Mutating commands are never automatically replayed.
|
|
587
|
+
- **BR-11:** Cancellation before dispatch prevents execution. Cancellation
|
|
588
|
+
after dispatch is best-effort and must not claim rollback.
|
|
589
|
+
- **BR-12:** Browser disconnect and explicit reconnect change the BrowserInstance
|
|
590
|
+
connection generation and invalidate sessions and observations. The generation
|
|
591
|
+
advances on successful restoration, not merely on an attempt. Discovery and
|
|
592
|
+
timers never initiate a browser connection.
|
|
593
|
+
|
|
594
|
+
Commands capture that generation when accepted. The Broker verifies it again
|
|
595
|
+
before browser dispatch and after the executor returns. A queued stale command
|
|
596
|
+
never reaches the browser. If a mutating command was already dispatched when the
|
|
597
|
+
generation changed, its terminal state is `unknown_outcome`; a stale read fails
|
|
598
|
+
with retryable `browser_disconnected` rather than returning old data.
|
|
599
|
+
|
|
600
|
+
The dispatch transition occurs immediately before the first browser mutation,
|
|
601
|
+
after argument, ref, target, and continuity preflight. Composite-action guards
|
|
602
|
+
preserve their structured interruption context when the terminal state is
|
|
603
|
+
`unknown_outcome`; callers must obtain fresh target/frame/Observation state
|
|
604
|
+
before deciding what remains to be done.
|
|
605
|
+
|
|
606
|
+
Normal bridge calls preserve dispatch order. `commands/get`, `commands/cancel`,
|
|
607
|
+
and dialog list/respond calls may bypass a pending `tools/call`; JSON-RPC clients
|
|
608
|
+
therefore correlate responses by ID rather than relying on response order. The
|
|
609
|
+
dialog exception prevents a paused browser command from blocking the explicit
|
|
610
|
+
response needed to release its JavaScript dialog.
|
|
611
|
+
|
|
612
|
+
Workspaces, Leases, target mappings, refs, command status, idempotency records,
|
|
613
|
+
and bounded event journals live in Broker memory by default. Broker restart
|
|
614
|
+
invalidates them; clients initialize again, list tabs again, and observe again.
|
|
615
|
+
Only installation identity, browser preference, Broker locator/version data,
|
|
616
|
+
and explicit user configuration may persist. DOM snapshots, refs, cookies,
|
|
617
|
+
passwords, network bodies, and transient control state never persist.
|
|
618
|
+
|
|
619
|
+
Broker-created targets cross one additional private ownership boundary. A
|
|
620
|
+
janitor child process is the sole owner of the root CDP WebSocket and proxies
|
|
621
|
+
all daemon CDP requests, results, and events over private IPC. The same process
|
|
622
|
+
creates and tracks only managed targets plus popup descendants with a verified
|
|
623
|
+
managed opener chain. Its parent pipe is the liveness signal: daemon EOF,
|
|
624
|
+
including `SIGKILL`, causes bounded descendant-first target cleanup. User
|
|
625
|
+
targets are never adopted merely because they share a browser window. Browser
|
|
626
|
+
disconnect clears that transient ownership before a new connection generation
|
|
627
|
+
is exposed. No janitor method or raw target ID is part of the CLI or stdio
|
|
628
|
+
protocol, and no ownership record is written to disk.
|
|
629
|
+
|
|
630
|
+
## Observation and Ref Semantics
|
|
631
|
+
|
|
632
|
+
Observation v1 has these required public fields: `workspaceId`, `leaseId`,
|
|
633
|
+
`targetId`, `url`, `observationId`, `title`, `elements`, `truncated`, and
|
|
634
|
+
`truncationReasons`. Each element contains only `ref`, `role`, `name`, and the
|
|
635
|
+
optional `value` and `checked` fields. Built-in Observation-producing tools
|
|
636
|
+
also return `hints`; action tools additionally return discriminated `evidence`.
|
|
637
|
+
The latter two fields remain optional in the schema so older compatible
|
|
638
|
+
executors stay valid. Raw nodes, selectors, bounds, CDP identifiers, and the
|
|
639
|
+
internal identity below never appear in an Observation result.
|
|
640
|
+
|
|
641
|
+
The frozen v1 limits are 50 elements by default and 10,000 at most; 4,096
|
|
642
|
+
string code units for title and element name; 16,384 for URL; 65,536 for one
|
|
643
|
+
element value; 1,000,000 across collected Observation text; AX depth 128; and
|
|
644
|
+
2 MiB of UTF-8 serialized Observation data. Broker storage retains at most
|
|
645
|
+
2,048 Observations for five minutes each. Hitting any collection limit sets
|
|
646
|
+
`truncated: true` and includes one or more canonical reasons in deterministic
|
|
647
|
+
order: `element_limit`, `text_limit`, `depth_limit`, `byte_limit`.
|
|
648
|
+
|
|
649
|
+
The public identity of an element is:
|
|
650
|
+
|
|
651
|
+
```text
|
|
652
|
+
workspaceId + observationId + ref
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
Internal resolution includes at least:
|
|
656
|
+
|
|
657
|
+
```text
|
|
658
|
+
browserProcessIdentity
|
|
659
|
+
browserConnectionGeneration
|
|
660
|
+
targetId
|
|
661
|
+
CDPSessionId
|
|
662
|
+
frameId
|
|
663
|
+
loaderId
|
|
664
|
+
backendNodeId
|
|
665
|
+
documentGeneration
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
The Broker stores process, connection, target, Lease, CDP session, frame,
|
|
669
|
+
loader, and Document generation on the Observation; each ref adds its backend
|
|
670
|
+
node identity. Resolution verifies all of them before live-node revalidation.
|
|
671
|
+
Same-context failures expose one of these stable invalidation reasons when
|
|
672
|
+
known: `navigation`, `loader_replaced`, `document_replaced`, `frame_changed`,
|
|
673
|
+
`frame_detached`, `session_replaced`, `target_detached`,
|
|
674
|
+
`browser_reconnected`, `target_ineligible`, `target_closed`,
|
|
675
|
+
`control_released`, or `expired`.
|
|
676
|
+
Ownership mismatches remain an undifferentiated `stale_ref` so they do not
|
|
677
|
+
disclose another Workspace's state.
|
|
678
|
+
|
|
679
|
+
Adding `document_replaced` as an optional `stale_ref.context.reason` value is
|
|
680
|
+
additive under protocol 1.0 and 1.1: clients branch on the stable error code,
|
|
681
|
+
handle known reasons when useful, and treat unknown reasons as a request to
|
|
682
|
+
rebuild current Observation state. It adds no operation or capability.
|
|
683
|
+
|
|
684
|
+
- **BR-13:** Cross-Workspace, cross-target, cross-observation, and expired refs
|
|
685
|
+
return `stale_ref`; they never fall back to another target.
|
|
686
|
+
- **BR-14:** Navigation, loader or Document replacement, target detach, frame
|
|
687
|
+
detach, CDP session replacement, and browser reconnect hard-invalidate
|
|
688
|
+
affected refs.
|
|
689
|
+
- **BR-15:** Same-document DOM changes require live node revalidation. They do
|
|
690
|
+
not force blanket invalidation when the node remains resolvable and valid.
|
|
691
|
+
- **BR-16:** Observations are immutable and bounded by element count, text size,
|
|
692
|
+
depth, and byte limits, with explicit truncation metadata.
|
|
693
|
+
- **BR-28:** Agent hints are advisory, deterministic, bounded, and based only on
|
|
694
|
+
browser-verifiable signals. They never contain field values, credentials,
|
|
695
|
+
private file paths, raw CDP identities, or framework-specific prompt state.
|
|
696
|
+
|
|
697
|
+
## Events
|
|
698
|
+
|
|
699
|
+
The event taxonomy includes navigation, document changed, target attached,
|
|
700
|
+
target detached, control acquired/released, popup, dialog, download, connection
|
|
701
|
+
lost, connection restored, network request, network response, command status,
|
|
702
|
+
observation invalidated, Lease expiry, and watchdog signals for stalled
|
|
703
|
+
navigation, selected-frame detach, unhandled dialogs, and repeated observable
|
|
704
|
+
no-progress actions.
|
|
705
|
+
|
|
706
|
+
Relevant event payloads carry the same `hints` representation: main-document
|
|
707
|
+
403/429 responses use `access_blocked`; downloads use `download` with the public
|
|
708
|
+
Artifact ID only after completion; and the threshold no-progress event uses
|
|
709
|
+
`repeated_action`. Subresource failures do not produce a page-blocked hint.
|
|
710
|
+
|
|
711
|
+
Every event contains an event ID, monotonic Workspace sequence, timestamp,
|
|
712
|
+
Workspace ID, relevant Lease and target IDs, type, payload version, and
|
|
713
|
+
sensitivity. `workspaces/create|get` returns an explicit current `eventCursor`.
|
|
714
|
+
Consumers poll from their last fully processed cursor; a poll returns ordered
|
|
715
|
+
events, `nextCursor`, and `hasMore`. The Broker may compact old events and must
|
|
716
|
+
return `cursor_expired` with retained cursor bounds rather than silently skip
|
|
717
|
+
them. A consumer that loses its cursor rebuilds tab and Observation state, then
|
|
718
|
+
uses `workspaces/get` to establish a new baseline.
|
|
719
|
+
|
|
720
|
+
JavaScript dialogs enter explicit pending state and emit opened/closed events.
|
|
721
|
+
They remain paused until the user or an Agent issues `browser.dialogs.respond`;
|
|
722
|
+
Browser Pilot never auto-accepts them.
|
|
723
|
+
|
|
724
|
+
Watchdogs report browser state; they do not make task decisions. A navigation
|
|
725
|
+
that never becomes interactive emits `watchdog.navigation_stalled` and leaves
|
|
726
|
+
the dispatched command as `unknown_outcome`. Detaching the selected frame emits
|
|
727
|
+
`watchdog.frame_detached`, clears the frame selection, and invalidates its
|
|
728
|
+
Observation. A dialog still pending after the bounded threshold emits one
|
|
729
|
+
`watchdog.dialog_unhandled` event but remains pending. Three consecutive actions
|
|
730
|
+
with browser-observable mismatch or no effect emit one `watchdog.no_progress`
|
|
731
|
+
event per streak, scoped by Lease and target. Unobservable coordinate/canvas
|
|
732
|
+
actions do not increment the streak. Navigation, frame changes, verified
|
|
733
|
+
progress, session replacement, Lease release, and Workspace cleanup reset the
|
|
734
|
+
applicable transient state.
|
|
735
|
+
|
|
736
|
+
Watchdog payloads contain only bounded recovery metadata and opaque public IDs;
|
|
737
|
+
they never contain typed values, passwords, refs, raw CDP target/session/frame
|
|
738
|
+
IDs, or dialog prompt responses. Consumers inspect fresh browser state before
|
|
739
|
+
deciding whether to continue, retry, or ask the user.
|
|
740
|
+
|
|
741
|
+
## Artifacts
|
|
742
|
+
|
|
743
|
+
Artifact descriptors contain an opaque ID, kind, MIME type, byte size, original
|
|
744
|
+
filename or dimensions when applicable, sensitivity, creation time, expiry, and
|
|
745
|
+
optional preview relationship. They do not expose internal storage paths as the
|
|
746
|
+
primary identity.
|
|
747
|
+
|
|
748
|
+
- **BR-17:** Broker storage directories are mode `0700`; files are mode `0600`
|
|
749
|
+
on platforms that support POSIX permissions.
|
|
750
|
+
- **BR-18:** Artifacts have per-item, per-Workspace, and global capacity limits,
|
|
751
|
+
TTL cleanup, retain/release, and explicit export to a client-owned path.
|
|
752
|
+
- **BR-19:** Binary bytes are not written as base64 to the stdio stream. The
|
|
753
|
+
local adapter reads an authorized Artifact or asks the CLI to export it, then
|
|
754
|
+
converts it to the Agent runtime's image/file content type.
|
|
755
|
+
- **BR-20:** Large or full-page screenshots return a model-sized preview plus
|
|
756
|
+
an optional original Artifact.
|
|
757
|
+
|
|
758
|
+
An adapter authorizes a local upload by calling `artifacts/import` with an
|
|
759
|
+
absolute path, Workspace, and active Lease. The Broker copies the file into
|
|
760
|
+
protected storage as a `user_file` / `upload_input` Artifact while preserving
|
|
761
|
+
its basename. `browser.upload` accepts only that Artifact kind and never treats
|
|
762
|
+
a screenshot, PDF, download, or arbitrary Broker-internal path as upload
|
|
763
|
+
authorization.
|
|
764
|
+
|
|
765
|
+
Downloads are event-produced Artifacts rather than a separate path-returning
|
|
766
|
+
tool. The implementation must configure download behavior on the controlled
|
|
767
|
+
target session only, stage bytes in a mode-`0700` per-session directory, keep
|
|
768
|
+
the CDP download GUID and staging path private, and ingest a completed file as a
|
|
769
|
+
Workspace-owned `download` Artifact before publishing the completed `download`
|
|
770
|
+
event. Lease/session/Workspace release removes partial staging files; failed,
|
|
771
|
+
cancelled, oversized, or detached downloads publish bounded metadata without a
|
|
772
|
+
local path. Browser-wide `Browser.setDownloadBehavior` on the user's default
|
|
773
|
+
context is forbidden because it would redirect downloads from unrelated user
|
|
774
|
+
tabs. If target-session isolation is unavailable in a Chrome version, Browser
|
|
775
|
+
Pilot reports download capture as unavailable and does not fall back globally.
|
|
776
|
+
The implementation applies per-download, per-Workspace staging, and global
|
|
777
|
+
staging bounds. An oversized or over-capacity download is cancelled by its
|
|
778
|
+
private GUID without changing download behavior for the browser's default
|
|
779
|
+
context. Stale staging directories from a prior Broker process are removed before
|
|
780
|
+
the first new download session is configured.
|
|
781
|
+
|
|
782
|
+
## Browser Discovery and Setup
|
|
783
|
+
|
|
784
|
+
Discovery returns every supported local browser candidate with product,
|
|
785
|
+
channel, profile, process state, remote-debugging state, authorization state,
|
|
786
|
+
and structured remediation. It does not silently select the first filesystem
|
|
787
|
+
match when several viable instances exist.
|
|
788
|
+
|
|
789
|
+
The client may select an instance explicitly or use a deterministic persisted
|
|
790
|
+
preference. Setup that requires Chrome UI remains a user-visible action. Browser
|
|
791
|
+
Pilot cannot bypass Chrome authorization and must not simulate consent.
|
|
792
|
+
|
|
793
|
+
Browser Pilot does not add an access-approval page. Products that want an
|
|
794
|
+
approval UX own it in the Agent host before exposing the tool. Browser Pilot
|
|
795
|
+
still excludes its own setup/status pages and other internal targets from
|
|
796
|
+
Agent inventory; the same-user CDP limitation in **CON-7** remains.
|
|
797
|
+
|
|
798
|
+
## Security and Sensitive Data
|
|
799
|
+
|
|
800
|
+
- Password inputs, cookies, auth credentials, network bodies, uploads,
|
|
801
|
+
downloads, page captures, and selected page text carry sensitivity metadata.
|
|
802
|
+
- Tool schemas mark selected text and page/element values as `browser_data`,
|
|
803
|
+
with `credential` added where a field may carry a password, cookie, header,
|
|
804
|
+
request body, response body, prompt response, or arbitrary eval value.
|
|
805
|
+
- Artifact descriptors and BrowserEvents carry runtime sensitivity because
|
|
806
|
+
their classification depends on the produced object or event. Their runtime
|
|
807
|
+
value takes precedence over a tool's possible schema classifications.
|
|
808
|
+
- Secrets are accepted through protected stdin or structured machine input, not
|
|
809
|
+
command-line arguments in recommended workflows.
|
|
810
|
+
- Audit records store metadata and hashes where possible, not secret values.
|
|
811
|
+
- Public errors do not include cookies, credentials, network bodies, DOM dumps,
|
|
812
|
+
or raw CDP payloads.
|
|
813
|
+
- The Broker socket/pipe, configuration, and Artifact storage are restricted to
|
|
814
|
+
the OS user.
|
|
815
|
+
- Browser Pilot documents that another same-user process may bypass it and use
|
|
816
|
+
Chrome's debugging endpoint directly.
|
|
817
|
+
|
|
818
|
+
## Stable Error Model
|
|
819
|
+
|
|
820
|
+
Errors contain a stable code, human message, retryability, affected object IDs,
|
|
821
|
+
and optional structured remediation. Required codes include:
|
|
822
|
+
|
|
823
|
+
```text
|
|
824
|
+
protocol_incompatible not_initialized capability_denied
|
|
825
|
+
browser_not_found browser_not_authorized browser_disconnected
|
|
826
|
+
broker_in_use
|
|
827
|
+
workspace_not_found lease_expired target_not_owned
|
|
828
|
+
target_busy stale_ref command_cancelled
|
|
829
|
+
action_not_verified command_expired unknown_outcome
|
|
830
|
+
artifact_not_found
|
|
831
|
+
artifact_expired cursor_expired result_too_large
|
|
832
|
+
invalid_argument internal_error
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
Human CLI output may add prose. Machine clients branch only on codes and typed
|
|
836
|
+
fields, never on message text.
|
|
837
|
+
|
|
838
|
+
## Compatibility and Versioning
|
|
839
|
+
|
|
840
|
+
- Protocol versions are independent of executable versions.
|
|
841
|
+
- Compatible embedded clients reuse the running Broker even when their host or
|
|
842
|
+
bundled executable versions differ. The one-shot compatibility CLI requires
|
|
843
|
+
the running Broker's exact executable version because its external JSON
|
|
844
|
+
contract is versioned separately from the bridge protocol.
|
|
845
|
+
- An incompatible executable never replaces a live Broker. A host either uses
|
|
846
|
+
a compatible executable or deliberately supplies a distinct
|
|
847
|
+
`BROWSER_PILOT_HOME`; Browser Pilot never creates a hidden version namespace.
|
|
848
|
+
- Broker shutdown is compare-and-stop: it requires the current Broker process
|
|
849
|
+
identity and matching executable installation identity, and refuses while
|
|
850
|
+
any embedded Connection remains live.
|
|
851
|
+
- Additive tool and field changes use capability negotiation and schema
|
|
852
|
+
evolution. Breaking semantics require a protocol-major change.
|
|
853
|
+
- Unknown response fields are ignored; unknown request fields are rejected only
|
|
854
|
+
when they change safety or semantics.
|
|
855
|
+
- Optional advisory output such as `hints` does not require a protocol-minor
|
|
856
|
+
version or capability when it adds no operation and only derives bounded data
|
|
857
|
+
already covered by an existing granted capability.
|
|
858
|
+
- The current CLI JSON shapes remain supported until a documented major CLI
|
|
859
|
+
release and migration period.
|
|
860
|
+
- A conformance suite validates any embedded adapter against the same executable
|
|
861
|
+
used by direct CLI users.
|
|
862
|
+
|
|
863
|
+
## Functional Requirements and Acceptance
|
|
864
|
+
|
|
865
|
+
- **FR-1 Universal installation:** An Agent can install Browser Pilot globally
|
|
866
|
+
or locally and use existing one-shot commands.
|
|
867
|
+
- **AC-1:** Existing documented CLI workflows and fixture tests pass after
|
|
868
|
+
Broker migration without requiring an SDK, MCP server, or extension.
|
|
869
|
+
- **FR-2 Embedded integration:** A product can bundle the official executable,
|
|
870
|
+
initialize `bridge --stdio`, discover tools, execute them, receive events,
|
|
871
|
+
and release resources.
|
|
872
|
+
- **AC-2:** A reference adapter integrates using only executable invocation,
|
|
873
|
+
the published protocol, and Artifact files; it imports no Browser Pilot
|
|
874
|
+
source module.
|
|
875
|
+
- **FR-3 Multi-client isolation:** Concurrent clients have isolated control and
|
|
876
|
+
transient state.
|
|
877
|
+
- **AC-3:** Two clients can operate separate Pilot windows concurrently, and
|
|
878
|
+
refs, active targets, frames, auth, rules, and close operations cannot cross
|
|
879
|
+
Workspace boundaries.
|
|
880
|
+
- **FR-4 User-browser control:** An Agent can list and control all eligible
|
|
881
|
+
current and future tabs in the selected BrowserInstance, including tabs the
|
|
882
|
+
user opened before invoking it.
|
|
883
|
+
- **AC-4:** No access-request or grant step is required. Inventory combines
|
|
884
|
+
ManagedTabSets and user tabs behind Workspace-scoped opaque IDs. A Host may
|
|
885
|
+
remove operations at launch. Concurrent control reports `target_busy`,
|
|
886
|
+
release leaves user tabs open, and bulk cleanup closes only managed tabs.
|
|
887
|
+
- **FR-5 Crash behavior:** Client and Broker failures have deterministic
|
|
888
|
+
outcomes.
|
|
889
|
+
- **AC-5:** Expired Leases are reclaimed; commands lost after dispatch report
|
|
890
|
+
`unknown_outcome`; reconnect invalidates prior observations.
|
|
891
|
+
- **FR-6 Media delivery:** Agent products can deliver Browser Pilot screenshots
|
|
892
|
+
to multimodal models.
|
|
893
|
+
- **AC-6:** Capture returns a protected Artifact and preview metadata; a
|
|
894
|
+
reference adapter converts it to native image content without base64 on
|
|
895
|
+
stdout.
|
|
896
|
+
- **FR-7 Version safety:** User-installed and product-bundled clients coexist.
|
|
897
|
+
- **AC-7:** Compatible clients reuse the Broker; incompatible clients receive
|
|
898
|
+
`protocol_incompatible` or use a deliberately isolated Broker without
|
|
899
|
+
terminating live clients.
|
|
900
|
+
- **FR-8 Browser reliability:** Browser capability improvements do not alter the
|
|
901
|
+
public lifecycle and isolation contract.
|
|
902
|
+
- **AC-8:** Observation and action conformance tests pass against the public
|
|
903
|
+
tool interface, including frame, navigation, stale-ref, obstruction, and
|
|
904
|
+
input readback cases.
|
|
905
|
+
|
|
906
|
+
## Non-Functional Requirements
|
|
907
|
+
|
|
908
|
+
- **NFR-1:** No protocol message or normal tool result exceeds negotiated size
|
|
909
|
+
limits; truncation is explicit.
|
|
910
|
+
- **NFR-2:** Broker restart invalidates transient Workspaces, Leases, target
|
|
911
|
+
assignments, refs, and commands. Clients rebuild state explicitly without
|
|
912
|
+
guessing or replaying mutations.
|
|
913
|
+
- **NFR-3:** Every command and security-sensitive lifecycle transition emits an
|
|
914
|
+
auditable event without storing secret payloads.
|
|
915
|
+
- **NFR-4:** Target command ordering is deterministic under concurrent clients.
|
|
916
|
+
- **NFR-5:** Resource cleanup is idempotent and bounded after normal release,
|
|
917
|
+
client crash, browser exit, and Broker restart.
|
|
918
|
+
|
|
919
|
+
## Non-Goals
|
|
920
|
+
|
|
921
|
+
- Hosting browsers in the cloud or providing captcha-solving infrastructure.
|
|
922
|
+
- Controlling Firefox or WebKit in the current architecture.
|
|
923
|
+
- Providing OS-level isolation between processes owned by the same user.
|
|
924
|
+
- Defining whether an Agent's requested browser action matches user intent;
|
|
925
|
+
Agent hosts own semantic approval and confirmation policy.
|
|
926
|
+
- Modeling an Agent's conversation, run, task, worker, or model provider.
|
|
927
|
+
- Replacing URL Preview features inside embedding products.
|
|
928
|
+
- Making Browser Pilot an MCP server or publishing language SDKs.
|
|
929
|
+
|
|
930
|
+
## Verification Strategy
|
|
931
|
+
|
|
932
|
+
1. Protocol unit tests validate framing, negotiation, errors, schemas,
|
|
933
|
+
idempotency, cancellation, and cursor behavior.
|
|
934
|
+
2. Broker integration tests create concurrent fake clients and assert complete
|
|
935
|
+
tab inventory, target assignment, Lease cleanup, crash recovery, and version
|
|
936
|
+
coexistence.
|
|
937
|
+
3. Existing Playwright fixtures remain regression tests for human CLI behavior.
|
|
938
|
+
4. Capability tests cover DOM/AX fusion, frames/OOPIF, stale refs, obstruction,
|
|
939
|
+
action verification, input readback, and document changes.
|
|
940
|
+
5. Adapter conformance tests run against a language-neutral reference adapter
|
|
941
|
+
and at least two example Agent runtimes. No example-specific behavior enters
|
|
942
|
+
Broker production code.
|
|
943
|
+
6. Browser-control tests prove that all eligible existing and future tabs are
|
|
944
|
+
included without grants, launch-time denied operations fail before CDP
|
|
945
|
+
dispatch, opaque IDs cannot cross Workspaces, and bulk cleanup never closes
|
|
946
|
+
user tabs.
|
|
947
|
+
7. Distribution tests pack and install the npm package through global and local
|
|
948
|
+
layouts, launch local npx and product-owned absolute paths, and exercise
|
|
949
|
+
version output, bridge initialization, private Broker startup, and cleanup.
|
|
950
|
+
Native verification additionally checks manifest hashes, signature state,
|
|
951
|
+
private child roles, and archive checksums on each target platform.
|
|
952
|
+
|
|
953
|
+
## Implementation Boundary
|
|
954
|
+
|
|
955
|
+
The target internal boundary is:
|
|
956
|
+
|
|
957
|
+
```text
|
|
958
|
+
CLI formatter -----------\
|
|
959
|
+
stdio bridge -------------+--> BrowserPilotService --> Broker domain actors
|
|
960
|
+
conformance harness ------/ | --> CDP connector
|
|
961
|
+
+--> Artifact/Event stores
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
`BrowserPilotService` is an internal architectural boundary, not a promised
|
|
965
|
+
Native SDK. CLI and bridge code may depend on it. Third-party products may not.
|