The missing toolchain for CLI coding agents. Run any agent on your existing subscription. Spawn parallel teams in isolated terminals or dispatch to the cloud for a PR. Watch live state across the fleet, nudge stalled runs, and message agents mid-flight. Schedule routines and set monitors that fire an agent when a source changes, drive browsers and Electron apps, store secrets behind Touch ID, and file tickets from a menu-bar bar — all from one CLI.

https://agents-cli.sh/demo.mp4

npm install -g @phnx-labs/agents-cli
# or
bun install -g @phnx-labs/agents-cli

Already installed? agents upgrade updates agents-cli itself to the latest version (agents upgrade 1.2.3 for a specific version or dist-tag, -y to skip the confirm prompt). The command is upgrade on every platform -- there is no agents update (on macOS, agents helper update is a different command that reinstalls the keychain helper, not agents-cli).

Source: github.com/phnx-labs/agents-cli

Also available as ag -- all commands work with both agents and ag.


Pin versions per project

# This project needs [email protected] -- newer versions changed tool calling.
agents use [email protected] -p

# The monorepo uses [email protected] across the team.
agents use [email protected] -p

This creates an agents.yaml at the project root:

# agents.yaml (commit this to your repo)
agents:
  claude: "2.0.65"
  codex: "0.116.0"

Think requirements.txt for CLI coding agents, on steroids. A shim reads agents.yaml from the project root and routes claude / codex / gemini / grok (and others) to the right version automatically. Each version gets its own isolated home -- switching backs up config and re-syncs resources.

agents add [email protected]     # Install a specific version
agents add codex@latest       # Install latest
agents add codex@oldest       # Install the oldest published version
agents view                   # See everything installed

One config, every agent

# Set up the Notion MCP server once.
agents install mcp:com.notion/mcp

# It's now registered with Claude Code, Codex, Gemini CLI, and Cursor.
agents mcp list

Skills, slash commands, rules, hooks, and permissions work the same way -- install once in ~/.agents/, synced to every agent's native format automatically.

agents skills add gh:yourteam/python-expert     # Knowledge pack -> all agents
agents commands add gh:yourteam/commands         # Slash commands -> all agents
agents rules add gh:team/rules                   # AGENTS.md -> CLAUDE.md, GEMINI.md, .cursorrules
agents permissions add ./perms                   # Permissions -> auto-converted per agent

Write one AGENTS.md. It becomes CLAUDE.md for Claude Code, GEMINI.md for Gemini CLI, .cursorrules for Cursor.


Run any agent

agents run claude "Find all auth vulnerabilities in src/"
agents run codex "Fix the issues Claude found"
agents run gemini "Write tests for the fixed code"

Each resolves to the project-pinned version with skills, MCP servers, and permissions already synced. Single-typo names auto-correct across every command — agents view cladue resolves to claude, agents add codx@latest to codex.

Rate-limited? Keep working.

# Claude Code hits a rate limit -> Codex picks up automatically. Same project, same config.
agents run claude "refactor auth module" --mode edit --fallback codex,gemini

Multiple accounts? Spread the load.

# Picks the signed-in account you haven't used recently.
agents run claude "summarize recent commits" --strategy balanced

# Or choose one account/version interactively for only this run.
agents run claude@
agents run codex@ "review this branch"

--strategy balanced spreads work across available versions of the same agent -- useful when you have multiple accounts and want to avoid burning through one.

A trailing @ opens an account picker before either an interactive or prompt-based run. Each installed version shows its account identity, exact version, login state, plan, and every available session, weekly, or monthly limit. Logged-out, rate-limited, and out-of-credit accounts remain visible with the reason they cannot be selected; signed-in accounts whose provider does not expose quota data stay selectable and say limits unavailable. The choice pins only that run and does not change your default version.

Account selection is available for Claude, Codex, Gemini, Grok, Antigravity, Kimi, Droid, and OpenCode. It requires a terminal and cannot be combined with --resume, --strategy/--balanced, --lease, or --host/--device; profiles and workflows must use their concrete host agent instead.

Chain agents

agents run claude "Review PRs merged this week, summarize risks" \
  | agents run codex "Write regression tests for the top 3 risks"

