browser-harness
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesebrowser-harness
browser-harness
Direct browser control via CDP. For task-specific edits, use . For setup, install, or connection problems, read install.md.
agent-workspace/agent_helpers.pyRouting check first: if the task needs no interaction (no clicks, logins, or forms) and you just want page content, use DeepAPI instead of driving a browser — see the skill. Use browser-harness when the task needs a real browser: interaction, JS-heavy flows, logged-in sessions, or visual verification.
POST /v1/scrape/websitedeepapiDomain skills (community-contributed per-site playbooks under ) are off by default. Set to enable them; see the bottom section.
agent-workspace/domain-skills/BH_DOMAIN_SKILLS=1If and the task is site-specific, read every file in the matching directory before inventing an approach.
BH_DOMAIN_SKILLS=1agent-workspace/domain-skills/<site>/通过CDP直接控制浏览器。如需针对特定任务的编辑,请使用。如遇安装、设置或连接问题,请阅读install.md。
agent-workspace/agent_helpers.py**首先进行路由检查:**如果任务无需交互(无需点击、登录或填写表单),仅需获取页面内容,请使用DeepAPI的接口,而非驱动浏览器——详见技能。当任务需要真实浏览器环境时才使用browser-harness:如交互操作、依赖JS的流程、已登录会话或视觉验证场景。
POST /v1/scrape/websitedeepapi领域技能(社区贡献的特定站点操作手册,位于目录下)默认处于关闭状态。设置即可启用;详见底部章节。
agent-workspace/domain-skills/BH_DOMAIN_SKILLS=1若且任务针对特定站点,请先阅读目录下的所有文件,再制定操作方案。
BH_DOMAIN_SKILLS=1agent-workspace/domain-skills/<site>/Usage
使用方法
bash
browser-harness -c '
new_tab("https://docs.browser-use.com")
wait_for_load()
print(page_info())
'- Invoke as browser-harness — it's on $PATH. No cd, no uv run.
- First navigation is new_tab(url), not goto_url(url) — goto runs in the user's active tab and clobbers their work.
bash
browser-harness -c '
new_tab("https://docs.browser-use.com")
wait_for_load()
print(page_info())
'- 直接调用browser-harness——它已在$PATH中。无需切换目录,无需执行uv run。
- 首次导航请使用new_tab(url),而非goto_url(url)——goto会在用户的活动标签页中执行,可能覆盖用户正在进行的操作。
Tool call shape
工具调用格式
bash
browser-harness -c 'bash
browser-harness -c 'any python. helpers pre-imported. daemon auto-starts.
可使用任意Python代码。辅助函数已预先导入。守护进程会自动启动。
'
run.py calls ensure_daemon() before exec — you never start/stop manually unless you want to.'
run.py在执行前会调用ensure_daemon()——除非手动指定,否则无需手动启动/停止守护进程。Remote browsers
远程浏览器
Use remote for parallel sub-agents (each gets its own isolated browser via a distinct BU_NAME) or on a headless server. BROWSER_USE_API_KEY must be set. start_remote_daemon, list_cloud_profiles, list_local_profiles, sync_local_profile are pre-imported.
When supervising those sub-agents, after each check send the user one very short status line: what they are doing and whether they are on track.
Claude Code cmux note: after Claude finishes, it may prefill a predicted next user message; that draft is Claude, not the user speaking.
bash
browser-harness -c '
start_remote_daemon("work") # default — clean browser, no profile适用于并行子Agent(每个子Agent通过唯一的BU_NAME获得独立的浏览器实例)或无头服务器场景。必须设置BROWSER_USE_API_KEY。start_remote_daemon、list_cloud_profiles、list_local_profiles、sync_local_profile均已预先导入。
监控这些子Agent时,每次检查后向用户发送一条简短的状态信息:当前执行的操作及是否按计划进行。
Claude Code多路复用注意事项:Claude完成任务后,可能会预填充预测的下一条用户消息;该草稿由Claude生成,并非用户的真实消息。
bash
browser-harness -c '
start_remote_daemon("work") # 默认配置——干净的浏览器环境,无配置文件start_remote_daemon("work", profileName="my-work") # reuse a cloud profile (already logged in)
start_remote_daemon("work", profileName="my-work") # 复用云配置文件(已登录状态)
start_remote_daemon("work", profileId="<uuid>") # same, but by UUID
start_remote_daemon("work", profileId="<uuid>") # 通过UUID复用配置文件
start_remote_daemon("work", proxyCountryCode="de", timeout=120) # DE proxy, 2-hour timeout
start_remote_daemon("work", proxyCountryCode="de", timeout=120) # 使用德国代理,超时时间2小时
start_remote_daemon("work", proxyCountryCode=None) # disable the Browser Use proxy
start_remote_daemon("work", proxyCountryCode=None) # 禁用Browser Use代理
'
BU_NAME=work browser-harness -c '
new_tab("https://example.com")
print(page_info())
'
start_remote_daemon prints liveUrl and auto-opens it in the local browser (if a GUI is detected) so the user can watch along. Headless servers print only — share the URL with the user. The daemon PATCHes the cloud browser to stop on shutdown, which persists profile state. Running remote daemons bill until timeout.
Profiles (cookies-only login state) live in interaction-skills/profile-sync.md — covers list_cloud_profiles(), the chat-driven "which profile?" pattern, and sync_local_profile() for uploading a local Chrome profile.'
BU_NAME=work browser-harness -c '
new_tab("https://example.com")
print(page_info())
'
start_remote_daemon会输出liveUrl,并在检测到GUI环境时自动在本地浏览器中打开该链接,方便用户实时查看操作过程。无头服务器仅输出链接——需将URL分享给用户。守护进程会通过PATCH请求通知云浏览器在关闭时停止运行,从而保留配置文件状态。远程守护进程会按时间计费,直至超时。
配置文件(仅包含Cookie的登录状态)相关内容请查看interaction-skills/profile-sync.md——涵盖list_cloud_profiles()、聊天驱动的“选择哪个配置文件?”模式,以及用于上传本地Chrome配置文件的sync_local_profile()。Interaction skills
交互技能
If you start struggling with a specific mechanic while navigating, look in interaction-skills/ for helpers. They cover reusable UI mechanics like dialogs, tabs, dropdowns, iframes, and uploads. The available interaction skills are:
- connection.md
- cookies.md
- cross-origin-iframes.md
- dialogs.md
- downloads.md
- drag-and-drop.md
- dropdowns.md
- iframes.md
- network-requests.md
- print-as-pdf.md
- profile-sync.md
- screenshots.md
- scrolling.md
- shadow-dom.md
- tabs.md
- uploads.md
- viewport.md
若在导航过程中遇到特定操作难题,请查看interaction-skills/目录下的辅助工具。这些工具涵盖可复用的UI操作机制,如对话框、标签页、下拉菜单、iframe、文件上传等。可用的交互技能包括:
- connection.md
- cookies.md
- cross-origin-iframes.md
- dialogs.md
- downloads.md
- drag-and-drop.md
- dropdowns.md
- iframes.md
- network-requests.md
- print-as-pdf.md
- profile-sync.md
- screenshots.md
- scrolling.md
- shadow-dom.md
- tabs.md
- uploads.md
- viewport.md
What actually works
实际可用的操作技巧
- Screenshots first: use capture_screenshot() to understand the current page quickly, find visible targets, and decide whether you need a click, a selector, or more navigation.
- Clicking: capture_screenshot() → read the pixel off the image → click_at_xy(x, y) → capture_screenshot() to verify. Suppress the Playwright-habit reflex of "locate first, then click" — no getBoundingClientRect, no selector hunt. Drop to DOM only when the target has no visible geometry (hidden input, 0×0 node). Hit-testing happens in Chrome's browser process, so clicks go through iframes / shadow DOM / cross-origin without extra work.
- Bulk HTTP: http_get(url) + ThreadPoolExecutor. No browser for static pages (249 Netflix pages in 2.8s).
- After goto: wait_for_load().
- Wrong/stale tab: ensure_real_tab(). Use it when the current tab is stale or internal; the daemon also auto-recovers from stale sessions on the next call.
- Verification: print(page_info()) is the simplest "is this alive?" check, but screenshots are the default way to verify whether a visible action actually worked.
- DOM reads: use js(...) for inspection and extraction when the screenshot shows that coordinates are the wrong tool.
- Iframe sites (Azure blades, Salesforce): click_at_xy(x, y) passes through; only drop to iframe DOM work when coordinate clicks are the wrong tool.
- Auth wall: redirected to login → stop and ask the user. Don't type credentials from screenshots.
- Raw CDP for anything helpers don't cover: cdp("Domain.method", params).
- 优先使用截图:调用capture_screenshot()快速了解当前页面状态,找到可见目标,判断是否需要点击、选择器或进一步导航。
- 点击操作流程:capture_screenshot() → 读取图像中的像素位置 → click_at_xy(x, y) → 再次调用capture_screenshot()验证操作结果。避免养成Playwright的习惯——“先定位,再点击”,无需使用getBoundingClientRect或查找选择器。仅当目标无可见几何形状(隐藏输入框、0×0节点)时,才使用DOM操作。点击测试在Chrome浏览器进程中执行,因此点击操作可穿透iframe / Shadow DOM / 跨域页面,无需额外处理。
- 批量HTTP请求:使用http_get(url) + ThreadPoolExecutor。静态页面无需使用浏览器(249个Netflix页面仅需2.8秒)。
- 导航后:调用wait_for_load()。
- 标签页异常/过期:调用ensure_real_tab()。当当前标签页过期或为内部页面时使用;守护进程也会在下次调用时自动恢复过期会话。
- 验证操作:print(page_info())是最简单的“是否正常运行?”检查方式,但截图是验证可见操作是否成功的默认方法。
- DOM读取:当截图显示坐标操作不合适时,使用js(...)进行检查和提取。
- Iframe站点(Azure控制台、Salesforce):click_at_xy(x, y)可穿透iframe;仅当坐标点击不合适时,才进行iframe DOM操作。
- 登录墙:被重定向到登录页面时→停止操作并询问用户。不要从截图中提取并输入凭据。
- 辅助工具未覆盖的操作:使用原始CDP命令:cdp("Domain.method", params)。
Design constraints
设计约束
- Coordinate clicks default. Input.dispatchMouseEvent goes through iframes/shadow/cross-origin at the compositor level.
- Connect to the user's running Chrome. Don't launch your own browser.
- cdp-use is only for CDPClient.send_raw. Prefer raw CDP strings over typed wrappers.
- run.py stays tiny. No argparse, subcommands, or extra control layer.
- Core helpers stay short. Put task-specific helper additions in ; daemon/bootstrap and remote session admin live in the core package.
agent-workspace/agent_helpers.py - Don't add a manager layer. No retries framework, session manager, daemon supervisor, config system, or logging framework.
- 默认使用坐标点击。Input.dispatchMouseEvent在合成器层面可穿透iframe/Shadow DOM/跨域页面。
- 连接到用户正在运行的Chrome浏览器。不要自行启动浏览器。
- cdp-use仅用于CDPClient.send_raw。优先使用原始CDP字符串,而非类型化包装器。
- run.py保持精简。不添加argparse、子命令或额外控制层。
- 核心辅助函数保持简短。将特定任务的辅助函数添加到中;守护进程/引导程序和远程会话管理功能位于核心包中。
agent-workspace/agent_helpers.py - 不添加管理层。无重试框架、会话管理器、守护进程监控器、配置系统或日志框架。
Hermes Agent integration
Hermes Agent集成
Installed at as editable . Binary at . Skill at .
~/path/to/browser-harnessuv tool install -e .~/.local/bin/browser-harness~/.hermes/skills/browser-harness/Frontmatter pitfall: The upstream SKILL.md ships with in frontmatter, which collides with Hermes's built-in toolset. When copying into , rename to in the frontmatter or Hermes will shadow/conflict with its own browser tools.
name: browserbrowser~/.hermes/skills/name: browser-harnessBrave Browser: Works identically to Chrome. Enable remote debugging at (same checkbox). The harness auto-discovers Brave's profile directory.
brave://inspect/#remote-debugging以可编辑模式安装在:。二进制文件位于。技能文件位于。
~/path/to/browser-harnessuv tool install -e .~/.local/bin/browser-harness~/.hermes/skills/browser-harness/**前置陷阱:**上游SKILL.md的前置内容中包含,这会与Hermes内置的工具集冲突。将技能文件复制到目录时,请将前置内容中的修改为,否则Hermes会遮蔽/与自身的浏览器工具冲突。
name: browserbrowser~/.hermes/skills/namename: browser-harness**Brave浏览器:**与Chrome完全兼容。在启用远程调试(相同的复选框)。该工具会自动发现Brave的配置文件目录。
brave://inspect/#remote-debuggingAuthenticated content extraction (proven pattern)
认证内容提取(已验证的模式)
browser-harness connects to the user's real browser with their active sessions — ideal for extracting content from login-walled sites where or Hermes's built-in fail (e.g. X/Twitter articles, LinkedIn, paywalled sites).
web_extractbrowser_navigatePattern:
bash
browser-harness -c '
new_tab("https://x.com/user/status/123456")
wait_for_load()
import time
time.sleep(5) # let JS-heavy pages render
text = js("""
const article = document.querySelector("article");
if (article) return article.innerText;
return document.body.innerText;
""")
with open("/tmp/extracted.txt", "w") as f:
f.write(text)
print("Written", len(text), "chars")
'- Write to a temp file to avoid shell escaping issues with large text
- Use generously for JS-heavy SPAs (X, LinkedIn need 3-5s)
time.sleep() - X/Twitter articles render inline — just scroll/extract via DOM, no extra click needed
- For very long pages, with
js(...)grabs everything including below-fold contentinnerText
browser-harness连接到用户的真实浏览器及其中的活动会话——非常适合从需要登录的站点提取内容,而或Hermes内置的在这些站点可能失效(如X/Twitter文章、LinkedIn、付费墙站点)。
web_extractbrowser_navigate操作模式:
bash
browser-harness -c '
new_tab("https://x.com/user/status/123456")
wait_for_load()
import time
time.sleep(5) # 等待依赖JS的页面渲染完成
text = js("""
const article = document.querySelector("article");
if (article) return article.innerText;
return document.body.innerText;
""")
with open("/tmp/extracted.txt", "w") as f:
f.write(text)
print("Written", len(text), "chars")
'- 将内容写入临时文件,避免大文本导致的Shell转义问题
- 针对依赖JS的SPA(X、LinkedIn需3-5秒),请充分使用
time.sleep() - X/Twitter文章为内联渲染——只需通过DOM滚动/提取,无需额外点击
- 对于超长页面,使用结合
js(...)可获取包括折叠区域在内的所有内容innerText
Hermes Agent integration
Hermes Agent集成
Installed at as editable . Binary at . Skill at .
~/path/to/browser-harnessuv tool install -e .~/.local/bin/browser-harness~/.hermes/skills/browser-harness/Frontmatter pitfall: The upstream SKILL.md ships with in frontmatter, which collides with Hermes's built-in toolset. When copying into , rename to in the frontmatter.
name: browserbrowser~/.hermes/skills/name: browser-harnessBrave Browser: Works identically to Chrome. Enable remote debugging at (same checkbox). The harness auto-discovers Brave's profile directory.
brave://inspect/#remote-debugging以可编辑模式安装在:。二进制文件位于。技能文件位于。
~/path/to/browser-harnessuv tool install -e .~/.local/bin/browser-harness~/.hermes/skills/browser-harness/**前置陷阱:**上游SKILL.md的前置内容中包含,这会与Hermes内置的工具集冲突。将技能文件复制到目录时,请将前置内容中的修改为。
name: browserbrowser~/.hermes/skills/namename: browser-harness**Brave浏览器:**与Chrome完全兼容。在启用远程调试(相同的复选框)。该工具会自动发现Brave的配置文件目录。
brave://inspect/#remote-debuggingAuthenticated content extraction (proven pattern)
认证内容提取(已验证的模式)
browser-harness connects to the user's real browser with active sessions — ideal for login-walled sites where or Hermes's built-in fail (X/Twitter articles, LinkedIn, paywalled sites).
web_extractbrowser_navigatebash
browser-harness -c '
new_tab("https://x.com/user/status/123456")
wait_for_load()
import time
time.sleep(5) # let JS-heavy pages render
text = js("""
const article = document.querySelector("article");
if (article) return article.innerText;
return document.body.innerText;
""")
with open("/tmp/extracted.txt", "w") as f:
f.write(text)
print("Written", len(text), "chars")
'- Write to a temp file to avoid shell escaping issues with large text
- Use generously for JS-heavy SPAs (X, LinkedIn need 3-5s)
time.sleep() - X/Twitter articles render inline — just scroll/extract via DOM, no extra click needed
- with
js(...)grabs everything including below-fold contentinnerText
browser-harness连接到用户的真实浏览器及其中的活动会话——非常适合从需要登录的站点提取内容,而或Hermes内置的在这些站点可能失效(如X/Twitter文章、LinkedIn、付费墙站点)。
web_extractbrowser_navigatebash
browser-harness -c '
new_tab("https://x.com/user/status/123456")
wait_for_load()
import time
time.sleep(5) # 等待依赖JS的页面渲染完成
text = js("""
const article = document.querySelector("article");
if (article) return article.innerText;
return document.body.innerText;
""")
with open("/tmp/extracted.txt", "w") as f:
f.write(text)
print("Written", len(text), "chars")
'- 将内容写入临时文件,避免大文本导致的Shell转义问题
- 针对依赖JS的SPA(X、LinkedIn需3-5秒),请充分使用
time.sleep() - X/Twitter文章为内联渲染——只需通过DOM滚动/提取,无需额外点击
- 使用结合
js(...)可获取包括折叠区域在内的所有内容innerText
Gotchas (field-tested)
常见问题(经实战验证)
- Brave Browser uses instead of
brave://inspect/#remote-debugging. The harness auto-discovers Brave's data dir.chrome://inspect/... - Login-walled content extraction (e.g. X/Twitter articles): navigate with ,
new_tab(url), then extract viawait_for_load(). Write to a temp file to avoid shell escaping:js("document.querySelector('article').innerText"). The user's existing browser session handles auth automatically.with open('/tmp/out.txt', 'w') as f: f.write(text) - Omnibox popups are fake page targets. Filter chrome://omnibox-popup... and other internals when you need a real tab.
- CDP target order != Chrome's visible tab-strip order. Use UI automation when the user means "the first/second tab I can see"; Target.activateTarget only shows a known target.
- Default daemon sessions can go stale. ensure_real_tab() re-attaches to a real page.
- Browser Use API is camelCase on the wire. cdpUrl, proxyCountryCode, etc.
- Remote cdpUrl is HTTPS, not ws. Resolve the websocket URL via /json/version.
- Stop cloud browsers with PATCH /browsers/{id} + {"action":"stop"}.
- After every meaningful action, re-screenshot before assuming it worked. Use the image to verify changed state, open menus, navigation, visible errors, and whether the page is in the state you expected.
- Use screenshots to drive exploration. They are often the fastest way to find the next click target, notice hidden blockers, and decide if a selector is even worth writing.
- Prefer compositor-level actions over framework hacks. Try screenshots, coordinate clicks, and raw key input before adding DOM-specific workarounds.
- If you need framework-specific DOM tricks, check interaction-skills/ first. That is where dropdown, dialog, iframe, shadow DOM, and form-specific guidance belongs.
- Brave浏览器使用而非
brave://inspect/#remote-debugging。该工具会自动发现Brave的数据目录。chrome://inspect/... - 登录墙内容提取(如X/Twitter文章):使用导航,调用
new_tab(url),然后通过wait_for_load()提取内容。将内容写入临时文件以避免Shell转义问题:js("document.querySelector('article').innerText")。用户现有的浏览器会话会自动处理认证。with open('/tmp/out.txt', 'w') as f: f.write(text) - 地址栏弹窗为虚假页面目标。当需要真实标签页时,请过滤chrome://omnibox-popup...及其他内部页面。
- CDP目标顺序≠Chrome可见标签栏顺序。当用户提及“我能看到的第一个/第二个标签页”时,请使用UI自动化;Target.activateTarget仅能激活已知目标。
- 默认守护进程会话可能过期。ensure_real_tab()可重新连接到真实页面。
- Browser Use API在传输时使用驼峰命名法。如cdpUrl、proxyCountryCode等。
- 远程cdpUrl为HTTPS,而非ws。通过/json/version解析WebSocket URL。
- 使用PATCH /browsers/{id} + {"action":"stop"}停止云浏览器。
- 每次执行重要操作后,请重新截图再假设操作成功。通过图像验证状态变化、菜单打开、导航结果、可见错误及页面是否符合预期状态。
- 使用截图驱动探索。截图通常是找到下一个点击目标、发现隐藏障碍、判断是否值得编写选择器的最快方式。
- 优先使用合成器层面的操作,而非框架技巧。在添加DOM特定的解决方案前,先尝试截图、坐标点击和原始按键输入。
- 若需要框架特定的DOM技巧,请先查看interaction-skills/目录。下拉菜单、对话框、iframe、Shadow DOM和表单的特定操作指南均位于该目录。
Domain skills (opt-in)
领域技能(可选启用)
Only applies when . Otherwise ignore — is dormant and won't surface skill files.
BH_DOMAIN_SKILLS=1agent-workspace/domain-skills/goto_urlWhen enabled, search before inventing an approach. returns up to 10 skill filenames for the navigated host.
agent-workspace/domain-skills/<host>/goto_urlIf you learn anything non-obvious — a private API, stable selector, framework quirk, URL pattern, hidden wait, or site-specific trap — open a PR to . Capture the durable shape of the site (the map, not the diary). Don't write pixel coordinates (break on layout), task narration, or secrets — the directory is public.
agent-workspace/domain-skills/<site>/仅当时生效。否则忽略——处于休眠状态,不会显示技能文件。
BH_DOMAIN_SKILLS=1agent-workspace/domain-skills/goto_url启用后,在制定操作方案前,请先搜索目录。会返回当前导航主机对应的最多10个技能文件名。
agent-workspace/domain-skills/<host>/goto_url若发现任何非显而易见的内容——私有API、稳定选择器、框架特性、URL模式、隐藏等待机制或站点特定陷阱——请提交PR到目录。记录站点的持久结构(即地图,而非日志)。不要写入像素坐标(布局变化会导致失效)、任务描述或机密信息——该目录为公开目录。
agent-workspace/domain-skills/<site>/