Files
workbuddy_skills/browser-harness/SKILL.md
T
admin 44d42b0943 browser-harness:补两条浏览器复用纪律(用户当场点破)+ 入库积压的「调 AI 工具提问方法」
- 🔴 先探测、能复用就复用:动手第一件事查 9223 上有没有已在跑的实例,
  有就直接连(netstat / curl /json/version 两种探法),⛔ 不再起第二个。
  专治「为了量一次尺寸就另起一个 headless 实例」这类小活
  (用户原话:「为什么要重新开浏览器,先检查之前是否开过浏览能否复用」)
- 🔴 一个页面只开一个标签:同一页面全程一个标签,换路由改 hash、换视口走 Emulation,
  只有并排对比两个不同页面才开第二个、用完立刻关;收工前 list_tabs() 复核,
  不给自己留尾巴、也不关别人的页
  (用户原话:「后续调试网页 一个页面开一个标签就行了不要反复开」)
- ⛔ 别自建取数通道:要 DOM 数值就用 js(...),别为「量一个高度」另写脚本去起 Chrome

同文件另有 2026-10-07 定案的「用 browser-harness 调 AI 工具(ChatGPT 等)的提问方法」一节,
一直是未提交状态,随本次一并入库(常驻后台任务守端口、独立实例 9223、profile 复用保登录态)。
2026-10-08 22:22:01 +08:00

15 KiB
Raw Blame History

name, description
name description
browser-harness Always use browser-harness for any web interaction: automation, scraping, testing, or site/app work.

browser-harness

Direct browser control via CDP. For task-specific edits, use agent-workspace/agent_helpers.py. For setup, install, or connection problems, read https://github.com/browser-use/browser-harness/blob/main/install.md.

🔴 本机(用户明令):本技能是唯一允许的浏览器工具

这条优先于本文档其它任何说法(用户 2026-09-13 / 09-25 / 09-26 三次明令):

  • ⛔ 不许改用 playwright(含 playwright-core)/ puppeteer / selenium / 自己起 headless chrome / agent-browser 技能 —— 包括"自己写个脚本调它们"。 有钩子 E:\ProgramData\.workbuddy\bin\browser-guard.py 在执行前拦违规命令; agent-browser / playwright-cli 插件已置 false。
  • ⛔ 不附着用户日常 Chrome。下面「Local Chrome」一节说的"默认附着正在运行的 Chrome" 在本机不适用 —— 那样会弹「允许远程调试?」去动用户自己的浏览器(2026-09-26 实际踩到)。 ⇒ 必须起独立实例:BU_CDP_URL=127.0.0.1:9223(不要用用户 Chrome 默认的 9222)。
  • 🔴 先探测、能复用就复用(2026-10-08 用户当场点破:「为什么要重新开浏览器,先检查之前是否开过浏览能否复用」)。 动手第一件事是查 9223 上有没有已经在跑的实例;有 ⇒ 直接连,⛔ 不要再起一个。 ⛔ 「量个尺寸 / 截个图 / 取个数」这类小活最容易犯这个错 —— 为了量一次就另起一个 headless 实例, 既违了上面的禁令,又会和常驻实例抢同一个 profile。 探法(第一条最轻,够用): netstat -ano | grep -E "127\.0\.0\.1:9223 .*LISTENING" ⇒ 有 pid = 在跑; curl --noproxy '*' -s http://127.0.0.1:9223/json/version ⇒ 回 JSON 说明端口后面确实是 CDP。 确认在跑之后按下面第 2 条的 env 写法连上去,先 list_tabs() 摸清现有页, 自己需要的页用 new_tab() 开 —— ⛔ 不碰别人的页,也⛔ 不为自己方便关掉现有页。
  • 🔴 一个页面只开一个标签,⛔ 不要反复开(2026-10-08 用户令:「后续调试网页 一个页面开一个标签就行了不要反复开」)。 这条接在上一颗子弹后面:先复用浏览器是做对了,但别在同一个浏览器里再反复开页。 典型的错法就是调试一个原型:量一次 new_tab(原型) 一次,量完还忘了关 —— 一次会话下来 共享实例里就堆出一串同一个页面的标签(用户 2026-10-08 亲眼看到,才出的这条令)。 正确做法,按便宜的排:
    • 同一个页面(同一个 URL / 同一份原型)从头到尾就那一个标签。
    • 换路由 ⇒ 改 hash(js("location.hash='#/x'"))或 goto_url(),⛔ 不要 new_tab()。
    • 换视口 ⇒ cdp("Emulation.setDeviceMetricsOverride", width=…, height=…) 在同一个标签里改, ⛔ 不要为了量另一个宽度再开一个标签;量完 cdp("Emulation.clearDeviceMetricsOverride") 还原。
    • 要并排对比两个不同页面(比如参照物 vs 我方)⇒ 这时才开第二个,用完立刻 close_tab()。
    • 完全不需要页面时(只取一个数、截一张图)⇒ 复用当前那个标签,别再开。
    • 🔴 收工前必须 list_tabs() 复核一遍,把自己开的一个不留。共享实例是别人的工作现场, ⛔ 别留尾巴;反向也一样 —— ⛔ 别顺手关掉不是自己开的页。
  • ✅ 动手前先 list_tabs() 看清有哪些标签页,别盲点。(这条同时是上面那条的收工复核用的)
  • ⛔ 别自建取数通道:需要 DOM 数值就用 js(...)、需要截图就用 harness 的截图helper, ⛔ 不要为了「量一个高度」另写一个脚本去起 Chrome。
  • ✅ 静态页 / 公开 API 取数优先 curl 或 WebFetch —— 用不着浏览器就别起。

