Let your coding agent use the browsers you're already signed into.
Chrome, Arc, Brave, Edge, Comet or Firefox, on this machine or another one over SSH.
Install · Benchmark · How it compares · Driving a page · Remote browsers · Command reference
npm install -g @phnx-labs/browser-cli
npx skills add phnx-labs/browser-cli # teaches your agents to use itOr paste this into your agent:
Install browser-cli (npm install -g @phnx-labs/browser-cli) and read its
skill (browser skills path). Then open news.ycombinator.com in my browser
and summarize the top 5 stories.
- Your own browsers, signed in. It drives the Chrome, Brave, Edge, Comet, Firefox or Arc profile you already use, cookies and logins included, instead of a fresh headless browser that sites block and that has no sessions.
- Fewer turns for the agent. Every action returns once the page has settled,
and
--snapshotprints the page it left, so known steps chain in one shell call with no task id to pass.start --snapshotlists the first page, andclick --text "Checkout"clicks by name. A ref keeps naming its element when a count in its label changes ("Cart, empty" to "Cart, 2 items"), and refs reach into iframes. - It does not stall where pages do. Alerts are answered and reported instead
of freezing the tab, a
confirm()comes back as a question forbrowser dialog, router navigations are listed once the new page is drawn, date and time inputs take "19:45", and off-screen elements are scrolled into view. - Cheap turns. The shipped skill is about 4.5 KB and command output is short, so each agent turn carries less context.
- Agents share a browser safely. Each task owns its tabs, so several agents can work in one signed-in browser at once; see Several agents, one browser.
- Remote browsers.
start --device <machine>binds a task to a browser on another machine; later commands follow it there over one kept-alive SSH connection. - A native binary. About 12 ms per command; the service keeps one session per task, with its own tabs, screenshots, recordings and network capture.
- Fastest of the five: 14.4 s per task, against 15.8 s for browser-harness and 16.8 s for Browser Use.
- Fewest tokens and lowest cost: 97k tokens and $0.041 per task, against 102k and $0.044 for Browser Use and 105k and $0.046 for browser-harness.
- Turns are level with Browser Use: 4.5 per task against 4.4; browser-harness takes 4.7. agent-browser and Browserbase's
browsetake about twice the turns and 2.5 to 3 times the tokens. - All 16 runs correct for browser-cli, Browser Use and agent-browser; browser-harness and
browsemissed one each. - On Browser Use Bench v2.1, Browser Use's own benchmark of long research tasks, browser-cli was 2.2 times as fast as Browser Use (90 s against 202 s per task), 7% cheaper, and scored 45.4 to its 43.6 with the benchmark's own rubric judge. browser-harness scored higher (50.4) at 220 s. Four tasks, 16 runs per tool: docs/benchmarks.md.
Method and every run
Claude Sonnet 5.5 ran each task headless in Claude Code with one tool and that tool's own shipped skill, on macOS against a fresh headless Chrome for Testing 153, two runs per task, on 2026-10-19 (trials 11 and 12, run in turn). The versions were:
- browser-cli 0.1.33
- Browser Use 0.13.11 (its CLI runs on browser-harness)
- browser-harness 0.1.13
- agent-browser 0.39.1
- Browserbase
browse0.6.1
Each cell gives the two runs' turns and their mean tokens; tokens count input,
including cached context, plus output. Wall-clock time is mostly the model
thinking between turns, so it varies more between runs than turns and tokens do.
With two runs per task, read single rows as a direction. One browse Demoblaze run took 810 s and 28 turns without an answer, which carries most of its 85.4 s mean. One browser-cli run that found the benchmark's Chrome not running was set aside and run again; no other run hit that.
Each browser start opens a task that owns its tabs. Page commands such as refs, text, click and type act only on that task's tabs, and done closes only the tabs it opened. So several agents can work in one signed-in browser at once without reading, typing into or closing each other's pages.
To test it, three Claude Code agents ran at the same time in one browser: one browsed a shop across pages, one filled a pizza-order form, and one completed a checkout. Every agent was told: "Work only in tabs you opened yourself." Each tool ran this twice, six agent runs per tool, on 2026-10-19. A run counts as showing another agent's tab when a script found another agent's site in that agent's tool output.
browser-cli 0.1.23 leaked once (1 / 6). Several agents that ran start at the same moment raced to open the browser connection, and one agent's task was dropped; its "not found" error listed the other agents' tasks. 0.1.24 fixes the race, and the row above is 0.1.24.
browser-harness documents the limit itself: one daemon has one shared current tab, and "two agents that switch tabs and act simultaneously can race".
Read from each tool's source at a pinned commit and its docs on 2026-10-19. browser-cli is the only one that combines per-task tab ownership with Chromium-family browsers on your own other machines over SSH; its Firefox and Arc profiles run on the local machine. Others reach further elsewhere: agent-browser drives Safari and the iOS Simulator and has five cloud providers built in.
- An agent with
browseracts as you. It can read and click anything your signed-in profile can. Give it a dedicated profile (browser profiles create work --browser chrome) when it should not see your personal accounts. - Nothing leaves your machine. browser-cli sends no telemetry. It talks to your browser's local DevTools port, Firefox's BiDi port or Arc's Apple Events, and to the machines you name over your own SSH config.
- What ships. npm installs one compiled binary per platform, published from this repository's release workflow through npm trusted publishing (OIDC), so no npm token exists to leak.
browser profiles create work --browser chromium
browser start --profile work --url https://example.com # prints the task name, e.g. 3f2a9c1d
browser screenshot -o shot.png --task 3f2a9c1d
browser done --task 3f2a9c1dstart launches (or attaches to) the browser for a profile and opens a task —
a named browsing context with its own tabs and capture ledger. Page verbs like
navigate and screenshot attach to that task: they resolve the caller's live
task, or take --task <id> to pick one explicitly. done closes the task's
tabs; browser stop stops the whole service.
Run browser --help for the full verb list and browser <verb> --help for its
options.
The loop an agent runs: list what it can act on, act, read the result.
browser start --url https://example.com --snapshot # task name, then the page's refs
browser refs # numbered interactive elements
browser text # title, URL and the readable text
browser click 3 --snapshot # act, then print the page it left
browser click --text "Checkout" # by accessible name, optionally --role button
browser type 5 "ada@example.com" # text positionally, or --text
browser type "Email" "ada@example.com" # or name the field by its label
browser type 9 "19:45" # date and time inputs take their value
browser select 7 "Large" # a <select> option by label or value
browser press Enter --snapshot
browser dialog accept # or dismiss: answers a confirm() or prompt()
browser navigate https://shop.example/p/1 && browser click --text "Add to cart" && browser text- Refs are numbers from the latest listing. Add
--snapshottostart,click,type,selectandpress: it prints the new URL, title and refs in the same call. Every action returns once the page has settled (Chrome-family browsers;--no-waitreturns as it lands), so steps chain with&&. A ref keeps naming its element while that element is on the page, even when a number in its label changes; one that drifted is re-matched by role and name before the action, within the same frame. - Dialogs. An
alert()or leave-page prompt is accepted and printed. Aconfirm()orprompt()waits: the action that raised it prints the question, andbrowser dialog accept|dismissanswers it. - iframes. In Chromium-family browsers,
refslists elements inside same-site and cross-site iframes under an- iframe "<url>"line, andclick,type,hoverandselectact on them;textreads them too. One level of frames below the page is covered.uploadinto a cross-site iframe is refused with the frame's URL. - Off-screen elements are scrolled into view before a click or hover.
- Pages without usable refs (canvas apps, custom widgets): take a
screenshotand click by position withclick --at X,Y. - Many steps in one process:
browser streamreads NDJSON requests on stdin and keeps one connection to the service open.
A profile names a browser, where it runs, and how to reach it. Profiles are
machine-local and stored under ~/.agents/devices/<machine>/agents.yaml.
browser profiles create work --browser chrome # local Chrome, auto-assigned CDP port
browser profiles create hl --browser chromium --headless # headless Chromium
browser profiles list
browser profiles logins # signed-in services and accounts per profile
browser profiles logins --json # [{"profile","service","account"} | {"profile","service":null,"account":null,"unread"}]logins reads each profile's cookie store where its browser keeps it: Arc's
User Data/<profile dir>, Comet's own user-data dir, a pinned userDataDir,
or the runtime dir browser launched into. A store it cannot read here (a
profile declared on another device, a browser reached over ssh://, Firefox,
a profile never launched on this machine) is listed as (not read: <reason>),
and in --json as one {"profile", "service": null, "account": null, "unread"} row, so a profile with no rows had its store read and has no live
session.
Each profile resolves to an endpoint:
cdp://127.0.0.1:9222— a Chromium-family browser over the DevTools Protocol.bidi=firefox-bidi://127.0.0.1:9674— Firefox over WebDriver BiDi.ssh://user@box?port=9222— a browser on a remote host reached over SSH.
Bind a task to a browser on another machine with --device on start:
browser start --device box --profile work
browser navigate https://example.com
browser screenshot -o shot.png--device <alias> resolves against ~/.ssh/config, and against an inherited
context descriptor when the CLI runs under agents-cli. browser-cli itself does
not read a fleet registry. Use --device local to force the task onto this
machine. The device is bound once at start; page verbs run against the task's
bound device, so --device is only valid there.
The package ships the browser skill in the standard Agent Skills layout, so agents learn the CLI from the version that is installed:
skills/browser/
SKILL.md # workflow, defaults, where to look for flags
references/arc.md # Arc limits and sharing the user's window
references/sites/<site>.md # per-site guides (higgsfield, linkedin, perplexity, slack)
scripts/slack/*.js # page scripts the Slack guide runs with evaluate --file
npx skills add phnx-labs/browser-cli # install into your agents
browser skills path # the installed copy (link agents here)
browser skills get arc # read one document
browser help --json # every command, argument and optionThe skill lists no flags. Agents read browser <command> --help or
browser help --json, which always match the installed binary.
browser start --url prints the site guide for that host.
Agents CLI ships agents browser as a thin consumer of this binary. It forwards
every verb unchanged and adds the concerns it owns: fleet device discovery
(--device becomes an SSH target), agent-session identity, remote-control
consent, and cross-machine session history. The seam between the two — the
inherited context descriptor, the event stream, and the shared on-disk paths —
is documented in docs/integration.md. The command
reference is docs/browser.md.
| Platform | Architectures |
|---|---|
| macOS | arm64, x64 |
| Linux | arm64, x64 |
| Windows | x64 |
Chromium CDP, Firefox BiDi and SSH endpoints work on all three. Native Arc control is macOS-only. Safari is not supported.
- Headless on Linux. A headless Chromium or Brave needs the usual shared
libraries (fonts,
libnss3,libatk,libgbm, and friends). Install your distribution's chromium package to pull them in; a missing library shows up as the browser process exiting immediately afterstart. - Port already in use. Each profile binds a debugging port. If
startreports a squatted port, another browser or a stale process holds it — stop it, or create the profile with a different--endpoint. - Comet and Arc. Comet is driven as a Chromium-family browser over CDP and works best as an attach-only profile against a browser you already launched. Arc is always attach-only and reuses an open tab or Space rather than creating one; it is macOS-only.
- Service state.
browser statusshows whether the IPC service is running and lists active tasks.browser stopshuts the service down.
browser sessions opens a searchable task and capture picker in a terminal.
Use arrows to move, Enter to browse or open a capture, and Escape to go back.
--no-interactive keeps the printed listing; --json keeps the existing
profile/capture schema. Add --tasks for durable task rows, including tasks
without captures, or --search <text> to filter those rows.
The same core filters as sessions apply to the picker, the printed listing
and --json: --since <when> / --until <when> take 2h, 7d, 4w, 1mo,
1y or an ISO date and keep rows by last activity (capture time in the
profile listing), and an invalid value exits 2. --limit <n> caps the printed
listing (default 50); --json is unbounded unless --limit is given. The
count footer (Showing 50 of 120 tasks. --limit 120 or --json to see all, …)
goes to stderr, so piped stdout carries rows only. The picker header names the
active filters.
browser sessions --since 7d
browser sessions --tasks --since 1mo --until 7d --json
browser sessions --no-interactive --limit 20Browser owns 365-day task summaries in .history/browser/history.db under
its configured Agents home. Neither Agents nor Sessions needs to be installed.
On first task listing it adopts legacy browser summaries read-only;
browser sessions migrate [--from /path/to/sessions.db] --json repeats the
import safely. Captures stay in place and are never deleted by summary retention.
Building, testing, regenerating the command reference and cutting a release are in docs/development.md.
Functional Source License 1.1 with an Apache 2.0 future grant (FSL-1.1-Apache-2.0): use it for anything except a competing product, and each release becomes Apache 2.0 two years after it ships.
