- type: ignore on each param line in sessions.py (pyright per-line)
- Remove ActionHandler assert in browser.py (breaks pre-existing tests)
- Ruff format
- Ruff format all skill_cli and test files
- Fix type: get_config_value returns str|int|None, callers cast properly
- Fix type: BrowserWrapper.actions is non-optional (always provided)
- Fix type: config comparison uses 'is' not '=='
- Rewrite test_setup_command for new setup.handle(yes=True) API
- Add None guard in test_cli_lifecycle for state file
cloud connect reads cloud_connect_proxy and cloud_connect_timeout from
~/.browser-use/config.json. Recording always enabled via enableRecording
default on CreateBrowserRequest. No CLI flags — edit config for custom
settings, use cloud v2 REST for full control.
cloud connect now works with no flags. On first use, creates a
"Browser Use CLI" profile via the Cloud API and saves the ID to
config.json. Subsequent connects reuse it (validates on each call,
recreates if deleted).
Removed --timeout, --proxy-country, --profile-id flags and their
plumbing through daemon/sessions. Power users who need custom browser
settings use cloud v2 POST /browsers directly.
Subclass BrowserSession as CLIBrowserSession that calls connect()
directly instead of start(). Skips all 13 watchdogs and event bus
handler registration. Actions execute via ActionHandler which calls
DefaultActionWatchdog methods directly and DomService for DOM snapshots.
- CLIBrowserSession.start() → connect() only (CDP + SessionManager)
- CLIBrowserSession.stop() → close websocket directly (no BrowserStopEvent)
- CLIBrowserSession.kill() → Browser.close + disconnect
- ActionHandler wraps DefaultActionWatchdog for click/type/scroll/keys/etc
- DomService called directly for state (no DOMWatchdog)
- Monkey-patches _enable_page_monitoring to no-op after initial connect
- Disables auto-reconnect (_intentional_stop = True)
- Falls back to event bus path if ActionHandler is not available
If list_chrome_profiles() returns empty (permissions, corrupt Local State,
first-run Chrome), skip resolution and use the profile value as-is instead
of always raising RuntimeError.
--profile now accepts both directory names ("Default", "Profile 1") and
display names ("Person 1", "Work") with case-insensitive matching. On
unknown profile, lists all available profiles with both names.
Replace the multi-session server (server.py, SessionRegistry, portalocker locking,
PID files, orphan detection) with a minimal daemon (daemon.py) that holds one
BrowserSession in memory. Socket file existence = alive. Auto-exits when browser
dies via CDP watchdog.
-2277 lines, +142 lines across 20 files.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove all cloud API paths from the CLI while leaving core library
cloud support (BrowserSession(use_cloud=True), browser/cloud/) untouched.
Deleted: api_key.py, cloud_task.py, cloud_session.py
Removed: --browser remote, cloud-only run flags, task/session subcommands,
cloud profile ops (create/update/delete/sync), remote mode validation
Kept: tunnel (just Cloudflare), all local commands, install_config.py
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Rename tunnel_manager.py to tunnel.py
- Remove dead code: commands/tunnel.py (session-scoped implementation never reached)
- Remove TunnelInfo dataclass and tunnels field from sessions.py
- Remove tunnel routing from server.py (unreachable code path)
- Update imports in main.py, doctor.py, setup.py, and tests
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, `browser-use tunnel 3000` would start a session server with
the default browser mode (chromium), which poisoned subsequent
`--browser remote` commands with a mode mismatch error.
Now tunnel commands are handled directly in main.py without starting a
browser session:
npm run dev &
browser-use tunnel 3000 # No session created
browser-use --browser remote open <tunnel-url> # Works!
Changes:
- Move tunnel logic to standalone functions in tunnel_manager.py
- Handle tunnel commands in main.py before ensure_server()
- Tunnels persist across browser-use close (independent lifecycle)
- Add `browser-use tunnel stop --all` command
Breaking behavior change:
- `browser-use close` no longer stops tunnels
- Use `browser-use tunnel stop <port>` or `tunnel stop --all` explicitly
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- New `tunnel` command: expose localhost ports via Cloudflare quick tunnels
(`bu tunnel 3000` → trycloudflare.com URL, idempotent, auto-cleanup on session close)
- New `skills/remote-browser/SKILL.md`: guides sandboxed agents through
cloud browser + tunnel workflow
- TunnelInfo dataclass on SessionInfo for tunnel lifecycle management
- Tunnel dispatch in both SessionServer and CLI arg parser
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add cloud profile commands: list, create, get, update, delete
- Add profile sync command to sync local Chrome cookies to cloud
- Add profile cookies command to list cookies by domain
- Add cookies export/import commands for bulk transfer
- Optimize cookie import using Network.setCookies (bulk API)
- Real browser now runs headless by default (use --headed for visible)
- Support --domain flag for syncing specific domain cookies only
- Update SKILL.md with cloud profile workflow documentation
- Add `profile list-local` command to discover local Chrome profiles
- Fix real browser mode to properly pass `profile_directory` to BrowserSession
- Document profile management workflow in SKILL.md
This adds support for connecting to an existing browser instance via
Chrome DevTools Protocol (CDP) URL in the skill_cli commands.
## Why
The current skill_cli only supports three browser modes:
- chromium: Launches a new Playwright-managed Chromium
- real: Launches users Chrome with profile
- remote: Uses Browser-Use Cloud
However, many use cases require connecting to an already-running browser:
- Remote browser automation via SSH tunnels
- Connecting to browsers in Docker containers
- Reusing authenticated browser sessions
- Integration with Claude Code on remote servers
The BrowserSession class already supports cdp_url, but it was not
exposed through the skill_cli. The TUI mode has this option, but the
simple CLI commands did not.
## Changes
- main.py: Added --cdp-url argument and pass-through to server
- server.py: Accept and store cdp_url, pass to session registry
- sessions.py: Handle cdp_url in session creation (takes precedence)
## Usage
browser-use --cdp-url http://localhost:9222 open https://example.com
browser-use --cdp-url http://localhost:9222 state
browser-use --cdp-url http://localhost:9222 click 5
## Testing
Tested with Chrome remote debugging over SSH tunnel - successfully
controlled a local macOS Chrome browser from a remote Linux server.
Vibe coded with Claude Opus 4.5
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>