用 browser-harness 调 AI 工具(ChatGPT 等)的提问方法

2026-10-07 用户定案。适用于「打开 ChatGPT / Claude 网页版求建议、核对方案、做结构评审」这类活。

1. 🔴 浏览器要由常驻后台任务开着

本机沙箱会在父进程退出时连带杀掉子进程。实测对照:

  • 普通(同步)调用里起 Chrome ⇒ 端口 1 秒内就绪,调用一返回 Chrome 立刻死(随后 curl 报 WinError 10061)。
  • 丢进后台任务、且该任务一直不退出(起完浏览器就守着端口)⇒ 浏览器全程常驻。

⇒ 做法:先起一个常驻任务把浏览器开着(守端口,掉了就写日志),之后每次操作只连不起。 ⛔ 别让每次调用各自起一遍浏览器 —— 父进程一退全没,而且多个实例会抢同一个 profile。

2. 起独立实例(端口 9223)

chrome.exe --remote-debugging-port=9223 \
  --user-data-dir=E:/ProgramData/.workbuddy/tmp/bu-chatgpt-profile \
  --proxy-server="socks5://127.0.0.1:10800" about:blank
  • 端口用 9223(用户日常 Chrome 是 9222);--user-data-dir 固定复用 ⇒ 登录态保留。
  • BU_CDP_URL 必须带 scheme:http://127.0.0.1:9223。
  • 必须清掉沙箱代理变量(HTTP_PROXY / HTTPS_PROXY 会劫持本地 CDP ⇒ 502 Bad Gateway): env -u HTTP_PROXY -u HTTPS_PROXY -u http_proxy -u https_proxy NO_PROXY=127.0.0.1,localhost BU_CDP_URL=http://127.0.0.1:9223 browser-harness
  • 可执行体写全名:~/.local/bin/browser-harness.exe。

3. 提问怎么写

  • 说清「意图和目标」+ 给「完整上下文」,末尾一句明确提问 —— 用户口径:不用写太多控制指令。
  • ⛔ 它看不到你的本机路径。要么把全文逐字内联,要么上传文件;⛔ 不要用「见 xxx.md」「文件在 E:/…」代替内容。
  • 一轮一个主题。

4. ✅ 消息发出去的硬证据 = 输入框被清空

⚠️ 页尾出现你写的提问 ≠ 已发出 —— 输入框本身就在 main 里,它的内容会落在 innerText 尾部,看起来就像已发送。发送动作之后回读输入框长度归零才算数。

5. ChatGPT 当前页面(实测,UI 会换代)

