chrome-agent 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +127 -283
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,347 +1,191 @@
1
1
  # chrome-agent
2
2
 
3
- Browser automation for AI agents. Single Rust binary, zero runtime dependencies, talks CDP directly to Chrome.
3
+ **Web tasks that compile.**
4
4
 
5
- ## Why
5
+ A browser doesn't report back. The click lands on a cookie banner, the form drops what you typed,
6
+ the page navigates away mid-action, and the tool returns success anyway. Everything the agent does
7
+ next is built on that.
6
8
 
7
- Existing tools (Playwright, Puppeteer, Selenium) carry heavy runtimes and weren't designed for agents. Agents need:
8
- - **Minimum tokens** a11y tree snapshots instead of raw HTML (~50 tokens vs ~2000)
9
- - **Minimum round-trips** — `--inspect` returns updated page state with every action
10
- - **Zero setup** — single binary, headless by default, no npm/Node required
11
- - **Persistent sessions** — login once, stay logged in across invocations
12
- - **Stable UIDs** — element identifiers based on `backendNodeId`, survive between inspects
13
- - **3 targeting modes** — uid from accessibility tree, CSS selectors, or coordinates
9
+ chrome-agent reads the page back after every action and answers which one it was: the change held,
10
+ something else took the click, or nothing could be observed. One word, in JSON, to branch on.
14
11
 
15
- ## Install
16
-
17
- ### For AI agents (recommended)
12
+ One 3 MB Rust binary over CDP. No Node runtime, no Playwright, no daemon.
18
13
 
19
- ```bash
20
- # Install the skill — your agent learns chrome-agent automatically
21
- npx skills add sderosiaux/chrome-agent
22
- ```
14
+ chrome-agent v0.16.0 (~28.2K lines of Rust in `src/`, blank and comment-only lines excluded; 3 MB binary)
23
15
 