Supports plan (read-only), edit, auto, and skip modes, effort levels, JSON output for scripting, and timeout limits.

What does --mode skip actually do?

Treat skip as a last-resort escape hatch. In direct-exec runs (without --acp), agents-cli forwards the harness's native no-prompt flag; it does not add another safety layer. Prefer auto where it adds a safer automatic policy (smart classifier on Claude/Copilot, native high-auto mode on Droid, or interactive Kimi), or edit everywhere else. For headless Kimi, edit, auto, and skip all use the same already-auto-approved -p behavior, so prefer edit rather than signaling a blanket bypass. Harnesses without a native bypass flag reject direct-exec skip.

Harness Direct-exec --mode skip becomes
Claude Code --dangerously-skip-permissions
Codex --dangerously-bypass-approvals-and-sandbox (equivalent to --yolo)
Gemini --yolo
Cursor -f
OpenClaw --mode full
GitHub Copilot --allow-all (alias: --yolo)
Antigravity --dangerously-skip-permissions
Grok --always-approve
Kimi --yolo interactively; no extra flag in headless -p runs, which already auto-approve
Droid --skip-permissions-unsafe

With --acp, these native flags are not used. agents-cli instead grants skip permission requests at the ACP protocol layer: it selects allow_always when offered, otherwise the first permission option offered by the server. The same last-resort warning applies.

Codex has no native smart-classifier mode, so agents run codex --mode auto resolves to sandboxed edit and can still prompt. agents run codex --mode skip is different: it bypasses approvals and removes the sandbox. full remains an alias for skip, but new scripts should use the explicit skip name.

One protocol, every harness

# Typed event stream instead of raw stdout. Same command, any supported agent.
agents run claude "review this diff" --acp --json

--acp routes through the Agent Client Protocol so you get a unified event stream -- agent_message_chunk, tool_call, plan_update, stop_reason -- instead of writing a parser per CLI. File writes and shell commands flow through agents-cli, which means --mode plan becomes a real sandbox: the write RPC is denied, not just unused.

ACP adapters are documented for claude, codex, gemini, cursor, opencode, openclaw, and grok. Other harnesses keep running on the direct-exec path.


Sessions across agents

When you run multiple agents, conversations scatter across tools. Session search brings them together.

# Where was that auth conversation? Search Claude Code, Codex, Gemini CLI, OpenCode at once.
agents sessions "auth middleware"

# Filter by agent, project, or time window
agents sessions --agent codex --since 7d
agents sessions --project my-app

# Read a full conversation
agents sessions a1b2c3d4 --markdown

# Just the last 3 turns, user messages only
agents sessions a1b2c3d4 --last 3 --include user

Interactive picker when you're in a terminal. Structured output (--json, --markdown, filtered by role or turn count) when piped.

Backed by a SQLite + FTS5 index at ~/.agents/.history/sessions/sessions.db with incremental scanning -- warm reads in ~100ms. External tools can consume --json output as a programmatic observability layer; see docs/05-sessions.md for the schema and docs/06-observability.md for the consumption patterns.

Live state, and catching up fast

Search is the past tense. --active is the present -- it infers what each running session is doing right now from the tail of its transcript.

agents sessions --active            # every live run across the fleet, with state
agents sessions focus a1b2c3d4      # jump back into one — attach in place, or resume

On a terminal, agents sessions --active (and a bare agents sessions) open the interactive session browser — one filter you drive with single keys, re-pulled live across the fleet:

key filters by flag it mirrors
s search text --query / positional
r running only --active
c team sessions --teams
a agent (cycles) -a
d device (cycles) --device
p this repo ↔ all dirs --all
w time window --since
resume / attach resume / focus
y copy the equivalent command --print-cmd

Filters stack (they AND together), the active set shows in the header, and the highlighted row previews below. Because every hotkey has a flag, the view you build by hand is a real command: press y (or run --print-cmd) to get the exact ag sessions … line — explore interactively, hand the line to an agent. Piped output, --json, or --no-interactive keep the plain listing for scripts. Peek without opening the pager with agents sessions <id> --preview.

