When ping fails but daemon is alive, return instead of trying to spawn
a second daemon. The old daemon holds the socket so the new one can't
bind, causing silent config mismatch.
On Windows, os.kill(pid, 0) calls TerminateProcess which kills the process
instead of checking liveness. Use ctypes OpenProcess for Windows, keeping
os.kill(pid, 0) for Unix. Affects list_sessions(), tunnel PID checks, and
_handle_sessions().
- Narrow cloud --help intercept to only fire when --help is immediately
after 'cloud', so 'cloud v2 --help' still shows OpenAPI endpoints
- Guard signal handler against concurrent shutdown tasks on repeated signals
- Route error response bodies to stderr in cloud REST commands
- Replace stale port 49200 in README Windows troubleshooting
- Intercept `cloud --help` early so it routes to _print_cloud_usage()
instead of argparse's generic stub
- Remove permissive `or 'cloud'` fallback in epilog test assertion
- Delete no-op regex test that didn't verify actual code
- Tighten default socket path assertion to check 'default.sock'
Wrap socket creation + connect in try/finally across 5 locations to
ensure sockets are closed when connect() raises. Previously, failed
connections leaked file descriptors until GC ran.
- Add `browser-use upload <index> <path>` command for uploading files to
file input elements via the CLI
- Extract find_file_input_near_element from nested closures in tools/service.py
to a reusable method on BrowserSession, deduplicating two copies
- Add BrowserWrapper.upload() for the Python REPL
- Resolve file paths to absolute on the client side before sending to daemon
- Update SKILL.md files and README with upload command docs
Use nargs=REMAINDER to capture profile-use args, matching the cloud
subcommand pattern. Without this, argparse rejects unknown args like
'browser-use profile update'.
Unify all CLI-managed files under ~/.browser-use/ (config, sockets, PIDs,
binaries, tunnels) instead of scattering across ~/.config/browser-use/ and
~/.browser-use/run/. Add profile-use Go binary as managed subcommand via
browser-use profile, with auto-download fallback and install.sh integration.
Wire cloudflared and profile-use availability checks into browser-use doctor.
Adds `--connect` to auto-discover running Chrome instances via DevToolsActivePort
files and well-known port probing, eliminating manual CDP URL construction. Fixes
daemon process hanging on `close` when connected to external browsers (--connect,
--cdp-url, cloud) by calling stop() (disconnect) instead of kill() (terminate).
The `run` command pulled in heavy SDK dependencies (openai, anthropic,
google), had a bug (await on sync get_llm), and is superseded by
`browser-use cloud` for agent execution. CLI is now purely a browser
automation interface.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Login/logout with API key persistence, versioned REST calls (v2/v3),
task polling, and OpenAPI-driven help. Stdlib only, no daemon needed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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>
The session server had a race condition where concurrent CLI calls could
spawn multiple server processes. The old server would be orphaned when
the new one overwrote the PID file and deleted its socket.
Changes:
- Add flock-based locking using portalocker (already a dependency)
- Server acquires exclusive lock before writing PID file
- CLI checks both is_server_running() AND is_session_locked()
- Add kill_orphaned_server() to clean up servers with PID but no lock
- Increase socket timeout from 0.1s to 0.5s for reliability
- cleanup_session_files() now removes .lock and .meta files
Co-Authored-By: Claude Opus 4.5 <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>
- Forward all cloud-only flags in _handle_remote_run_with_wait
Previously only forwarded 6 params; now includes session_id, vision,
metadata, secrets, allowed_domains, skill_ids, structured_output,
judge, judge_ground_truth, plus session creation for profile/proxy
- Use asyncio.to_thread for blocking SDK call in poll_until_complete
Prevents client.tasks.get_task from blocking the event loop while
polling for task completion
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace custom HTTP client with browser-use-sdk for tasks and sessions,
completing the SDK migration started in 8a992229.
## SDK Migration
- Add `sdk.py` with singleton client factory (`get_sdk_client()`)
- Rewrite `cloud_task.py` to use SDK (-300 lines)
- All functions return typed SDK models (TaskView, SessionView, etc.)
- Add `_filter_none()` to omit None values (SDK sends null, API rejects)
## No Client-Side Defaults
- Remove hardcoded defaults from CLI (max_steps, proxy_country, etc.)
- Let API use its own defaults (documented at docs.cloud.browser-use.com)
- Only pass values user explicitly sets
## New CLI Features
- `session create` - create session without task
- `session share <id>` - create/delete public share URLs
- `task list --session <id>` - filter tasks by session
- New task flags: --metadata, --secret, --allowed-domain, --skill-id,
--structured-output, --judge, --judge-ground-truth, --start-url
## Async by Default
- Change `--no-wait` to `--wait` (flip default behavior)
- Tasks return immediately with task_id by default
- Use `--wait` to block until completion
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace raw urllib HTTP calls with the official browser-use-sdk client
for all cloud profile API operations. This provides:
- Type-safe responses (ProfileView, ProfileListResponse)
- Cleaner error handling via SDK exceptions
- Consistent SDK usage pattern (matches skills/service.py)
- Removes 40 lines of manual HTTP/auth handling from main.py
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Use CREATE_NO_WINDOW instead of DETACHED_PROCESS to prevent
a blank console window from appearing when the server starts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Use ctypes.OpenProcess on Windows for process existence check
(os.kill raises WinError 87 or SystemError on Windows)
- Use 127.0.0.1 instead of localhost to avoid IPv6 binding issues
- Add reuse_address=True to asyncio.start_server for TCP port reuse
Fixes issues reported in:
- #3912 (os.kill fails on Windows)
- #3918 (WinError 87 in is_server_running)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously doctor said "See details above" but never printed the actual
check results. Now prints each check with status icon and details.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The setup command parser was changed to use --mode but the handler was
still passing args.profile and reading result["profile"]. Fixed both
to use mode consistently.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Default task status shows only latest step (token efficient for agents)
- Add --compact/-c flag to show all steps with reasoning
- Add --verbose/-v flag to show all steps with URLs + actions
- Add --last/-n, --reverse/-r, --step/-s flags for navigating long tasks
- Display duration for tasks (e.g., "18s", "5m 13s") and sessions
- Format proxy cost to 2 decimal places in session output
- Update SKILL.md docs with recommended monitoring workflow
- Spawn cloudflared as daemon with start_new_session=True
- Track tunnels via PID files in ~/.browser-use/tunnels/ instead of memory
- Properly add --all flag to tunnel argparser (fixes unrecognized args error)
- Clean up stale PID files when tunnel process has died
This fixes the issue where cloudflared would become a zombie/defunct process
immediately after browser-use tunnel returned, causing 530 errors.
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>
When a session is started without --browser remote and a subsequent command
uses --browser remote, the CLI now errors with guidance instead of silently
using the local browser (which loses cloud features like live_url).
Code changes:
- Add session metadata file to track browser_mode per session
- Error only when remote requested but session is local
- Allow local-on-remote (user gets more features than requested)
- Clean up metadata on session close
SKILL.md improvements:
- Clarify that --browser remote only needed on FIRST command
- Add table showing session modes
- Add "What happens if you forget" section with error example
- Add troubleshooting entry for mode mismatch error
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a session is started with --browser chromium and a subsequent command
uses --browser remote (or vice versa), the CLI now detects the mismatch and
provides actionable error guidance instead of silently using the wrong mode.
Changes:
- Add get_session_metadata_path() to track session config in temp files
- Write browser_mode, headed, profile to metadata on server start
- Check metadata in ensure_server() and error if modes don't match
- Clean up metadata file on session close
Example error:
Error: Session 'default' is running with --browser chromium,
but --browser remote was requested.
Options:
1. Use existing browser: browser-use --browser chromium <command>
2. Use different session: browser-use --browser remote --session other <command>
3. Close existing session: browser-use close
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>
- Remove invalid cdp_url parameter from create_browser_session calls
- Replace deleted GetCookiesEvent with direct _cdp_get_cookies() call
- Add type assertion for cookies_file after error check
- Use unique variable names for CDP results to avoid type conflicts
- Add type ignores for CDP typed return values used as dicts
PR #3911 changed the browser-use entry point to skill_cli/main.py but
didn't port the early command interception for install, init, --template,
and --mcp. This broke:
- `browser-use install` (installs Chromium via playwright)
- `browser-use init` (generates template files)
- `browser-use --template` (direct template generation)
- `browser-use --mcp` (MCP server mode)
This fix adds early command interception to skill_cli/main.py, matching
the behavior from browser_use/cli.py. Commands are handled before argparse
to avoid loading heavy dependencies for simple setup tasks.
Also adds tests to prevent regression.
- 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
Adds information retrieval commands to the browser-use CLI:
- get title: page title
- get html: full page or element HTML via selector
- get text: text content of element by index
- get value: input/textarea value by index
- get attributes: all attributes of element by index
- get bbox: bounding box (x, y, width, height) of element
Adds mouse interaction commands to the browser-use CLI:
- hover: move mouse over element (triggers CSS :hover effects)
- dblclick: double-click element
- rightclick: right-click element (context menu)