文件历史

63 次代码提交

作者 SHA1 备注 提交日期
Laith Weinberger 15f0e2a316 don't use BH too much, and don't retry chrome perm in loop 2026-07-21 13:26:48 -07:00
Gregor Žunič 3220402522 Fold video workflow into browser harness 2026-07-16 19:33:05 -07:00
Gregor Žunič 2cecabb27f Simplify and harden video workflow 2026-07-16 18:21:13 -07:00
Gregor Žunič 0f78a99bc5 Make recording opt-in and automate video production 2026-07-16 17:08:38 -07:00
Gregor Žunič ab9a9b440b Add secret redaction: scrub credential URLs in trace, pixelate on-screen regions
Recorder always strips credential-bearing query/fragment params (OAuth
codes, tokens, api keys) from URLs before they land in events.jsonl.
The video template takes redact: {"frame.jpg": [{x,y,w,h}]} and
pixelates those page-px regions wherever the frame is drawn, tracking
zooms and after-swaps. Auto-record is back on by default (BH_RECORD=0
opts out); making a video is a separate, discretionary step.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 10:40:41 -07:00
Gregor Žunič c5de1e5417 Trim skill docs: dedupe gotchas, drop formula internals
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 10:00:27 -07:00
Gregor Žunič d724466c30 Auto-record via BH_RECORD=1, easy opt-in via start_recording()
Recording stays off by default; the user asking ("record this") maps to
start_recording(). Setting BH_RECORD=1 auto-records every session into
session-<timestamp> folders that roll over after BH_RECORD_IDLE seconds
(default 180) of no actions, so unrelated tasks never merge into one
recording. Explicit recordings never roll over.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-15 09:55:39 -07:00
Gregor Žunič e88f4e327a Add built-in session recording + video generation
Record a browser session as a folder of per-action screenshots + an
events.jsonl trace (start_recording/stop_recording helpers, marker file
spans CLI invocations, no daemon changes, no new deps). An agent then
edits the recording into a Screen-Studio-style clip via the make-video
skill: a self-contained HTML compositor renders the frames + a
composition on a canvas (realistic Chrome window, calm zoom camera,
synthetic cursor, telemetry overlay, error treatment) and exports webm
through the browser's own MediaRecorder — no ffmpeg.

- src/browser_harness/recorder.py: capture layer (+ 6 unit tests)
- src/browser_harness/{run,helpers}.py: observe() hook + helper exports
- interaction-skills/video-template.html: the compositor/renderer
- interaction-skills/make-video.md: the editor skill
- SKILL.md: recording section

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:14:19 -07:00
Laith Weinberger 0ab39e3a23 encourage use of AX tree in prompt 2026-07-10 16:27:17 -07:00
Laith Weinberger edaecbc32c nudge cloud browser 2026-07-07 11:03:44 -07:00
Laith Weinberger 20d3cbd1d5 rename to browser-harness 2026-07-07 08:55:58 -07:00
Laith Weinberger 607f1687f3 update key importation 2026-07-01 20:25:42 +08:00
Laith Weinberger 057dd1504f promote v4 2026-07-01 19:10:53 +08:00
Laith Weinberger 81daf7f99c restore browser-use skill identity 2026-07-01 18:23:58 +08:00
Laith Weinberger be7a36dfa0 align skill identity with harness CLI 2026-07-01 18:19:56 +08:00
Laith Weinberger 5d34276f1a rename to browser use 2026-06-29 10:01:05 +08:00
Gregor Žunič 5447f2a601 Fix skill frontmatter 2026-06-21 08:35:46 -07:00
Gregor Žunič 6cc9c051ae Link packaged skill to install docs 2026-06-21 07:16:54 -07:00
Gregor Žunič d250809de1 Clarify remote daemon flow 2026-06-20 23:43:24 -07:00
Gregor Žunič 010a25205b Add release-ready browser harness packaging 2026-06-20 23:06:41 -07:00
Sarath Suresh a9f7b1d547 Remove -c script execution 2026-05-12 15:35:12 +05:30
MinJaeLee1 226876d56e docs: nudge agents to read matching domain skills 2026-05-07 21:16:03 +09:00
Alezander9 a2443d1d51 docs: standardize harness docs against canonical browser connection reference
Cross-checked AGENTS.md, README.md, SKILL.md, install.md, and profile-sync.md for accuracy. Tightened the sync_local_profile docstring and the chrome://inspect stderr message to match. Cloud-bootstrap test updated to set BU_AUTOSPAWN. All unit tests pass.
2026-05-02 18:02:36 -07:00
Alezander9 7e9a7db8c5 feat: gate domain skills behind BH_DOMAIN_SKILLS env (default off)
Domain skills auto-injected by goto_url() are community-contributed and quality varies; defaulting them off avoids polluting the average run while preserving the contribution loop. Set BH_DOMAIN_SKILLS=1 to opt in.
2026-05-01 20:34:01 -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
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
Abraham 74afacf28c domain-skills: add Polymarket scraping skill
Markdown-style domain skill for Polymarket scraping via Gamma API
(api-first per repo doctrine) with DOM leaf-div-disambiguation fallback
for CSS-module SPAs. Covers market outcomes, metadata, and comments.