Each live session resolves to working, waiting_input (with why -- a question, a plan review, or a permission prompt), or idle, alongside badges for the PR it opened, the worktree it sits in, and the ticket it's working. agents sessions focus [id] attaches the live pane in place -- the tmux split locally or over SSH, or its Ghostty tab -- and falls back to a fresh tab + resume when the terminal is gone.

Landing on a session cold? agents sessions <id> prints a catch-up digest: an inferred title, files changed grouped by directory (created / modified / deleted), a histogram of which tools did the work, and the last test verdict -- the signals to reload a task in seconds.

Resume anywhere — and stay resumed

Pick up any past conversation and drop it back into a terminal:

agents sessions resume                     # multi-select; packs two sessions per tab
agents sessions resume "auth middleware"   # pre-filter the pool, then choose
agents sessions resume --tmux              # into persistent tmux — survives editor restarts
agents sessions resume --host zion --tmux  # resume on another machine over SSH

agents sessions resume reopens sessions in whatever terminal you're in -- auto-detected across iTerm, Ghostty, tmux, and the VSCodium agent-terminal, or forced with --iterm / --ghostty / --tmux / --vscodium. Back them with tmux and the runs turn durable: detach, close your editor, reboot the GUI -- the session is still alive to agents tmux attach. The whole agents tmux subsystem (persistent multiplexer sessions that survive editor restarts and can be shared with other tools) sits underneath.


Control the fleet

Running agents aren't fire-and-forget. Steer them mid-run without opening their terminals.

Message a running agent

# Delivered at the agent's next tool call — no restart, no lost context.
agents message tester "also cover the null case"

agents message <target> <text> reaches any running agent by name or id -- a live local run, a teammate, a loop agent, or a cloud task -- and the text lands at its next tool call. Tag the sender with --from <who>.

See every open block

agents feed                         # grouped by outcome (ticket/PR/worktree) across the fleet
agents feed --flat                  # one row per agent (legacy)
agents feed --host mac-mini         # scope the view to one or more hosts
agents feed --local                 # skip the SSH fan-out
agents feed --json                  # blocks stamped with their outcome key

Top-level questions and waiting notifications publish one atomic open-block record per session, including the mailbox id, host, runtime, and every answer option. The default view collapses agents under the outcome they serve (Linear ticket, PR, worktree slug, or Unassigned) so a 1,100-agent fleet reads as dozens of deliverables. Answered, resumed, and stopped blocks clear automatically; Task subagents are excluded. The rendered reply command uses the same mailbox id with agents message, so the decision routes back to the agent that asked it.

Auto-nudge stalls

agents watchdog            # one tick, dry run — reports what it WOULD nudge and why
agents watchdog --nudge    # actually inject "Continue." into the stalled split
agents watchdog --watch    # daemon loop: a tick every --interval

agents watchdog detects a stalled session, resolves the exact terminal split it lives in (tmux, iTerm, VSCodium, or a raw pty), and injects a nudge -- Continue. by default, or set --text. It's dry by default; --nudge acts on a single tick, and agents watchdog enable flips global auto-nudge on so --watch injects on its own. Steer a single run with agents watchdog policy <id> off | keep | handsoff.


Sync the fleet

One machine is set up the way you like it. Make every other machine match -- same agents installed, same config, logins seeded -- in one command.

# agents.yaml -- add a fleet: block
fleet:
  devices: all              # every online registered device (minus this one)
  defaults:
    agents: [claude@latest, codex@latest, gemini@latest]
    sync: [user]            # config scopes to reconcile
    login: sync             # propagate logins where the token is portable
agents apply --plan                 # device x dimension matrix; changes nothing
agents apply                        # reconcile the fleet (confirms first; -y to skip)
agents apply --device yosemite-s0   # scope to one device
agents apply --only agents,config   # limit dimensions (agents, config, login)
agents apply --no-login             # skip login propagation

agents apply (ag apply) probes every target over the existing SSH transport, then reconciles it to the profile: installs missing agents, upgrades agents-cli, syncs the named config scopes, and propagates logins so a host signed in once seeds the fleet -- turning "6 hosts x 8 harnesses = 48 OAuth flows" into one. Portable credential files (claude, codex, gemini, grok, kimi, opencode, droid, antigravity) stream to each target over encrypted SSH stdin, never shell-interpolated, and land at 0600. Honest boundary: macOS keychain-bound tokens (claude, antigravity on a Mac target) can't be extracted -- those surface as a one-time manual login, never faked. --plan / --dry-run shows the full matrix without touching anything.

