Bug 1: `cookies clear` printed 'Request log cleared' instead of 'Cookies cleared'
because the output handler matched the generic `{ cleared: true }` response shape
without checking the action context. Now uses the `action` parameter to distinguish
`cookies_clear` from `requests --clear`.
Bug 2: `tab close` printed 'Browser closed' instead of 'Tab closed' because the
output handler matched the generic `{ closed: ... }` response shape without checking
the action context. Now uses the `action` parameter to distinguish `tab_close` from
`close` (full browser close).
Closes#556
Per POSIX, kill(pid, 0) returns EPERM when the process exists but the
caller lacks permission to signal it, and ESRCH when it does not exist.
The daemon liveness checks in both the Rust CLI and TypeScript daemon
treated any kill failure as "not running", which is incorrect when
running inside a macOS sandbox that restricts signal delivery to
(target self). This caused the CLI to delete the real daemon's socket
and PID files, then spawn a duplicate daemon.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- bind MediaQueryList methods when proxied for prefers-color-scheme light patch
- add regression test for addEventListener/removeEventListener
- bump version to 0.14.0-fork.6 and sync Cargo metadata
The CLI's URL normalization was auto-prepending https:// to any URL
whose scheme wasn't in the allowlist (http, https, about, data, file).
This caused chrome-extension:// URLs to become
https://chrome-extension//... which fails with ERR_NAME_NOT_RESOLVED,
preventing navigation to extension pages (popup, side panel, options).
Add chrome-extension:// and chrome:// to the open command's scheme
allowlist, and update the record start/restart commands to preserve
any URL that already contains :// instead of only checking for http.
Fixes#409
* add security hardening features
- Add authentication vault (`auth save/login/list/show/delete`) so credentials are stored locally and never exposed to the LLM (fixes Snyk W007)
- Add `--content-boundaries` flag to wrap page-sourced output in structural markers, helping LLMs distinguish tool output from untrusted page content (fixes Snyk W011)
- Add `--allowed-domains` flag to restrict browser navigation to trusted domains
- Add `--action-policy` for static allow/deny gating of action categories, with opt-in `--confirm-actions`/`--confirm-interactive` for orchestrator or human-in-the-loop confirmation
- Add `--max-output` flag to truncate large page outputs, preventing context flooding
- New docs page at /security, updated README, SKILL.md, CLI help text, and templates
* fixes
* fixes
* fixes
* fixes
* fixes
* fixes
* fixes
* docs
* add --selector flag to scroll command
The `scroll` command uses `window.scrollBy()`, which has no effect on apps
that use custom scrollable containers (e.g. a nested div with overflow-y: auto).
The backend `handleScroll` already supports a `selector` parameter, but the CLI
never exposed it. This adds `-s` / `--selector` to the `scroll` command so users
can target a specific scrollable element:
agent-browser scroll down 500 --selector "div.scroll-container"
Also fixes the backend to apply `direction`/`amount` when a selector is present
(previously those fields were only used in the no-selector branch).
Closes#501
* fixes
* feat: add --download-path option
Adds a `--download-path` flag (and `AGENT_BROWSER_DOWNLOAD_PATH` env / `downloadPath` config key) to set a default download directory for browser downloads.
Without this, Playwright stores downloads in a temp directory that is deleted when the browser closes. The new option passes through to Playwright's `downloadsPath` on `launch()` and `launchPersistentContext()`.
Fixes#507
* improvements
* fixes
* fixes
Adds `keyboard type` and `keyboard insertText` subcommands that
operate on the currently focused element without requiring a selector.
Essential for contenteditable editors (Lexical, ProseMirror, CodeMirror,
Monaco) where `type <selector>` doesn't trigger the editor's internal
event pipeline (beforeinput/DOM mutation).
- `keyboard type <text>` — page.keyboard.type() with real keystrokes
- `keyboard insertText <text>` — page.keyboard.insertText()
Note: `keyboard press` intentionally omitted — the existing top-level
`press` command already operates on current focus.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The warning "⚠ --annotate only applies to the screenshot command" fires
on every non-screenshot command when annotate is set in config. This is
noisy for users who set it as a persistent default.
Add cli_annotate tracking (matching the existing cli_* pattern) so the
warning only fires when --annotate is passed as a CLI flag.
Fixes#519. Playwright defaults `colorScheme` to `light` on all new contexts, overriding the browser/OS dark mode setting. This is especially disruptive in CDP mode, where every reconnection resets the scheme. The `set media dark` command also didn't persist its choice to new tabs or pages.
- Add `--color-scheme <dark|light|no-preference>` flag, config key (`colorScheme`), and env var (`AGENT_BROWSER_COLOR_SCHEME`)
- Store the preference in `BrowserManager` and automatically apply it to all new contexts (via Playwright's context option) and all new pages (via `page.emulateMedia` in `setupPageTracking`)
- `set media dark/light` now also persists its choice for subsequent pages and tabs
* feat: Enable capture of profiling data
Adding a new set of commands:
```
agent-browser profiler start
agent-browser profiler stop trace.json
```
With this, agents can start a profiling trace, perform a set of actions, and then extract the profiling data for analysis.
**Note:** I was originally going to call it `agent-browser profile` but I realized that might cause confusion with the `--profile` flag
CDP supports a couple commands for starting/stopping a trace.
When a trace is running, it emits events that need to be picked up.
We store these locally in the daemon until the trace is completed.
When the final event is received, we dump all of them into an output file.
That file can be loaded directly into chrome devtools or another analysis tool to visualize what happened during the agentic run.
Added some basic rust tests for parsing the commands (since they have some optional / required args)
TS daemon adds ~6 tests to make sure the profiling lifecycle (including saving the output file) works as intended
* add docs
* fixes
* fixes
---------
Co-authored-by: Chris Tate <chris@ctate.dev>
## Summary
- Return a `ParseError` when `--headers` receives invalid JSON instead of silently dropping the headers and proceeding
- Reject `frame` commands that provide no `selector`, `name`, or `url` (previously returned `{ switched: true }` without doing anything)
- Add missing mutual exclusion check for `--cdp` + `--extension` (extensions require a local browser, not a CDP connection)
## Summary
- Fix `allowFileAccess` being silently stripped from launch commands by adding it to the Zod schema in `protocol.ts` (the `--allow-file-access` CLI flag was not reaching the browser)
- Fix `trace stop` requiring a path argument despite help text documenting it as optional -- now works with or without a path
- Fix `addscript`/`addstyle` silently succeeding when neither `content` nor `url` is provided -- now returns a validation error
- Replace hardcoded ANSI escape code with `color::error_indicator()` in `main.rs` to respect `NO_COLOR`
- Fix double-parse pattern and add descriptive expect messages in `commands.rs`
- Fix incomplete string escaping in `snapshot.ts` `buildSelector` (use `JSON.stringify` instead of manual quote escaping)
- Simplify redundant ternary in `snapshot.ts` cursor-interactive role assignment
- Sync docs changelog with CHANGELOG.md (v0.8.1 through v0.10.0)
* docs: fix 6 documentation issues (#303, #245, #186, #134, #61, #73)
Addresses six open documentation issues in a single pass:
- **#303** -- Add `npx agent-browser` usage across README, SKILL.md, docs site, and `--help` output for zero-install experience. Global install is recommended as the fastest path (native Rust CLI vs Node.js indirection with npx).
- **#245** -- Document Claude Code skill installation with `npx skills add vercel-labs/agent-browser`
- **#186** -- Split installation instructions into Global (recommended), Quick Start (npx), and Project (local dependency) sections with clear guidance on when to use each
- **#134** -- Add "Why agent-browser over playwright-mcp?" comparison table to README covering output format, element selection, protocol, sessions, performance, mobile, cloud, and streaming
- **#61** -- Add "Timeouts and Slow Pages" section to SKILL.md documenting the 60s default timeout, all `wait` variants, and guidance for slow websites
- **#73** -- Replace stale `cp node_modules/...` advice with `npx skills add`, add warning against copying SKILL.md manually, add "Session Management and Cleanup" section to SKILL.md
* remove section
* fix doc
Rebased and fixed implementation of PR #184 features on current main:
Session persistence:
- --session-name flag and AGENT_BROWSER_SESSION_NAME env var auto-save/restore
cookies and localStorage across browser restarts
- State files stored in ~/.agent-browser/sessions/ with owner-only permissions
- AES-256-GCM encryption via AGENT_BROWSER_ENCRYPTION_KEY env var
- Auto-expiration of old state files (AGENT_BROWSER_STATE_EXPIRE_DAYS, default 30)
State management commands:
- state list: list saved state files with metadata
- state show <file>: display state summary (cookies, origins, domains)
- state rename <old> <new>: rename state files
- state clear [name] [--all]: clear saved states
- state clean --older-than <days>: delete expired states
New --new-tab flag for click command:
- Opens link href in a new tab instead of navigating the current tab
Security hardening:
- Session name validation prevents path traversal (CLI + daemon)
- safeHeaderMerge prevents prototype pollution in header merging
- WebSocket stream server binds to 127.0.0.1 only
- State files written with 0o600 permissions
Fixes applied over the original PR:
- Use color.rs module instead of hardcoded ANSI escape codes
- Align CLI output field names with daemon response format
- Add CLI-level --session-name validation (not just daemon-side)
- Avoid adding "DOM" to tsconfig.json lib (use proper typing in evaluate)
- Keep version at 0.9.3 (matches current main)
- Centralize session name validation in daemon.ts helper
- Update all documentation (README, SKILL.md, docs site, --help output)
Co-authored-by: Chris Tate <chris@ctate.dev>