Live-tested against gamma-api.polymarket.com and a live event page:
  - 9 outcomes extracted (e.g. April 7: YES 99.95 / NO 0.05, vol $45.7M)
  - Metadata: title, end_date, total_volume, category, market_count
  - 38 comments fetched (40 raw, 2 deleted skipped)

Gotcha documented: Gamma API comment envelopes for deleted comments
preserve id/createdAt/profile/media/parentCommentID but drop the body
field entirely — naive dict access throws KeyError. Guard with
'if "body" not in c: continue'.

DOM fallback pattern documented (not primary path): Polymarket has
zero data-testid attributes and CSS-module-hashed classes. Leaf-div
disambiguation (children.length === 0 + nearest-common-ancestor
grouping) is the only robust approach.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 19:33:17 -03:00
Sarath S Menon 0c4af63b1b docs: move setup/maintenance content from SKILL.md to install.md (#186)
SKILL.md now covers day-to-day usage only. Maintenance commands
(--doctor, --setup, --update) and the architecture section move to
install.md where setup and break-fix content belongs.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 15:19:50 +05:30
Sarath S Menon 724c1c7a16 docs(SKILL.md): remove inline backticks; fix install.md goto_url rename (#185)
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 14:45:28 +05:30
Sarath Suresh fbd9146df5 refactor: rename goto/click/screenshot to avoid Playwright name overlap
- goto()       → goto_url()
- click()      → click_at_xy()
- screenshot() → capture_screenshot()

These three shared exact names with Playwright but different argument
shapes, causing agent confusion. Updated helpers.py and all markdown
skill files.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 11:26:07 +05:30
Sarath Suresh 3dfb08a73d docs(SKILL.md): remove bold formatting
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-24 10:52:30 +05:30
Gregor Žunič ba8b22f1ff fix(run): exec scoping for comprehensions + sharpen click guidance (#133)
* fix(run): pass globals to exec so comprehensions resolve free vars

exec(sys.stdin.read()) inside main() passes different dicts for globals
and locals. Python comprehensions and generator expressions compile to a
nested function whose free-variable lookups can only see the globals
dict, so code like

    for it in items:
        low = it['text'].lower()
        hit = any(k in low for k in KEYS)   # NameError: 'low'

fails at module level under exec. `low` is stored in the exec locals
dict which the generator's implicit function cannot see.

Passing globals() as the only extra arg makes exec use the same dict
for both globals and locals, and comprehensions resolve cleanly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(skill): eyeball click coords from screenshots; no getBoundingClientRect

The previous Clicking bullet said "screenshot -> look -> click(x,y)" but
did not rule out roundtripping through js("...getBoundingClientRect()")
to compute coords. Agents coming from Playwright / Selenium habits tend
to locate-first-click-second even when the screenshot already shows the
target, which is slower and more brittle (hidden inputs placed at
x=-9999, CSS-transformed elements, pseudo-elements) than just reading
the pixel off the image.

Rewrite the bullet to explicitly suppress that reflex and scope the
DOM-fallback to elements with no visible geometry. Also replace the
loose "compositor level" phrasing with the actual mechanism: Chrome's
browser-process hit-testing, which is why clicks pass through iframes
/ shadow DOM / cross-origin without extra work.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 16:06:16 -07:00
reformedot 8a0c981082 feat: self-update CLI, release workflow, and fetch-use routing
- Add --version, --doctor, --setup, --update[-y] commands in run.py;
  logic lives in admin.py (install-mode detection, GitHub-releases cache
  with 24h TTL, dirty-worktree guard, interactive Chrome-attach flow).
- Print a once-per-day startup banner telling agents to run
  `browser-harness --update -y` when a newer release is available.
- Rename project to browser-harness in pyproject.toml so PyPI installs
  (uv tool install browser-harness) work via the public package name.
- Add .github/workflows/release.yml: on v* tag push, verify the tag
  matches pyproject.toml, uv build, and publish to PyPI via trusted
  publishing.
- Wire helpers.http_get through fetch_use.fetch_sync(...).text when
  BROWSER_USE_API_KEY is set; falls back to the original urllib path
  otherwise, preserving the existing str return contract.
- Document the new commands and the agent's self-update duty in
  SKILL.md and install.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-20 12:49:07 -07:00
Gregor Žunič 92f16a5109 docs: point onboarding fast-start at docs.browser-use.com (#118)
The Fast start snippet used https://browser-use.com purely as an
illustrative "hello world". Pointing it at docs.browser-use.com
gives agents a more useful landing page on their first run.

Refs #102

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-19 16:14:18 -07:00
Magnus Müller 96ccb7692b remote: Python API for remote browsers, profiles, and local-profile sync (#84)
* remote: Python API for remote browsers, profiles, and local-profile sync

No CLI, no new entrypoint. Every helper is a Python function callable from
inside a normal `browser-harness <<'PY'` block. run.py pre-imports them.

admin.py:
- start_remote_daemon(name, profileName=None, **create_kwargs)
  Now forwards every documented POST /browsers kwarg (profileId, profileName,
  proxyCountryCode, timeout, customProxy, browserScreenWidth/Height, ...).
  profileName is resolved client-side via list_cloud_profiles — no browser-use
  API change needed. Prints liveUrl and auto-opens it locally when a GUI is
  detected (macOS/Windows always; Linux needs $DISPLAY / $WAYLAND_DISPLAY);
  headless servers print only.
- list_cloud_profiles() — GET /api/v3/profiles + per-profile detail; returns
  [{id, name, cookieDomains, lastUsedAt, userId}]. Agents should report
  len(cookieDomains) not the full list — profiles can have 500 cookies across
  dozens of domains.
- list_local_profiles(), sync_local_profile(name) — shell out to `profile-use`.
  sync_local_profile returns the newly-created cloud UUID.

Profile-sync skill rewritten Python-first with the chat-driven flow (ask the
user which profile; summarize by domain count, never dump cookies) and calls
out the two upstream limitations (sync always creates a new cloud profile; no
per-domain filtering) that need a PR to browser-use/profile-use — they can't
be fixed in browser-harness because the Browser Use API has no cookie
upload/download endpoint.

SKILL.md remote-browsers section updated to match, leading with the parallel
sub-agent use case.

* remote: fix misleading 'no GUI' message when webbrowser.open raises

cubic flagged this on #84: if _has_local_gui() is True but webbrowser.open
raises (e.g. no default browser configured), the code fell through to the
final 'no local GUI — share the liveUrl' line, which is wrong on both counts.
Restructure so each branch produces exactly one accurate message.
2026-04-18 22:19:47 -07:00
Magnus Müller bf0a36a61a skill: surface remote browser liveUrl and tell agents to share it (#83)
* skill: surface remote browser liveUrl and tell agents to share it

* skill: trim liveUrl callout to one short sentence
2026-04-18 18:32:21 -07:00
Magnus Müller 7b457139ba skill: make PATH invocation and new_tab-at-session-start unmissable (#77)
* skill: make PATH invocation and new_tab-at-session-start unmissable

Two footguns that agents keep hitting on their first call:

1. They prefix the harness with `cd /path/to/browser-harness && uv run …`
   even though `browser-harness` is installed on `$PATH` as a standalone
   entrypoint. `uv run` from the wrong cwd actively fails, and the `cd`
   bakes a brittle assumption about where the repo lives.
2. They `goto(url)` on the first call, which navigates the user's
   currently-active tab and destroys whatever they were doing.

Fast start now:
- uses `browser-harness <<'PY'` (no `uv run`) in the example
- uses `new_tab(url)` instead of `goto(url)`
- adds an explicit two-point callout explaining *why* each rule matters
- mirrors both rules in the "What actually works" bullet list so a
  scanning agent sees them even if they skip the intro
- drops the stray `uv run` from the remote-browser snippet

* skill: trim Fast start callout; add read-before-edit note

* skill: require reading full file before using the harness, not just editing
2026-04-18 18:07:40 -07:00
Magnus Müller dcd802cdb1 install: error-driven decision tree, drop unconditional chrome://inspect (#74)
* install: error-driven decision tree, drop unconditional chrome://inspect

The previous bootstrap implied that every attach failure (and any
not-running-Chrome case) needed a chrome://inspect navigation. In
practice the remote-debugging checkbox is per-profile sticky in Chrome,
so for any profile that has ever had it toggled on, just launching
Chrome and polling is enough — chrome://inspect is only needed the
first time per profile, when DevToolsActivePort is genuinely missing.

Restructure step 3 of install.md as an explicit error-keyed decision
tree (no Chrome process / DevToolsActivePort missing / port not live
yet / stale websocket) and add a matching gotcha to SKILL.md. Also fix
a stale `uv run bh` snippet in SKILL.md — the entrypoint is
`browser-harness`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update install.md

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* Update install.md

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
2026-04-18 17:44:48 -07:00
Magnus Müller 6a6081538a add 5s timeout on domain enable calls, add nuclear recovery gotcha (#66)
daemon.py: Page/DOM/Runtime/Network.enable calls now have a 5s
timeout. Previously they could hang indefinitely on heavy pages
(TikTok FYP), preventing the daemon from reaching its socket
listener.

SKILL.md: added one gotcha for when restart_daemon() itself hangs
(kill Chrome entirely and reconnect).

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 15:06:33 -07:00
Magnus Müller f014990f84 SKILL.md: reframe post-task ritual as "Always contribute back" (#61)
* Reframe post-task ritual as the default "contribute back" procedure

Renames the section to "Always contribute back" and turns the guidance
into an imperative default. Adds concrete examples of what's worth a PR
(private APIs, framework quirks, stable selectors, URL patterns, waits,
traps), a schema for what a domain skill should capture (the durable
shape of the site, not the run narration), and an explicit do-not-write
list — most importantly banning raw pixel coordinates.

Narrows the scope to `domain-skills/` contributions only; no longer
nudges agents to update `interaction-skills/` or `helpers.py` as part
of this loop.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Replace "hesitate" with clearer cost framing

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 11:25:53 -07:00
Magnus Müller 23ce2ec464 Fix daemon attaching to invisible omnibox popup (#60)
* fix daemon attaching to invisible omnibox popup on fresh Chrome

When Chrome opens fresh, the only page targets are chrome://
internal pages and the omnibox popup (1px invisible viewport).
The daemon's attach_first_page() fell back to the popup, making
all subsequent work invisible to the user.

Fix: when no real pages exist, create an about:blank tab via
Target.createTarget instead of attaching to the omnibox popup.

Tested configurations:
- Fresh start with no real tabs → creates about:blank (1112x817)
- Navigate without AppleScript → works, tab visible
- Recovery from stale socket → auto-reconnects
- Chrome restart from scratch → creates about:blank

Also adds interaction-skills/connection.md documenting the
omnibox popup problem and startup sequence.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* add connection skill reference to main SKILL.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 11:07:43 -07:00
Magnus Müller 0e12dc8f17 [codex] Refine domain skill guidance (#41)
* Refine domain skill guidance

* Drop unintended skill regressions
2026-04-17 23:27:35 -07:00
Magnus Müller 239a2a45ea [codex] Document domain-skill PR ritual (#39)
* Document domain-skill PR ritual

* Tighten domain-skill PR wording

* Expand shared domain-skill guidance
2026-04-17 23:19:18 -07:00
Magnus Müller ffc0aceaba Emphasize screenshots for verification and exploration (#38) 2026-04-17 23:09:23 -07:00
Magnus Müller bfc07d37e8 Trim JS-heavy guidance from SKILL (#37) 2026-04-17 22:59:35 -07:00
Magnus Müller f87fdde0af Remove default ensure_real_tab from docs (#36) 2026-04-17 22:46:33 -07:00
Magnus Müller becec42ca4 [codex] Rename CLI to browser-harness run (#35)
* Rename CLI to browser-harness run

* Simplify browser-harness CLI
2026-04-17 22:33:05 -07:00
Magnus Müller c9910d426d Top-load browser harness usage guidance (#33)
* Top-load browser harness usage guidance

* Refine skill fast-start copy
2026-04-17 22:26:46 -07:00
Magnus Müller acda8c72a0 Simplify helper surface (#23)
* Simplify helper surface

* Trim common module and restore dispatch key
2026-04-17 21:37:58 -07:00
Magnus Müller 0702b83759 Clarify Chrome remote debugging bootstrap (#22) 2026-04-17 21:12:50 -07:00