See docs/fleet.md for the manifest schema and reconcile semantics.


Run open models through Claude Code (experimental)

Note: Profiles are experimental, but available by default — no enable step needed.

# Kimi K2.5 responding inside Claude Code's UI, tools, and skills.
# No proxy server. No LiteLLM. One OpenRouter key, stored in Keychain.
agents profiles add kimi
agents run kimi "refactor this file"

Built-in presets (all via OpenRouter, one shared key):

Preset Model Notes
kimi Kimi K2.5 #1 HumanEval. Reasoning -- interactive only.
minimax MiniMax M2.5 #1 SWE-bench Verified. Reasoning.
glm GLM 5 #1 Chatbot Arena (open-weight).
qwen Qwen3 Coder Next Latest coding Qwen. Print-safe.
deepseek DeepSeek Chat V3 Latest non-reasoning. Print-safe.

A profile swaps the model while keeping Claude Code as the agent runtime -- same UI, slash commands, skills, MCP tools. Under the hood: ANTHROPIC_BASE_URL + ANTHROPIC_MODEL, auth from Keychain at spawn time.

Custom endpoints (Ollama, vLLM) work too -- drop a YAML in ~/.agents/profiles/:

name: local-qwen
host: { agent: claude }
env:
  ANTHROPIC_BASE_URL: https://ollama.example.com
  ANTHROPIC_MODEL: qwen3.6:35b
auth:
  envVar: ANTHROPIC_AUTH_TOKEN
  keychainItem: agents-cli.ollama.token

Profile YAML has no secrets -- safe to agents repo push to a shared repo. agents profiles presets lists the full catalog.


Run on your own machines

Dispatch any read-only or config command -- and agents run itself -- to another machine over SSH. No daemon.

# Enroll a machine (from ~/.ssh/config, or inline with user@address)
agents hosts add gpu-box
agents hosts check gpu-box              # reachable? which agents-cli version?

# Run there instead of locally
agents run claude --host gpu-box "profile this build"   # headless: follows live by default
agents run claude --host gpu-box                         # no prompt → interactive TTY over SSH (tmux-backed)
agents run claude --host gpu-box --copy-creds "fix auth" # copy local runtime creds + Claude token, shred after
agents hosts ps                         # list dispatched runs + terminal status
agents hosts stop <id>                  # terminate a hung/detached run (alias: kill)
agents logs --host gpu-box              # pick a dispatched run — concise summary by default
agents logs <id> --full                 # the full raw transcript / stdout (token-heavy)
agents logs <id> -f                     # re-attach to a running one and follow
agents view claude --host gpu-box       # inspect the remote install
agents sync --host gpu-box              # make the remote machine current
agents doctor --devices                 # readiness matrix for every registered device
agents doctor --devices --json          # machine-readable fleet readiness
agents doctor --device mac-mini         # same matrix, scoped to one device
agents fleet status                     # warnings rollup + health/sync/version/Auth matrix (cache-first)
agents fleet status --live              # force a live resource probe (alias of --refresh)
agents fleet status --json --strict     # scriptable fleet health gate
agents check --devices                  # CI drift gate across every registered device

# Your Tailscale fleet, auto-discovered
agents devices sync                     # ingest `tailscale status`
agents devices list                     # fleet + headroom: load, mem, idle/busy — which box has room (cache-first)
agents devices list --live              # force a live probe of every device (alias of --refresh)
agents devices list --full              # add per-device cores and free/total RAM
agents devices list --no-stats          # instant: names/addresses only, skip the probe
agents ssh mac-mini                     # hardened SSH: fails fast if offline,
                                        # PowerShell on Windows, password-from-Keychain,
                                        # auto-syncs your terminfo (Ghostty/kitty/…) so
                                        # backspace, colors & clear work on the remote
agents hosts list                       # devices show up here too (one host pool)
agents hosts add mac-mini --cap gpu     # tag a device for capability routing (--host gpu)