24
- This installs a `SKILL.md` that teaches your agent (Claude Code, Cursor, Copilot, etc.) how to use chrome-agent, including the workflow, commands, and best practices.
16
+ Full documentation: [github.com/sderosiaux/chrome-agent](https://github.com/sderosiaux/chrome-agent).
25
17
 
26
- ### CLI binary
18
+ ## Install
27
19
 
28
20
  ```bash
29
- # npm (downloads prebuilt binary)
30
- npm install -g chrome-agent
31
-
32
- # or with npx (no install needed)
33
- npx chrome-agent --help
34
-
35
- # or with Cargo (builds from source)
36
- cargo install chrome-agent
21
+ npx skills add sderosiaux/chrome-agent # skill file + binary, for coding agents
22
+ npm install -g chrome-agent # prebuilt binary
23
+ npx chrome-agent --help # no install
24
+ cargo install chrome-agent # from source
37
25
  ```
38
26
 
39
- ## Quick Start
27
+ ## Quickstart
40
28
 
41
29
  ```bash
42
- # Navigate and inspect the page in one call
30
+ # Navigate and read the page as an accessibility tree with stable uids
43
31
  chrome-agent goto https://example.com --inspect
44
- # https://example.com — Example Domain
45
- # uid=n1 RootWebArea "Example Domain"
46
- # → uid=n9 heading "Example Domain" level=1
47
- # → uid=n10 paragraph "This domain is for..."
48
- # → uid=n12 link "Learn more"
32
+ # uid=n9 heading "Example Domain" level=1
33
+ # uid=n12 link "More information..."
49
34
 
50
- # Click by uid, get updated page state
35
+ # Act by uid, by CSS selector, or by coordinates
51
36
  chrome-agent click n12 --inspect
37
+ chrome-agent click --selector "button.submit"
38
+ chrome-agent click --xy 100,200
52
39
 
53
- # Fill a form field
40
+ # Fill, then check what the page kept
54
41
  chrome-agent fill --uid n20 "user@test.com"
42
+ chrome-agent assert value --uid n20 --equals "user@test.com"
55
43
 
56
- # Or target by CSS selector (when uids aren't practical)
57
- chrome-agent click --selector "button.submit"
58
- chrome-agent fill --selector "input[name=email]" "hello@test.com"
59
-
60
- # Extract article content (Mozilla Readability — reader mode)
44
+ # Content, not markup
61
45
  chrome-agent read
62
-
63
- # Extract full visible text (use --selector to scope, --truncate to cap)
46
+ chrome-agent extract --limit 30
64
47
  chrome-agent text --selector "main" --truncate 500
65
48
 
66
- # Evaluate JavaScript
67
- chrome-agent eval "document.title"
68
-
69
- # Screenshot (returns file path, not binary data)
70
- chrome-agent screenshot
71
- ```
72
-
73
- ## How It Works
74
-
75
- ```
76
- chrome-agent v0.15.0 (~22.2K lines of Rust in src/, 3 MB binary)
77
-
78
- │ WebSocket (Chrome DevTools Protocol)
79
-
80
- Chrome / Chromium (headless by default)
49
+ # JSON for everything
50
+ chrome-agent --json eval "document.title"
51
+ chrome-agent screenshot --format jpeg --quality 60 --max-width 1024
81
52
  ```
82
53
 
83
- No Node.js. No Playwright. No daemon required. Headless by default `--headed` for debugging.
84
-
85
- UIDs are stable across inspects (based on Chrome's `backendNodeId`). The agent inspects, picks a uid, acts — even minutes later. When a11y tree isn't practical, CSS selectors and coordinates work as fallbacks. Click auto-falls back to JS `.click()` when the element has no box model.
54
+ Chrome stays alive between invocations, so a command costs a connection, not a browser launch. Give
55
+ each parallel agent its own `--browser <name>`, or they corrupt each other's session state.
86
56
 
87
57
  ## Commands
88
58
 
89
- | Command | Description |
90
- |---------|------------|
91
- | `goto <url> [--inspect] [--max-depth N] [--header "K: V"]` | Navigate to URL. `--header` sends extra HTTP headers (repeatable) |
92
- | `inspect [--verbose] [--max-depth N] [--uid nN] [--filter "role,role"] [--max-chars N] [--offset K]` | Accessibility tree with stable uids. `--max-chars`/`--offset` cap and page the output |
93
- | `click <uid> [--inspect] [--max-depth N]` | Click by uid (JS fallback if no box model) |
94
- | `click --selector "css" [--inspect]` | Click by CSS selector |
95
- | `click --xy 100,200` | Click by coordinates |
96
- | `fill --uid <uid> <value> [--inspect]` | Fill input by uid |
97
- | `fill --selector "css" <value>` | Fill by CSS selector |
98
- | `fill-form <uid=val>...` | Batch fill multiple fields |
99
- | `read [--html] [--truncate N]` | Extract main content (Mozilla Readability) |
100
- | `text [uid] [--selector "css"] [--truncate N]` | Extract visible text (page or element) |
101
- | `eval <expression> [--selector "css"]` | Run JS in page context (`el` = matched element) |
102
- | `network [--filter "pattern"] [--body] [--live N]` | Capture network requests / API responses |
103
- | `console [--level error] [--clear]` | Show captured console.log/warn/error + JS exceptions |
104
- | `pipe` | Persistent connection: JSON stdin JSON stdout |
105
- | `wait <text\|url\|selector> <pattern>` | Wait for condition |
106
- | `wait network-idle [--idle-ms N] [--timeout N]` | Wait until the network is quiet (SPA/XHR settle) |
107
- | `type <text> [--selector "css"]` | Type into focused/selected element |
108
- | `press <key>` | Press Enter, Tab, Escape, etc. |
109
- | `scroll <down\|up\|uid>` | Scroll page or element into view |
110
- | `hover <uid>` | Hover over element |
111
- | `back` | Navigate back in history |
112
- | `screenshot [--filename name] [--format jpeg\|png] [--quality N] [--max-width N] [--uid nN\|--selector "css"]` | Screenshot file path. JPEG/max-width shrink it; `--uid`/`--selector` clip to one element |
113
- | `pdf [--filename name] [--landscape] [--background]` | Print the current page to a PDF file |
114
- | `download <url> [--out path] [--timeout N]` | Download a URL fetched in-page (cookies/auth preserved) → `{path,bytes,mime}` |
115
- | `tabs` | List open browser tabs |
116
- | `close [--purge]` | Close browser (--purge deletes profile/cookies) |
117
- | `status` | Show session info |
118
- | `stop` | Stop background daemon |
119
-
120
- ## Global Flags
59
+ | Command | What it does |
60
+ |---|---|
61
+ | `goto <url> [--inspect] [--header "K: V"]` | Navigate. Reports where you landed and what answered. |
62
+ | `inspect [--filter "role,role"] [--uid nN] [--urls] [--max-chars N] [--offset K]` | Accessibility tree with stable uids. |
63
+ | `diff` | What changed since the last inspect. |
64
+ | `click <uid> [--selector "css"] [--xy X,Y] [--inspect]` | Click. JS fallback when there is no box model. |
65
+ | `dblclick <uid>` | Double-click, same targeting modes. |
66
+ | `fill --uid <uid> <value>` | Fill an input. Reports the value the page kept. |
67
+ | `fill-form <uid=val>...` | Fill several fields at once. |
68
+ | `select --uid <uid> <value>` | Pick a `<select>` option by value or visible text. |
69
+ | `check <uid>` / `uncheck <uid>` | Idempotent checkbox and radio control. |
70
+ | `upload --uid <uid> <file>...` | Upload to a file input. |
71
+ | `drag <from-uid> <to-uid>` | Mouse-event drag. |
72
+ | `type <text>` / `press <key>` / `hover <uid>` / `scroll <down\|up\|uid>` | Keyboard and pointer primitives. |
73
+ | `wait <text\|url\|selector> <pattern>` | Wait for a condition. `wait network-idle` for SPA settle. |
74
+ | `assert value\|text\|url\|state\|exists ...` | Check a page fact. Exit 2 when it does not hold. |
75
+ | `read [--html] [--truncate N]` | Article extraction via Mozilla Readability. |
76
+ | `text [--selector "css"] [--truncate N]` | Visible text of the page or one element. |
77
+ | `extract [--limit N] [--scroll] [--a11y]` | Auto-detect repeating records. No selectors needed. |
78
+ | `eval <expression> [--selector "css"]` | JS in page context. |
79
+ | `screenshot [--format jpeg\|png] [--quality N] [--max-width N] [--uid nN]` | Screenshot to a file path. |
80
+ | `pdf [--filename name] [--landscape] [--background]` | Print the page to PDF. |
81
+ | `download <url> [--out path]` | Fetch in-page so cookies and auth carry over. |
82
+ | `network [--filter "pattern"] [--body] [--live N] [--abort "pattern"]` | Requests and API responses. |
83
+ | `console [--level error] [--clear]` | console.log/warn/error and JS exceptions. |
84
+ | `frame <selector\|main>` | Bind `eval`/`inspect` to an iframe, inside a `pipe`/`batch` process. |
85
+ | `emulate device --width W --height H` | Device metrics for one named page. |
86
+ | `pipe` / `batch` | Persistent JSON stdin/stdout, or a JSON array on stdin. |
87
+ | `tabs` / `status` / `history` / `close [--purge]` | Session management. |
88
+
89
+ ## Global flags
121
90
 
122
91
  ```
123
92
  --browser <name> Named browser profile (default: "default")
124
- --page <name> Named page/tab (default: "default")
125
- --connect <auto|url> Connect to running Chrome (a value is required: "auto", or a
126
- ws:// or http:// URL)
127
- --headed Show browser window (default is headless)
128
- --stealth Bypass bot detection (Cloudflare, Turnstile)
129
- --timeout <seconds> Command timeout (default: 30)
130
- --max-depth <N> Limit inspect tree depth (works with --inspect on any command)
93
+ --page <name> Named tab (default: "default")
94
+ --connect <auto|url> Attach to a running Chrome (a value is required)
95
+ --headed Show the browser window (default: headless)
96
+ --stealth Anti-detection CDP patches
131
97
  --copy-cookies Use cookies from your real Chrome profile
98
+ --timeout <seconds> Command timeout (default: 30)
99
+ --max-depth <N> Limit inspect depth
100
+ --verdict <mode> auto (default) reads the page back; off reports the action only
132
101
  --dialog <mode> JS dialog policy: accept (default), dismiss, or manual
133
- --dialog-text <text> Text submitted for prompt() dialogs under --dialog accept
134
102
  --ignore-https-errors Accept self-signed certificates
135
- --json Structured JSON output for all commands
103
+ --json Structured JSON output
136
104
  ```
137
105
 
138
- JS dialogs (`alert`/`confirm`/`prompt`/`beforeunload`) are auto-answered by default (`--dialog accept`) so the page never hangs on a blocking dialog.
106
+ ## What a response tells you
139
107
 
140
- ## The Inspect Act Inspect Loop
108
+ `ok:true` means the command ran, not that the page complied. Every mutating action carries a
109
+ `verdict`, a `verdict_reason` and a `next` — one token from `proceed`, `inspect`, `retry`,
110
+ `confirm`, `dismiss`, `stop` — so an agent branches without parsing prose.
141
111
 
142
- ```bash
143
- # 1. Navigate and inspect
144
- chrome-agent goto https://app.com/login --inspect
145
- # uid=n47 heading "Login" level=1
146
- # uid=n52 textbox "Email" focusable
147
- # uid=n58 textbox "Password" focusable
148
- # uid=n63 button "Sign In" focusable
149
-
150
- # 2. Act
151
- chrome-agent fill --uid n52 "user@test.com"
152
- chrome-agent fill --uid n58 "password123"
153
-
154
- # 3. Click with --inspect to get result + new state in one call
155
- chrome-agent click n63 --inspect
156
- # → Clicked uid=n63
157
- # → uid=n101 heading "Dashboard" level=1
158
- # → uid=n105 navigation "Main menu"
159
- ```
160
-
161
- UIDs (n47, n52, etc.) are stable — they won't change between inspects as long as the DOM node exists.
162
-
163
- ## Network Capture
164
-
165
- Extract API data directly instead of DOM scraping:
112
+ | `verdict` | Means |
113
+ |---|---|
114
+ | `changed` | The page moved; `delta` says how. |
115
+ | `navigated` | New document. Every stored uid is dead. |
116
+ | `intercepted` | Another element received the event; `intercepted_by` names it. |
117
+ | `not_kept` | The write reached the element and it does not hold it. Read `value.actual`. |
118
+ | `no_effect` | Delivery proven by hit test, and the tree stayed still. |
119
+ | `unchanged` | The tree was identical while the tool watched. Delivery not proven. |
120
+ | `unknown` | Nothing could be compared. Never repeat the action — it may already have landed. |
166
121
 
167
- ```bash
168
- # Show resources loaded by the page (stealth-safe, uses Performance API)
169
- chrome-agent network --filter "api"
122
+ Exit codes: `0` success, `1` error, `2` a claim this tool made did not hold, `130` Ctrl+C. `2` is
123
+ a failed `assert`, or a `macro run` guard that was checked and did not hold — nothing else.
170
124
 
171
- # Capture live traffic with response bodies (5 seconds)
172
- chrome-agent network --live 5 --body --filter "graphql"
125
+ ## uids
173
126
 
174
- # JSON output for structured extraction
175
- chrome-agent --json network --body --filter "api" --limit 10
176
- ```
127
+ Element ids come from Chrome's `backendNodeId`, printed as `n82`. They stay valid across inspects
128
+ of the same page. A navigation reassigns them all, so re-inspect after `goto`, `back`, or a click
129
+ that changes route. CSS selectors and coordinates work where a uid is impractical.
177
130
 
178
- ## Console Capture
131
+ ## Pipe mode
179
132
 
180
- See what the page logs useful for debugging and error detection:
133
+ One process, one connection, one JSON line per response, and uids stay stable across the whole
134
+ sequence — which is the reason to reach for it. The speed-up is real and small: pipe removes about
135
+ 12 ms of per-command overhead, worth 1.5x on a stream of reads (nine commands, 352 ms → 228 ms) and
136
+ 1.1x on a stream of fills and clicks (2029 ms → 1908 ms), where the settle window and the tree
137
+ re-read pipe does not touch are most of the cost. Measured on 2026-08-30, M4 Max, Chrome 152,
138
+ median of 9 runs (`scripts/measure-pipe.sh` in the repo).
181
139
 
182
140
  ```bash
183
- chrome-agent console # all messages
184
- chrome-agent console --level error # errors + exceptions only
185
- chrome-agent console --clear # read and clear buffer
186
- ```
187
-
188
- Stealth-safe: uses injected interceptor, not `Runtime.enable`.
189
-
190
- ## Pipe Mode
191
-
192
- Persistent connection for high-performance agent workflows:
193
-
194
- ```bash
195
- # Start pipe (one connection, reads JSON from stdin)
196
141
  echo '{"cmd":"goto","url":"https://example.com","inspect":true}
197
142
  {"cmd":"click","uid":"n12","inspect":true}
198
143
  {"cmd":"read"}' | chrome-agent pipe
199
144
  ```
200
145
 
201
- Each command returns one JSON line: `{"ok":true,...}` or `{"ok":false,"error":"..."}`. 10x faster than spawning chrome-agent per command.
202
-
203
- ## Content Extraction
204
-
205
- ```bash
206
- # Article content (Readability — like Firefox Reader Mode)
207
- chrome-agent read
208
- # → # Article Title
209
- # → Clean article text without nav, footer, sidebar...
210
-
211
- # Full page text (scoped by selector)
212
- chrome-agent text --selector "[role=main]" --truncate 1000
213
-
214
- # Structured data via JS
215
- chrome-agent eval "JSON.stringify([...document.querySelectorAll('h2')].map(e => e.textContent))"
216
- ```
217
-
218
- ## Stealth Mode
219
-
220
- Many sites (Cloudflare, Turnstile) block headless Chrome. `--stealth` patches 7 automation fingerprints via CDP:
221
-
222
- ```bash
223
- chrome-agent --stealth goto https://protected-site.com --inspect
224
- ```
225
-
226
- What it patches:
227
- - `navigator.webdriver` → `undefined`
228
- - `chrome.runtime` → mocked (headless doesn't have it)
229
- - Permissions API → consistent with real browser
230
- - WebGL renderer → masks ANGLE/headless fingerprint
231
- - User-Agent → removes "HeadlessChrome"
232
- - Input `screenX`/`pageX` leak → random offset added
233
- - `Runtime.enable` → skipped (the #1 CDP detection vector)
234
-
235
- All patches are CDP-level (`Page.addScriptToEvaluateOnNewDocument`). No fake Chrome flags.
236
-
237
- ### Heavy bot protection (DataDome, Kasada)
238
-
239
- Some sites (Leboncoin, etc.) use advanced fingerprinting that detects bundled Chromium regardless of CDP patches. For these, connect to your real installed Chrome instead:
240
-
241
- ```bash
242
- # Launch your real Chrome with debugging enabled
243
- google-chrome --remote-debugging-port=9222 &
244
-
245
- # Connect chrome-agent to it
246
- chrome-agent --connect http://127.0.0.1:9222 goto https://www.leboncoin.fr --inspect
247
- ```
146
+ ## Bot detection
248
147
 
249
- Real Chrome has genuine canvas/audio/codec fingerprints that Chromium lacks.
148
+ `--stealth` applies 7 CDP-level patches: `navigator.webdriver`, `chrome.runtime`, the Permissions
149
+ API, the WebGL renderer, the User-Agent, an input coordinate leak, and never calling
150
+ `Runtime.enable`.
250
151
 
251
- | Protection Level | Solution |
152
+ | Protection | What works |
252
153
  |---|---|
253
154
  | None | `chrome-agent goto ...` |
254
- | Cloudflare/Turnstile | `chrome-agent --stealth goto ...` |
255
- | DataDome/Kasada | `chrome-agent --connect` to real Chrome |
155
+ | Cloudflare JS challenge | `--stealth` clears it |
156
+ | Cloudflare managed Turnstile, DataDome, Kasada | `--stealth` does not help. Use `--connect`. |
157
+ | Logged-in sites | `--copy-cookies`, optionally with `--stealth` |
256
158
 
257
- ## JSON Mode
159
+ Heavy protection fingerprints the Chromium binary itself, so the only route is a real installed
160
+ Chrome. `--copy-cookies` copies the cookie database from your Chrome profile and leaves your real
161
+ Chrome untouched.
258
162
 
259
163
  ```bash
260
- chrome-agent --json goto https://example.com --inspect
261
- # {"ok":true,"url":"...","title":"...","snapshot":"uid=n1 heading..."}
262
-
263
- chrome-agent --json eval "1+1"
264
- # → {"ok":true,"result":2}
265
-
266
- chrome-agent --json read
267
- # → {"ok":true,"title":"...","text":"...","excerpt":"...","byline":"..."}
268
-
269
- # Errors also structured (exit 1, JSON still on stdout for agent parsing):
270
- chrome-agent --json click n99
271
- # → {"ok":false,"error":"Element uid=n99 not found.","hint":"Run 'chrome-agent inspect'"}
272
- ```
273
-
274
- ## Multi-Tab
275
-
276
- ```bash
277
- chrome-agent --page main goto https://app.com
278
- chrome-agent --page docs goto https://docs.app.com
279
- chrome-agent --page main eval "document.title" # → "App"
280
- chrome-agent --page docs eval "document.title" # → "Docs"
281
- ```
282
-
283
- ### Parallel Agents
284
-
285
- Multiple agents sharing the same browser corrupt each other's sessions. Isolate with `--browser`:
286
-
287
- ```bash
288
- # Agent 1
289
- chrome-agent --browser agent1 goto https://example.com
290
-
291
- # Agent 2 (separate Chrome instance)
292
- chrome-agent --browser agent2 goto https://other.com
293
- ```
294
-
295
- ## Using with AI Agents
296
-
297
- ### Skill (recommended)
298
-
299
- ```bash
300
- npx skills add sderosiaux/chrome-agent
301
- ```
302
-
303
- This installs a SKILL.md that teaches your agent the full chrome-agent workflow, commands, and tips. Works with Claude Code, Cursor, Copilot, and any agent that reads skill files.
304
-
305
- ### Manual
306
-
307
- Tell your agent to run `chrome-agent --help` — the help output includes a complete LLM usage guide.
308
-
309
- ### Claude Code permissions
310
-
311
- ```json
312
- {
313
- "permissions": {
314
- "allow": ["Bash(chrome-agent *)"]
315
- }
316
- }
317
- ```
318
-
319
- ### Connect to Your Browser
320
-
321
- ```bash
322
- chrome-agent --connect auto inspect # auto-discover Chrome with debugging
323
- google-chrome --remote-debugging-port=9222 # or launch manually
164
+ google-chrome --remote-debugging-port=9222 &
165
+ chrome-agent --connect http://127.0.0.1:9222 goto https://www.leboncoin.fr --inspect
166
+ chrome-agent --stealth --copy-cookies goto x.com/home --inspect
324
167
  ```
325
168
 
326
169
  ## Comparison
327
170
 
328
- | | chrome-agent | dev-browser | chrome-devtools-mcp | Playwright MCP |
329
- |---|---|---|---|---|
330
- | Language | Rust | Rust + Node.js | TypeScript | TypeScript |
331
- | Runtime deps | none | Node.js + npm + Playwright + QuickJS | Node.js + Puppeteer | Node.js + Playwright |
332
- | Binary size | ~3 MB | ~3 MB (CLI) + ~200 MB (daemon + deps) | npm package | npm package |
333
- | CLI startup (reuse session) | ~10ms | ~500ms (daemon check) | N/A (MCP server) | N/A (MCP server) |
334
- | Element targeting | uid + CSS selector + coordinates | CSS selectors + snapshotForAI | uid (sequential) | CSS selectors |
335
- | UID stability | backendNodeId (stable across inspects) | N/A | sequential (reassigned each snapshot) | N/A |
336
- | Action + observe | `--inspect` flag (1 call) | 1 script (batched) | 1 MCP call per action | 1 MCP call per action |
337
- | Script batching | No (atomic commands + eval) | Full JS scripts in QuickJS sandbox | No | No |
338
- | Stealth mode | 7 CDP patches + Runtime.enable skip | No | No | No |
339
- | Reader mode | `read` (Mozilla Readability) | No | No | No |
340
- | Sandbox | Chrome sandbox | QuickJS WASM sandbox | Chrome sandbox | No |
341
- | Network capture | Retroactive + live | No | No | Metadata only (no bodies) |
342
- | Console capture | Stealth-safe interceptor | No | Console messages | No |
343
- | Pipe mode | JSON stdin/stdout | No | No | No |
344
- | Code | ~22.2K lines of Rust in `src/` (blank and comment-only lines excluded; a test re-measures it) | ~76K lines (their figure, unverified here) | ~12K lines (their figure, unverified here) | Playwright |
171
+ | | chrome-agent | agent-browser (Vercel) | Playwright MCP |
172
+ |---|---|---|---|
173
+ | Language | Rust | Rust | TypeScript |
174
+ | Runtime deps | none | none (CLI) | Node + Playwright |
175
+ | Startup | 12 ms measured, one command on a running browser | daemon | cold start |
176
+ | UID stability | `backendNodeId`, stable across inspects | sequential, reassigned per snapshot | N/A |
177
+ | Compliance reporting | `verdict`/`next` on every action | no | no |
178
+ | Stealth | 7 CDP patches | delegated to cloud providers | none |
179
+ | Reader mode | `read` (Readability.js) | none | none |
180
+ | Record extraction | `extract`, structural, no LLM call | none | none |
181
+ | MCP server | none | yes | yes |
182
+ | Code | ~28.2K lines of Rust in `src/` (blank and comment-only lines excluded; a test re-measures it) | ~40K lines (their figure, unverified here) | Playwright |
183
+
184
+ ## Using it from an agent
185
+
186
+ `npx skills add sderosiaux/chrome-agent` installs a SKILL.md. Otherwise `chrome-agent --help`
187
+ embeds a full LLM usage guide, and every error carries a `hint` naming the next action. Claude Code
188
+ permissions: `{"permissions": {"allow": ["Bash(chrome-agent *)"]}}`.
345
189
 
346
190
  ## License
347
191
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "chrome-agent",
3
- "version": "0.15.0",
4
- "description": "Browser automation for AI agents. Single binary, zero dependencies, CDP direct.",
3
+ "version": "0.16.0",
4
+ "description": "Web tasks that compile. Browser automation that reads the page back after every action and reports what actually happened, in JSON. Single binary, CDP direct.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "chrome-agent": "./bin/chrome-agent.js"