提交

提交图

245 次代码提交

作者 SHA1 备注 提交日期
Alezander9 fcd9fbae12 add VOUCHED.td seeded with two recent contributors 2026-05-01 11:46:16 -07:00
Alexander Yue ff5eea44fc Merge pull request #272 from browser-use/docs/issue-templates
docs: add issue templates; route questions to Discussions
2026-05-01 11:42:45 -07:00
Alezander9 24fc314065 add issue templates and route questions to Discussions
bug-report.yml: 4 required fields plus a 4-box preflight (searched issues, ran --doctor, read install.md, this is a bug not a question/FR/cloud issue). feature-request.yml: 3 required fields plus a 2-box preflight. config.yml disables blank issues and links to Discussions Q&A and install.md.
2026-05-01 11:38:27 -07:00
Alexander Yue faac614bc1 Merge pull request #269 from browser-use/docs/add-agents-md
docs: add AGENTS.md
2026-05-01 11:36:06 -07:00
Alezander9 b124b56c42 list agent-workspace contents; clarify SKILL.md scope 2026-04-30 16:16:29 -07:00
Alezander9 f3a011b988 docs: add AGENTS.md with repo orientation for coding agents 2026-04-30 16:13:51 -07:00
Alexander Yue 013097aaa7 Merge pull request #265 from molesza/fix/chrome147-default-profile-cdp-fallback
fix(daemon): fall back to DevToolsActivePort ws path when /json/version 404s
2026-04-30 16:13:40 -07:00
Alezander9 fb2571ab8e inline 404 fallback; drop saw_http_404 flag
Same behavior matrix: HTTPError 404 with a ws_path returns the file's ws URL immediately; 404 without ws_path or any other error keeps polling until the 30s deadline. Removes the flag, the break, the post-loop check, and shrinks the explanatory comment.
2026-04-30 16:10:52 -07:00
Alexander Yue 9cddcc1f59 Merge pull request #266 from shaunandrewjackson1977/fix/headless-cloud-auto-bootstrap
fix: auto-bootstrap cloud daemon on headless servers when BROWSER_USE_API_KEY is set
2026-04-30 15:45:20 -07:00
Alezander9 49355ba7a8 probe /json/version instead of bare TCP; trim redundant gate tests
Cubic flagged that the original socket.create_connection probe matches any process on 9222/9223, not just Chrome. Mirror daemon.py's fallback by hitting /json/version, so a stale or unrelated listener does not skip the cloud bootstrap.

Drop the three boolean-table tests that mocked every collaborator and re-asserted the literal if-condition. Add a focused test for _local_chrome_listening that covers the false-positive case directly.
2026-04-30 15:34:35 -07:00
Shaun Jackson 79e1ce9ff6 fix: auto-bootstrap cloud daemon on headless servers when BROWSER_USE_API_KEY is set
On headless servers (VPS, Docker) with no local Chrome, ensure_daemon() fires
before any user script runs and raises immediately — start_remote_daemon() can
never be reached from within a -c script.

Add a pre-check in main(): if no daemon is alive, Chrome is not listening on
known debugging ports (9222/9223), and BROWSER_USE_API_KEY is set, auto-
provision a Browser Use cloud browser before falling through to ensure_daemon().

_local_chrome_listening() probes ports 9222/9223 with a 0.3s timeout rather
than relying on _is_local_chrome_mode(), which only checks for absence of
BU_CDP_WS and would incorrectly trigger cloud bootstrap on a local machine
where Chrome is running but BROWSER_USE_API_KEY is also set (e.g. for profile
sync).

Fixes the behaviour reported in issues #181 and #183.