# Hosts as a task backend + scheduled placement
agents cloud run "nightly benchmark" --host gpu-box --agent claude   # task in cloud ps AND hosts ps
agents routines add nightly -s "0 2 * * *" -a claude -p "run the sweep" --run-on gpu-box

agents devices list shows normalized load, memory pressure, and an idle/light/busy/loaded headroom badge, plus a fleet-capacity summary (164 cores · 421G free / 518G RAM). It answers "which machine has room right now?" — the utilization signal the teammate scheduler doesn't yet see. It's cache-first: reads serve instantly from a stats cache the daemon warms (~every 3 min), probing only this machine locally plus any device missing from the cache; pass --refresh (or the shorter --live) to force a full live probe of every box. Cache-served output notes its age (updated 2m ago — pass --refresh (--live) for a live probe).

agents fleet status adds an Auth column — which agent accounts are actually logged in, per device, read from the auth-health cache (no network). Four buckets keep it from crying wolf: ●live (verified), ·present (signed in but the agent has no live-probe endpoint — e.g. codex/grok — benign), ◐degraded (soft/self-healing: expired-but-refreshing, rate-limited), and ○revoked (server rejected — re-login now). Only means a real re-login is needed. Run agents fleet ping to force a live re-verification across the fleet.

Hosts (agents hosts) are git-synced dispatch targets in agents.yaml; devices (agents devices) are your Tailscale machines in a local registry. Both ride SSH and feed one host pool: devices appear in agents hosts list and capability routing without a second enrollment. On --host runs every agents run option is either forwarded (--effort --env --timeout --loop …), rejected loud (--secrets never crosses SSH implicitly), or consumed locally — nothing silently drops. See docs/00-concepts.md.

Every --host command rides one multiplexed SSH engine, tuned for driving a fleet from a small laptop: the first call to a machine opens a control socket and every later call reuses it (no repeat TCP+auth handshake), connections carry keepalive so a dropped link dies in ~45 s instead of zombying, and following a remote run polls in a single round-trip per cycle. Measured against a Tailscale-relayed host: repeated calls ~6–7× faster, dispatch readiness ~2×, and the follow loop ~21× faster with 50% fewer local ssh spawns. Design: docs/09-ssh-transport.md · reproduce: node scripts/bench-ssh.mjs <host>.


Teams

agents teams create auth-feature

# Research first, then implement, then test.
agents teams add auth-feature claude "Research auth libraries"       --name researcher
agents teams add auth-feature codex  "Draft the migration"           --name migrator --after researcher
agents teams add auth-feature claude "Write tests for the new code"  --name tester   --after migrator

agents teams start auth-feature     # Fires teammates whose deps are done
agents teams status auth-feature    # Who's working, what they changed, what they said

Teammates run detached -- close your terminal, they keep working. Check in with teams status, glance at a teammate's summary with teams logs <name> (add --full for the raw output), clean up with teams disband.

Team state is observable via agents teams list --json / agents teams status --json (compact by default; add --verbose for the full per-teammate shape). External tools join it with sessions --json (teammates get isTeamOrigin: true) and cloud list --json (for --cloud teammates) to build a unified fleet view. See docs/06-observability.md.


Cloud

Some work shouldn't tie up your laptop. agents cloud run hands a task to a managed provider that clones the repo, plans, implements, tests, and opens a PR -- while your terminal stays free. A fifth provider, host, dispatches the same way onto machines you own: agents cloud run "…" --host gpu-box (tasks track in agents cloud ps and agents hosts ps alike).

# Dispatch and detach — streams to the cloud, not your terminal.
agents cloud run "fix the flaky test in the payments suite" \
  --provider rush --repo acme/api --branch main

agents cloud list                                      # what's running, queued, or needs review
agents cloud logs <id>                                 # re-attach and stream
agents cloud message <id> "also update the changelog"  # steer it mid-run
agents cloud cancel <id>

Four managed backends behind one interface (agents cloud providers):