项 写法
输入框 div.ProseMirror[role="textbox"](#prompt-textarea 已不存在)
发送按钮 #composer-submit-button → button[data-testid="send-button"] → button[aria-label="发送"]
取正文 `(document.querySelector('main')
上传文件 input[type=file] + cdp("DOM.setFileInputFiles", files=[路径], nodeId=...)
切分锚点 你说: / ChatGPT 说: / ChatGPT 可能会出错

三个易误判点:

  1. 一页可能有多个 ChatGPT 说:(历史轮次)⇒ 取正文用 rfind 取最后一个,find 会切到上一轮。
  2. 「ChatGPT 可能会出错」不是完稿信号(它一直在页面上)⇒ 完稿判据 = 正文长度连续两次采样不变。
  3. 「思考」是输入框工具栏的按钮文案,不是「正在生成」状态。

6. 脚本怎么写

  • ⛔ 不要在 Python 里拼 heredoc + 转义引号喂给 harness(嵌套转义 ⇒ SyntaxError)。
  • ✅ 每一步脚本写成独立 .py 文件,驱动脚本读文件后经 stdin 喂给 harness。
  • ✅ 全程日志落盘(每步 rc + 关键读数),失败能直接定位到哪一步。
  • 多标签页时:先 cdp("Target.getTargets", flatten=True) 看清有哪些页,必要时关掉重复页再 new_tab(目标URL);各步落在不同标签页上会导致读数错乱。

When Not to Use

A basic fetch of public information needs no browser. If a plain HTTP request can read it — a public page, an API, docs — use curl or your fetch tool, and leave the browser alone. Use browser-harness when the task needs interaction (click, type, navigate), the user's logged-in session, JS rendering, or a bot-protected page. If a direct fetch fails or returns a shell page, then escalate to the browser.

Domain skills are off by default. Set BH_DOMAIN_SKILLS=1 to enable them; see the bottom section.

If BH_DOMAIN_SKILLS=1 and the task is site-specific, read every file in the matching $BH_AGENT_WORKSPACE/domain-skills/<site>/ directory before inventing an approach.

Usage

browser-harness <<'PY'
print(page_info())
PY
  • Invoke as browser-harness. Use heredocs for multi-line commands.
  • Helpers are pre-imported. run.py calls ensure_daemon() before exec.
  • First navigation is new_tab(url), not goto_url(url).
  • ⚠️ 上游默认流程是「附着到正在运行的 Chrome/Chromium CDP endpoint」—— 本机禁止这样做,见文件头的🔴段落:必须用 BU_CDP_URL=127.0.0.1:9223 起独立实例。

Local Chrome

⛔ 本机警告:本节描述的是"附着用户现有 Chrome"的流程,在本机不要用(会动用户自己的浏览器)。 需要浏览器时按文件头的规定起独立实例;daemon 连不上先 --doctor 排查,⛔ 不要让 harness 自动去拉起用户日常 Chrome。

If the daemon cannot connect, run diagnostics:

browser-harness --doctor

If Chrome is not running at all, the harness launches it automatically and retries — no user action needed beyond clicking Allow if a permission popup appears.

If Chrome is running but remote debugging is not enabled, the harness opens:

chrome://inspect/#remote-debugging

Ask the user to tick "Allow remote debugging for this browser instance" and click Allow if Chrome shows a permission popup. Then retry the same browser-harness command.

Remote Browsers

Use Browser Use cloud for headless servers, parallel sub-agents, or isolated work.

Cloud browsers are managed Chrome instances hosted by Browser Use. Each one is a fresh, isolated browser. Proactively suggest one (briefly explain why) when:

  • The user wants multiple concurrent tasks. Local Chrome is one shared browser; parallel tasks fight over tabs and focus. One cloud browser per task keeps them fully isolated.
  • Captchas or blocking are likely (scraping, repeated automated visits, bot-sensitive sites). Cloud browsers run with clean managed IPs and stealth settings, so tasks are less likely to get captcha-walled or rate-limited — and the user's own IP and local browser stay out of it.

You can also direct the user to try the same agent behind Browser Harness, fully hosted, in Browser Use Cloud (it's called the v4 agent): https://cloud.browser-use.com?utm_source=skill&utm_medium=browser-use&utm_campaign=v4.

Authenticate once:

browser-harness auth login

Or import a key safely:

printf '%s' "$BROWSER_USE_API_KEY" | browser-harness auth login --api-key-stdin

Pick a short made-up name; r7k2 below is just a placeholder:

browser-harness <<'PY'
start_remote_daemon("r7k2")
PY

BU_NAME=r7k2 browser-harness <<'PY'
new_tab("https://example.com")
print(page_info())
PY

When the task is done and a cloud browser is still running, ask directly: "Should I close this browser now?" If yes, run stop_remote_daemon(name). Remote daemons bill until they stop or time out.

Do not start a remote daemon and then keep using the default daemon. Use the same name for BU_NAME.

Cloud profile cookie sync reference: https://github.com/browser-use/browser-harness/blob/main/interaction-skills/profile-sync.md.

Page Workflow

  • Prefer to find elements with the accessibility tree, not screenshots: cdp("Accessibility.getFullAXTree")["nodes"] has every element's role, name, and backendDOMNodeId — filter in Python before printing (it is thousands of nodes). Coordinates: q = cdp("DOM.getBoxModel", backendNodeId=n)["model"]["content"]; x, y = sum(q[0::2])/4, sum(q[1::2])/4 (viewport px, ready for click_at_xy; negative/oversized means scroll first).
  • Clicking: AX node -> box center -> click_at_xy(x, y) -> verify with a targeted js(...)/page_info() check.
  • Fall back to raw HTML via js(...) only when the AX tree lacks the element (canvas, exotic widgets); screenshot when layout or imagery matters.
  • After navigation, call wait_for_load().
  • If the current tab is stale or internal, call ensure_real_tab().
  • Use js(...) for DOM inspection or extraction when coordinates are the wrong tool.
  • Login walls: stop and ask. Exception: use available SSO automatically when Chrome is already signed in; still stop for passwords, MFA, consent, or ambiguous account choice.
  • Raw CDP is available with cdp("Domain.method", ...).

Recordings and Videos

Fresh installs do not record. Users can enable local background traces:

browser-harness recordings enable
browser-harness recordings disable
browser-harness recordings

BH_RECORD=1 or BH_RECORD=0 overrides the preference for one process. Any natural nudge to “record,” “show,” “demo,” or “make a video” opts in that task; significant work alone does not.

Before browser work, call start_recording(name, title=...), retain its exact returned directory, and call stop_recording() after verifying the result. Never replace that path with recordings --latest. For a request made after the task, use:

browser-harness recordings --latest

Use it only if timestamps and pages match; otherwise say the work was not captured. Never reenact a completed task. For a video, follow make-video.md. If sub-agents are available, they may handle post-production from the exact recording path while the main agent returns the task result.

Interaction Skills

If you get stuck on a browser mechanic, check https://github.com/browser-use/browser-harness/tree/main/interaction-skills.

  • connection.md
  • cookies.md
  • cross-origin-iframes.md
  • dialogs.md
  • downloads.md
  • drag-and-drop.md
  • dropdowns.md
  • iframes.md
  • make-video.md
  • network-requests.md
  • print-as-pdf.md
  • profile-sync.md
  • screenshots.md
  • scrolling.md
  • shadow-dom.md
  • tabs.md
  • uploads.md
  • viewport.md

Design Constraints

  • Coordinate clicks default. CDP mouse events pass through iframes/shadow/cross-origin at the compositor level.
  • Keep the connection model simple: use the default daemon, BU_NAME, BU_CDP_URL, BU_CDP_WS, or start_remote_daemon(...).
  • Core helpers stay short. Put task-specific helper additions in $BH_AGENT_WORKSPACE/agent_helpers.py.

Gotchas

  • chrome://inspect/#remote-debugging must be enabled for local Chrome control.
  • Chrome may show an "Allow remote debugging?" popup; wait for the user to click Allow. Do not retry in a loop — Chrome pops a fresh dialog for every new connection, and the daemon's single held connection is what makes this a one-time click.
  • Omnibox popups are not real work tabs.
  • CDP target order is not Chrome's visible tab-strip order.
  • BU_CDP_URL is an HTTP DevTools endpoint; the daemon resolves it to WebSocket.
  • Ask before leaving cloud browsers running; stop them with stop_remote_daemon(name) or PATCH /browsers/{id} {"action":"stop"}.

Domain Skills

Only applies when BH_DOMAIN_SKILLS=1. Otherwise ignore domain skills.

When enabled, search $BH_AGENT_WORKSPACE/domain-skills/<host>/ before inventing an approach. goto_url(...) returns up to 10 skill filenames for the navigated host.