Tested on a headless Hostinger VPS running hermes-agent in Docker — browser-
harness -c '...' now works without any manual daemon setup when BROWSER_USE_API_KEY
is set.
2026-04-30 22:27:18 +10:00
molesza 5dfa89fa66 fix(daemon): fall back to DevToolsActivePort ws path when /json/version 404s
Chrome 147+ silently disables /json/* HTTP discovery when remote debugging
runs on the default user-data-dir (IsUsingDefaultDataDirectory). The websocket
itself still works and DevToolsActivePort still holds the live ws path, but
get_ws_url() polls /json/version for 30s and dies with a misleading
"DevTools is not live yet" error.

PR #260 deliberately stopped trusting the path stored in DevToolsActivePort
because a stale port file (left behind after switching --user-data-dir on the
same port) had a dead UUID. That fix is correct, but it never falls back to
the file's UUID even when Chrome just wrote the file in the current run.

Read both port and ws path. Try /json/version first (preserves #260's
stale-UUID behavior). On HTTP 404 specifically — which is distinct from
connection-refused/timeout meaning "Chrome still starting" — fall back to
ws://127.0.0.1:{port}{ws_path} from the file. The file's UUID is fresh
because Chrome rewrites it on every launch, and the only persistent reason
/json/version 404s on a live port is the default-profile lockdown. If the WS
upgrade then 404s (true stale UUID), the existing CDP handshake error
surfaces unchanged.

Closes #264.
2026-04-30 12:55:10 +02:00
Alexander Yue d1209ab99c Merge pull request #261 from browser-use/fix/shopify-admin-skills-location
fix: move shopify-admin skills to agent-workspace/domain-skills/
2026-04-30 00:04:10 -07:00
alex e1eabc4584 fix: move shopify-admin skills to agent-workspace/domain-skills/
PR #247 added these under domain-skills/ at the repo root, but the
canonical location for domain skills is agent-workspace/domain-skills/
(referenced in README.md, SKILL.md, and helpers.py).
2026-04-29 23:39:22 -07:00
Alexander Yue 660827d7d4 Merge pull request #260 from Alezander9/fix/stale-devtools-active-port
fix(daemon): ignore stale DevToolsActivePort path; resolve WS via /json/version
2026-04-29 23:23:38 -07:00
Alezander9 9a87de27f4 fix(daemon): resolve WS via /json/version to avoid stale DevToolsActivePort path
Chrome leaves DevToolsActivePort behind across runs. If the user previously
launched Chrome with one --user-data-dir on a debug port, then later launches
Chrome with a different --user-data-dir on the same port, the file in the
first profile keeps a stale browser UUID. The TCP probe to that port
succeeds against the new Chrome, but the WS upgrade returns HTTP 404
because the cached UUID is dead -- daemon dies with
'CDP WS handshake failed: HTTP 404'.

Resolve the WS URL via /json/version on the port from DevToolsActivePort
instead of trusting the path stored alongside it. /json/version is
authoritative for whatever Chrome is currently bound to that port, so
stale paths no longer matter. The 9222/9223 fallback below already used
this approach -- now both paths agree.

Reproduced on Windows 11 with one Chrome running on port 9222 with a custom
--user-data-dir while a stale DevToolsActivePort sat in
~/AppData/Local/Google/Chrome/User Data from a prior debug session.
2026-04-29 23:21:38 -07:00
Alexander Yue c8f09ebf67 Merge pull request #256 from browser-use/docs/install-profile-sync-c-flag
docs: replace remaining heredoc examples with -c flag
2026-04-29 13:59:50 -07:00
Alezander9 db41106662 docs: replace remaining heredoc examples with -c flag
PR #229 (src layout refactor) updated SKILL.md and run.py to the -c form
when the CLI dropped stdin support, but missed install.md (steps 2 and 7)
and interaction-skills/profile-sync.md. Sync them up.

Picks up the still-relevant hunks from #215 (closes #215, refs #213).

Co-authored-by: Andres Gonzalez <62394570+FVTVLIX@users.noreply.github.com>
2026-04-29 13:55:44 -07:00
Alexander Yue 7ce5ba7ca4 Merge pull request #255 from browser-use/docs/readme-operator-framing-rebase
docs: lead README with first-buyer job (rebased from #170)
2026-04-29 13:53:11 -07:00
Alexander Yue c95a512891 Merge pull request #254 from browser-use/fix/connection-status-error-on-cdp-failure
fix(daemon): report error on stale CDP in connection_status
2026-04-29 13:51:13 -07:00
Matt Van Horn 9e609f2674 docs: lead README with first-buyer job
Rebased from #170 (authored by @mvanhorn) onto current main.
The original branch was based on a stale README; only the two
intentional lines from that PR are reapplied here.
2026-04-29 13:51:12 -07:00
Alezander9 e52992ad80 fix(daemon): report cdp_disconnected on stale CDP probe in connection_status
When the browser dies but the daemon process keeps running, target_id and session stay cached on the Bridge. Pre-fix, connection_status swallowed the Target.getTargetInfo failure and returned the cached IDs with page=null, so admin counted the daemon as healthy. Now it returns {error: cdp_disconnected} and admin's existing error-check skips it. Also returns {error: not_attached} when target_id is unset.
2026-04-29 13:45:16 -07:00
FuLin 1c5a5681bb domain-skills: add Xiaohongshu scraping skill (web search, sorting, and note-opening) (#246)
* Add Xiaohongshu search and note-opening skill

* Clarify Xiaohongshu search URL encoding
2026-04-29 11:46:32 -07:00
playjing 2a478a8ff9 domain-skills/shopify-admin: KB FAQs, embedded apps, Polaris inputs (#247)
Three patterns discovered while populating the Shopify Knowledge Base App
for JING (silent training football brand). Each pattern saved 30+ minutes
of rediscovery; documenting so future agents on any Shopify store benefit.

- README.md: when to use the harness for Shopify admin vs Storefront API
  / Admin API / Shopify CLI; auth notes; Polaris React vs Web Components
  detection.

- embedded-apps.md: every Shopify app surfaces in an iframe at
  *-app.shopify.prod.shopifyapps.com. Use iframe_target() and pass
  target_id to js() calls. Known iframe slugs table (extend as
  discovered).

- polaris-inputs.md: Polaris React text inputs reject the standard
  React-friendly synthetic value setter pattern — fields fill but Save
  button stays disabled. Working pattern is .focus() via JS + CDP-native
  keystrokes via type_text(). Includes full add-FAQ implementation +
  notes on Polaris's web-component migration (polaris-react archived
  Jan 2026).

- knowledge-base.md: canonical automation for the Shopify Knowledge
  Base App (Winter '26 Edition). FAQ-pair flow, batch loop pattern,
  /pairs/<id> URL signal for save success, brand-voice guidance,
  query-log review cadence. App is currently English-only with no
  public API — browser automation is the only path until Shopify
  exposes endpoints.

Tested with 19 successful FAQ saves on the JING store on 2026-04-29.

Co-authored-by: Claude (JING build agent) <build@playjing.local>
2026-04-29 11:31:14 -07:00
BitToby d2410828ec Fix remote browser cleanup when daemon startup fails (#251)
* Fix remote startup cleanup

* Fix cloud browser cleanup on startup interruption
2026-04-29 11:09:30 -07:00
Alexander Yue 997ee457b4 Merge pull request #245 from browser-use/add-comet-arc-profiles
daemon: discover DevToolsActivePort in Comet and Arc profiles on macOS
2026-04-28 22:46:07 -07:00
Alezander9 e4a4478a10 daemon: discover DevToolsActivePort in Comet and Arc profiles on macOS 2026-04-28 22:43:06 -07:00
Alexander Yue 2e0f7ec3a8 Merge pull request #241 from cryptoshrine/fix/windows-os-kill-systemerror
fix(admin): catch SystemError raised by os.kill on Windows
2026-04-28 22:34:29 -07:00
Alexander Yue b1ec1346a2 Merge pull request #244 from browser-use/fix/bh-tmp-dir-short-filenames
fix(_ipc): drop bu-<NAME> filename prefix when BH_TMP_DIR is set
2026-04-28 22:32:57 -07:00
Alezander9 51d62fbbe7 fix(_ipc): drop bu-<NAME> filename prefix when BH_TMP_DIR is set
When BH_TMP_DIR is set, the caller owns the directory and is expected to
give each daemon its own — so the bu-<NAME> filename prefix is redundant.
Dropping it cuts ~30 chars off the AF_UNIX path on POSIX, which matters
because sun_path is 104 bytes on macOS / 108 on Linux and a long BU_NAME
(e.g. an opencode-style session id) can blow past it.

Concretely the failing path on macOS for a 30-char session id under
~/.local/share/bcode/sessions/<sessionID>/bu-<sessionID>.sock was 117
bytes; with this change it becomes ~83 bytes.

When BH_TMP_DIR is unset, _TMP is the shared default (/tmp on POSIX,
gettempdir() on Windows) and the bu-<NAME> prefix is kept to disambiguate
multiple daemons sharing the dir. Backward compatible by default.

admin._daemon_endpoint_names: when BH_TMP_DIR is set, the dir is per-daemon
by construction, so glob discovery doesn't apply — just check whether our
local endpoint exists. Without BH_TMP_DIR, fall back to the existing
shared-dir glob.

Validation (_check on BU_NAME) still runs in both modes to catch garbage
names early.
2026-04-28 22:30:57 -07:00
Alexander Yue 2125cea3a5 Merge pull request #243 from browser-use/fix/ipc-tmp-dir-mkdir
fix(_ipc): mkdir -p _TMP at module load
2026-04-28 21:25:36 -07:00
Alezander9 225abcc9d1 fix(_ipc): mkdir -p _TMP at module load so BH_TMP_DIR can point at a non-existent dir
Without this, a caller passing BH_TMP_DIR=<custom dir> to a directory that
doesn't exist yet causes the first write (sock/port/pid/log/screenshot) to
fail with FileNotFoundError. Default _TMP (/tmp on POSIX, gettempdir() on
Windows) always exists, so this is latent today; it bites the per-session
scratch-dir use case browsercode is about to introduce.

Single root cause -> single fix: cover screenshots, sock, port, pid, and
log paths uniformly.
2026-04-28 21:21:05 -07:00
Alexander Yue 04f7716630 Merge pull request #242 from browser-use/claude/slack-session-sdKmR
Rename skill command from /browser-harness to /browser
2026-04-28 15:48:45 -07:00
Alexander Yue 036bfaf69c Merge pull request #240 from browser-use/fix/ensure-daemon-windows-probe
fix(admin): route ensure_daemon CDP probe through ipc.connect (Windows)
2026-04-28 15:48:30 -07:00
Alezander9 6dc41c1a5b fix(_ipc): suppress empty python.exe console window on Windows daemon spawn
DETACHED_PROCESS overrides CREATE_NO_WINDOW per Win32 docs, so combining
them caused Windows to allocate a fresh console for the daemon. Closing
that window killed the daemon and forced Chrome to re-prompt for remote
debugging permission. Drop DETACHED_PROCESS, keep CREATE_NEW_PROCESS_GROUP
for terminal-close survival.
2026-04-28 15:32:35 -07:00
Alezander9 82ef2a13ab feat(_ipc): BH_TMP_DIR overrides sock/port/pid/log + screenshot dir
Lets callers (e.g. browsercode per-session scratch) redirect all harness
file output via one env var. Default behavior unchanged when unset:
/tmp on POSIX, gettempdir() on Windows.

helpers.capture_screenshot and the debug-click overlay now route through
ipc._TMP so the same knob covers screenshots.
2026-04-28 15:21:48 -07:00
Claude ee1ff81eac Rename skill command from /browser-harness to /browser
Shortens the invocation to a cleaner /browser command.

https://claude.ai/code/session_014BWe8AkViicHviYPP843t5
2026-04-28 22:19:53 +00:00
cryptoshrine 06aad12d91 fix(admin): catch SystemError raised by os.kill on Windows
On Windows, `os.kill(pid, 0)` does not behave like its POSIX
counterpart. Instead of returning silently when the process
exists or raising ProcessLookupError when it doesn't, CPython
on Windows raises:

    SystemError: <built-in function kill> returned a result
                 with an exception set

This happens because the underlying Win32 TerminateProcess API
does not accept signal 0 as an "is alive?" probe — Python's C
implementation hits an internal error path that doesn't set a
proper exception, and the interpreter surfaces SystemError.

`restart_daemon()` already catches `(ProcessLookupError, OSError)`
around both `os.kill(pid, 0)` and `os.kill(pid, signal.SIGTERM)`,
but SystemError isn't a subclass of either, so the harness crashes
on every second invocation on Windows: the daemon's stale pid file
points at a no-longer-running pid, the probe raises SystemError,
and the whole `browser-harness -c '...'` call dies with a stack
trace.

Repro on Windows 11 (Python 3.12, browser-harness 0.1.0):

    browser-harness --reload      # ok
    browser-harness -c 'print(page_info())'   # ok
    browser-harness -c 'print(page_info())'   # CRASH

Fix: add SystemError to the existing except clauses in
restart_daemon(). One-word change in two places, matches the
intent of the existing handlers (treat any "couldn't probe/signal
the pid" failure as "process is gone, move on").
2026-04-28 22:56:48 +01:00
Alezander9 1dd4f60252 fix(admin): route ensure_daemon CDP probe through ipc.connect (Windows)
The stale-daemon probe in ensure_daemon used raw socket.AF_UNIX, which:
1. Doesn't exist on uv-bundled Python on Windows (AttributeError).
2. Would point at a TCP display string '127.0.0.1:<port>', not a socket
   path, even if AF_UNIX existed.

Either way the probe always raised, was swallowed by 'except Exception',
and fell through to restart_daemon — killing and respawning the daemon
on every warm call. Symptom is most visible on Windows where the warm
path is the common case.

Fix: use ipc.connect(name) which already does the right thing per
platform (AF_UNIX on POSIX, TCP loopback on Windows). Same call
daemon_alive and restart_daemon already use.

Also drop the now-unused _paths() helper; restart_daemon only needed
the pid_path half, inline that.
2026-04-28 13:16:28 -07:00
Vlad Rafeev ac71315eda fix: prevent chrome://inspect tab flooding during setup (#232)
When remote-debugging is not enabled, `run_setup` opens chrome://inspect
once, then retries `ensure_daemon` in a loop. But `ensure_daemon` itself
also calls `_open_chrome_inspect()` on failure — opening a new tab every
~7 seconds and flooding the browser.

Add `_open_inspect` parameter to `ensure_daemon` so the retry loop in
`run_setup` can suppress redundant tab opens after the first one.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Saurav Panda <sgp65@cornell.edu>
2026-04-28 12:01:13 -07:00
Sarath S Menon fefca43ab5 feat(doctor): show live browser connections and attached pages in run_doctor (#234)
Add browser_connections() / active_browser_connections() to admin, which probe
each daemon socket via a new connection_status meta message. The daemon tracks
target_id (set on attach and on set_session) and returns the live page title/URL
via Target.getTargetInfo. switch_tab now forwards target_id in set_session so the
daemon stays in sync after tab switches. run_doctor shows the count, each daemon
name, and the truncated active-page title and URL.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 17:42:47 +05:30
Sarath S Menon 64dafa2805 refactor(js): proper return-statement parsing, unserializable value decoding, unified eval helpers (#231)
Replace naive `"return " in expression` check with a character-level parser that
ignores strings, line comments, and block comments. Add `_decode_unserializable_js_value`
to handle NaN, ±Infinity, -0, and BigInt. Extract `_runtime_value` and
`_runtime_evaluate` to unify error handling across `js()` and `page_info()`.
Wrap Runtime.evaluate TimeoutErrors in RuntimeError with expression context.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:33:28 +05:30
Sarath S Menon 5a77ea5525 fix(js): raise RuntimeError on JS evaluation errors instead of returning None (#230)
Previously js() silently returned None when Chrome reported a syntax or
runtime error. Now it raises RuntimeError with the error description,
line/column location, and a snippet of the failing expression.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 16:04:33 +05:30
Sarath S Menon fb1a51dd9b refactor: move to src layout, agent-workspace, and fix SKILL.md invocation format (#229)
* refactor(tests): reorganize into tests/unit and tests/integration

Moves all root-level test_*.py files into a structured tests/ directory:
- tests/unit/ — admin, helpers (was test_screenshot), run
- tests/integration/ — js expression tests
- tests/conftest.py — shared fake_png pytest fixture, eliminating duplication

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* refactor: move to src layout, agent-workspace, and fix SKILL.md invocation format

- Move package to src/browser_harness/ and domain-skills/interaction-skills to agent-workspace/
- Fix all browser-harness <<'PY' heredoc examples in SKILL.md and run.py HELP string to use the correct -c '...' flag format (heredoc was never supported by the CLI)
- Update SKILL.md path references from domain-skills/ to agent-workspace/domain-skills/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 15:38:11 +05:30
Sarath S Menon cae52ce916 refactor(tests): reorganize into tests/unit and tests/integration (#228)
Moves all root-level test_*.py files into a structured tests/ directory:
- tests/unit/ — admin, helpers (was test_screenshot), run
- tests/integration/ — js expression tests
- tests/conftest.py — shared fake_png pytest fixture, eliminating duplication

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-28 14:42:52 +05:30
Alexander Yue f5f0564757 Merge pull request #225 from browser-use/fix/windows-ipc
Windows support: route IPC through ipc.py (TCP on Windows, AF_UNIX on POSIX)
2026-04-28 01:04:34 -07:00
Alezander9 51ff305bfa Use /tmp on POSIX to stay under AF_UNIX sun_path limit
tempfile.gettempdir() on macOS returns /var/folders/xx/yy.../T/ (~49 chars).
Combined with bu-{64-char-name}.sock that exceeds the 104-byte sun_path
limit on macOS (108 on Linux), causing daemon startup to fail.

Pre-PR upstream hardcoded /tmp; this restores that for POSIX. Windows is
unaffected (uses TCP, not AF_UNIX).
2026-04-28 00:24:18 -07:00
Matt Van Horn a5c973f333 fix(daemon): fire-and-forget mark-title eval so load events don't stall (#171)
* fix(daemon): fire-and-forget mark-title eval so load events don't stall

* fix(daemon): bound mark-title eval to 2s so stalled V8 can't pile up tasks

Fire-and-forget kept the perf win, but dropped the 2s upper bound. On a
discarded renderer or hard-hung V8, the Runtime.evaluate task would
never resolve, leaking one task per navigation. Restore the timeout
inside the _silent wrapper.

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
Co-authored-by: Saurav Panda <sgp65@cornell.edu>
2026-04-27 18:44:19 -07:00
Alezander9 b05be93d60 Slim ipc.py and rename to _ipc.py to signal internal
Cut ipc.py from 127 to 68 lines (-46%) by removing restated docstrings and
keeping only load-bearing inline comments (path-traversal guard, uv-Python
AF_UNIX gating, Windows .port-file role). Same logic, same call sites.

Rename ipc -> _ipc per Python convention for internal modules. The IPC
plumbing is only called by daemon/admin/helpers; agents reading helpers.py
should not be pulled into transport details. Callers do 'import _ipc as ipc'
so internal ipc.foo references stay unchanged.
2026-04-27 18:01:11 -07:00
Alezander9 71cf3a87a0 Merge remote-tracking branch 'origin/main' into fix/windows-ipc
# Conflicts:
#	SKILL.md
#	admin.py
#	helpers.py
2026-04-27 17:41:08 -07:00