Provider What runs Notes
rush Claude against a GitHub repo + branch Opens a PR. Multi-repo via repeatable --repo; attach screenshots with --image for vision dispatch.
codex A pre-built Codex Cloud environment Target it with --env.
factory droid exec on a cloud VM Computer-use; pick the box with --computer.
antigravity Gemini managed agents Antigravity harness in a remote sandbox.

Auto-routes each --agent to its native cloud, or pin the backend with --provider. Instead of dispatching now, register a run as an event trigger with --on pull_request (also push, issue_comment, workflow_run) -- it persists as a trigger-bound routine that fires on the event. --json on every subcommand for scripting.


Workflows

Bundle an orchestrator prompt with optional subagents, skills, and plugins into a named, reusable pipeline. One bundle, one invocation.

# Use a workflow — workflow name goes in the agent slot
agents run code-review "review PR #42 on acme/api"

# List + inspect
agents workflows list
agents workflows view code-review

# Install from GitHub or local
agents workflows add gh:yourteam/code-review
agents workflows add ./my-workflow

A workflow is a directory:

~/.agents/workflows/code-review/
  WORKFLOW.md          # YAML frontmatter + orchestrator system prompt
  subagents/           # optional: *.md files exposed to the orchestrator
    security.md
    style.md
  skills/              # optional: knowledge packs scoped to this workflow
  plugins/             # optional: plugin bundles

WORKFLOW.md's Markdown body is the orchestrator's system prompt. Files under subagents/ get copied to ~/.claude/agents/ at run time so the built-in Agent tool can dispatch to them by name — including in parallel. skills/ and plugins/ sync into the version home just for the run.

# WORKFLOW.md frontmatter
---
name: Code Review
description: Evidence-grounded PR review with file:line citations.
model: opus
tools:
  - Read
  - Grep
  - Bash
  - WebFetch
---

Workflows that need to write — post PR comments, edit files, send Slack — should run with --mode edit, or --mode auto on Claude Code and GitHub Copilot. Reserve --mode skip (legacy alias: full) for last-resort bypasses. agents run defaults to --mode plan (read-only), which deadlocks at ExitPlanMode in headless runs.

Resolution is project > user > system: a <repo>/.agents/workflows/<name>/ overrides a same-named workflow in ~/.agents/workflows/. Commit project workflows with your repo so teammates get the same pipeline.


Plugins

Bundle skills, commands, hooks, MCP servers, settings, and permissions under a single manifest. One source dir at ~/.agents/plugins/<name>/, mirrored into every installed Claude / OpenClaw version automatically.

# Install from a git URL or local path
agents plugins install hivemind@https://github.com/activeloopai/hivemind.git
agents plugins install ./my-plugin

# Apply to one agent (default version) or all supported
agents plugins sync rush-toolkit claude
agents plugins sync rush-toolkit

A plugin is a directory with a manifest:

~/.agents/plugins/my-plugin/
  .claude-plugin/plugin.json       # required: { name, version, description }
  skills/<name>/SKILL.md           # optional
  commands/*.md                    # optional
  hooks/hooks.json                 # optional — executable surface
  .mcp.json                        # optional — executable surface
  bin/, scripts/, settings.json    # optional — executable surface
  permissions/                     # optional — executable surface

On sync, agents-cli copies the plugin into each version home's marketplace (<home>/.claude/plugins/marketplaces/agents-cli/plugins/<name>/), registers the synthetic marketplace, and flips settings.json#enabledPlugins[<name>@agents-cli] = true so Claude / OpenClaw load it.

Executable-surface gate

Plugins that ship hooks/, .mcp.json, bin/, scripts/, settings.json (non-permissions), or permissions/ can execute code on session events. agents-cli requires explicit consent before flipping enabledPlugins:

# Hooks-bearing plugins copy in but stay disabled by default
agents plugins install hivemind@https://github.com/activeloopai/hivemind.git \
  --allow-exec-surfaces

# Same gate on re-sync (e.g., after upstream updates)
agents plugins sync hivemind claude --allow-exec-surfaces

Skills, commands, and subagents are declarative and never trip the gate. The gate is per-plugin, per-install: consenting to hivemind doesn't grant blanket exec-surface trust to anything else.

Version portability

Plugins live in the user repo (~/.agents/plugins/), not inside any single version home. Switching Claude via agents use claude@<v> re-syncs the plugin into the new version automatically — no re-install. New Claude versions added later pick it up on their first sync. Project-level <repo>/.agents/plugins/<name>/ overrides a same-named user plugin (resolution is project > user > system, same as every other resource).


Browser

Give agents access to a real browser — no relay extension, no cloud service, no Playwright getting blocked.

# First run: omit --profile and we auto-pick the first installed Chromium-family
# browser. macOS prefers Chrome > Brave > Edge > Chromium > Comet; Linux prefers
# Chrome > Chromium > Brave > Edge; Windows prefers Edge (always preinstalled) >
# Chrome > Brave > Comet. The auto-picked profile is saved as "default" for later runs.
export AGENTS_BROWSER_TASK=$(agents browser start --url https://app.example.com)

# Or pin a named profile to a specific browser (chrome, comet, brave, chromium,
# edge, or custom) when you want isolation from "default".
agents browser profiles create work --browser chrome
# `start` writes the resolved name (e.g. `swift-crab-falcon-a3f92b1c`) to stdout
# and human-friendly commentary to stderr, so $(...) capture stays clean.
export AGENTS_BROWSER_TASK=$(agents browser start --profile work --url https://app.example.com)
agents browser refs                  # Get interactive element refs
agents browser click 42              # Click element ref 42
agents browser type 15 --text "hello"  # Type into element ref 15
agents browser screenshot            # Smart resizing, token-efficient
agents browser tabs                  # List tabs open for the current task
agents browser tab focus tab123      # Switch focus to another tab
agents browser done                  # Close task's tabs when finished

# Need to address a different task in the same shell? Override per call:
agents browser screenshot --task other-flow

Why this works where Playwright fails

Playwright and Puppeteer spin up fresh browser instances with automation flags. Sites like LinkedIn, Google, and most finance apps detect and block them immediately.

agents browser launches your existing residential Chrome (or Brave, Edge, Chromium) on your machine via CDP. Same browser fingerprint, same IP, same everything. Sites can't detect automation because you're using the same browser you'd use manually.

Token-efficient automation

The CLI handles the mechanical work so agents don't burn tokens on low-level browser commands. Screenshots are automatically resized without excessive compression — agents process smaller images while keeping the detail they need to make decisions.

Profile isolation

Multiple agents can run browser tasks simultaneously without stepping on each other. Each profile gets its own user data directory, cookies, and state. One agent logs into your work Slack, another into your personal email — no conflicts, no shared state.

agents browser profiles create work-slack --browser chrome
agents browser profiles create personal-gmail --browser chrome
# Two agents, two profiles, no interference

Safe credential access

Attach a secrets bundle to a profile. The agent can log in without credentials in plaintext, and every secret access is recorded in the session log.

agents browser profiles create bank --browser chrome --secrets bank-creds

Electron apps

Control Electron apps (Slack, Discord, VS Code, your own app) with custom binaries:

agents browser profiles create slack \
  --browser custom \
  --binary "/Applications/Slack.app/Contents/MacOS/Slack" \
  --electron

Remote browsers

Connect to browsers running anywhere — local, SSH tunnels, or cloud services:

# Local CDP (discovers WebSocket URL automatically)
agents browser profiles create local-debug \
  --browser chrome \
  --endpoint "http://localhost:9222"

# SSH tunnel to a remote machine
agents browser profiles create staging \
  --browser chrome \
  --endpoint "ssh://[email protected]?port=9222"

# Cloud browser services (BrowserBase, Steel, etc.)
agents browser profiles create cloud \
  --browser chrome \
  --endpoint "wss://connect.browserbase.com?apiKey=..."

Secrets

Platform: agents secrets requires macOS Keychain or Linux libsecret. On Windows (non-WSL), use environment variables or a .env file instead.

# API keys in Keychain, not in .env files.
agents secrets create prod-stripe
agents secrets add prod-stripe STRIPE_SECRET_KEY     # Prompts, stores in Keychain
agents secrets add prod-stripe TEST_CARD --value "4242..."

# Injected at run time. Bundle definitions live in the Keychain, not on disk.
agents run claude "charge a test card" --secrets prod-stripe