browser-harness

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

browser-harness

browser-harness

Direct browser control via CDP. For task-specific edits, use
agent-workspace/agent_helpers.py
. For setup, install, or connection problems, read install.md.
Routing check first: if the task needs no interaction (no clicks, logins, or forms) and you just want page content, use DeepAPI
POST /v1/scrape/website
instead of driving a browser — see the
deepapi
skill. Use browser-harness when the task needs a real browser: interaction, JS-heavy flows, logged-in sessions, or visual verification.
Domain skills (community-contributed per-site playbooks under
agent-workspace/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
agent-workspace/domain-skills/<site>/
directory before inventing an approach.
通过CDP直接控制浏览器。如需针对特定任务的编辑,请使用
agent-workspace/agent_helpers.py
。如遇安装、设置或连接问题,请阅读install.md。
**首先进行路由检查:**如果任务无需交互(无需点击、登录或填写表单),仅需获取页面内容,请使用DeepAPI的
POST /v1/scrape/website
接口,而非驱动浏览器——详见
deepapi
技能。当任务需要真实浏览器环境时才使用browser-harness:如交互操作、依赖JS的流程、已登录会话或视觉验证场景。
领域技能(社区贡献的特定站点操作手册,位于
agent-workspace/domain-skills/
目录下)默认处于关闭状态。设置
BH_DOMAIN_SKILLS=1
即可启用;详见底部章节。
BH_DOMAIN_SKILLS=1
且任务针对特定站点,请先阅读
agent-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
    agent-workspace/agent_helpers.py
    ; daemon/bootstrap and remote session admin live in the core package.
  • 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
~/path/to/browser-harness
as editable
uv tool install -e .
. Binary at
~/.local/bin/browser-harness
. Skill at
~/.hermes/skills/browser-harness/
.
Frontmatter pitfall: The upstream SKILL.md ships with
name: browser
in frontmatter, which collides with Hermes's built-in
browser
toolset. When copying into
~/.hermes/skills/
, rename to
name: browser-harness
in the frontmatter or Hermes will shadow/conflict with its own browser tools.
Brave Browser: Works identically to Chrome. Enable remote debugging at
brave://inspect/#remote-debugging
(same checkbox). The harness auto-discovers Brave's profile directory.
以可编辑模式安装在
~/path/to/browser-harness
uv tool install -e .
。二进制文件位于
~/.local/bin/browser-harness
。技能文件位于
~/.hermes/skills/browser-harness/
**前置陷阱:**上游SKILL.md的前置内容中包含
name: browser
,这会与Hermes内置的
browser
工具集冲突。将技能文件复制到
~/.hermes/skills/
目录时,请将前置内容中的
name
修改为
name: browser-harness
,否则Hermes会遮蔽/与自身的浏览器工具冲突。
**Brave浏览器:**与Chrome完全兼容。在
brave://inspect/#remote-debugging
启用远程调试(相同的复选框)。该工具会自动发现Brave的配置文件目录。

Authenticated 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
web_extract
or Hermes's built-in
browser_navigate
fail (e.g. X/Twitter articles, LinkedIn, paywalled sites).
Pattern:
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
    time.sleep()
    generously for JS-heavy SPAs (X, LinkedIn need 3-5s)
  • X/Twitter articles render inline — just scroll/extract via DOM, no extra click needed
  • For very long pages,
    js(...)
    with
    innerText
    grabs everything including below-fold content
browser-harness连接到用户的真实浏览器及其中的活动会话——非常适合从需要登录的站点提取内容,而
web_extract
或Hermes内置的
browser_navigate
在这些站点可能失效(如X/Twitter文章、LinkedIn、付费墙站点)。
操作模式:
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
~/path/to/browser-harness
as editable
uv tool install -e .
. Binary at
~/.local/bin/browser-harness
. Skill at
~/.hermes/skills/browser-harness/
.
Frontmatter pitfall: The upstream SKILL.md ships with
name: browser
in frontmatter, which collides with Hermes's built-in
browser
toolset. When copying into
~/.hermes/skills/
, rename to
name: browser-harness
in the frontmatter.
Brave Browser: Works identically to Chrome. Enable remote debugging at
brave://inspect/#remote-debugging
(same checkbox). The harness auto-discovers Brave's profile directory.
以可编辑模式安装在
~/path/to/browser-harness
uv tool install -e .
。二进制文件位于
~/.local/bin/browser-harness
。技能文件位于
~/.hermes/skills/browser-harness/
**前置陷阱:**上游SKILL.md的前置内容中包含
name: browser
,这会与Hermes内置的
browser
工具集冲突。将技能文件复制到
~/.hermes/skills/
目录时,请将前置内容中的
name
修改为
name: browser-harness
**Brave浏览器:**与Chrome完全兼容。在
brave://inspect/#remote-debugging
启用远程调试(相同的复选框)。该工具会自动发现Brave的配置文件目录。

Authenticated content extraction (proven pattern)

认证内容提取(已验证的模式)

browser-harness connects to the user's real browser with active sessions — ideal for login-walled sites where
web_extract
or Hermes's built-in
browser_navigate
fail (X/Twitter articles, LinkedIn, paywalled sites).
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
    time.sleep()
    generously for JS-heavy SPAs (X, LinkedIn need 3-5s)
  • X/Twitter articles render inline — just scroll/extract via DOM, no extra click needed
  • js(...)
    with
    innerText
    grabs everything including below-fold content
browser-harness连接到用户的真实浏览器及其中的活动会话——非常适合从需要登录的站点提取内容,而
web_extract
或Hermes内置的
browser_navigate
在这些站点可能失效(如X/Twitter文章、LinkedIn、付费墙站点)。
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
    可获取包括折叠区域在内的所有内容

Gotchas (field-tested)

常见问题(经实战验证)

  • Brave Browser uses
    brave://inspect/#remote-debugging
    instead of
    chrome://inspect/...
    . The harness auto-discovers Brave's data dir.
  • Login-walled content extraction (e.g. X/Twitter articles): navigate with
    new_tab(url)
    ,
    wait_for_load()
    , then extract via
    js("document.querySelector('article').innerText")
    . Write to a temp file to avoid shell escaping:
    with open('/tmp/out.txt', 'w') as f: f.write(text)
    . The user's existing browser session handles auth automatically.
  • 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
    而非
    chrome://inspect/...
    。该工具会自动发现Brave的数据目录。
  • 登录墙内容提取(如X/Twitter文章):使用
    new_tab(url)
    导航,调用
    wait_for_load()
    ,然后通过
    js("document.querySelector('article').innerText")
    提取内容。将内容写入临时文件以避免Shell转义问题:
    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
BH_DOMAIN_SKILLS=1
. Otherwise ignore —
agent-workspace/domain-skills/
is dormant and
goto_url
won't surface skill files.
When enabled, search
agent-workspace/domain-skills/<host>/
before inventing an approach.
goto_url
returns up to 10 skill filenames for the navigated host.
If you learn anything non-obvious — a private API, stable selector, framework quirk, URL pattern, hidden wait, or site-specific trap — open a PR to
agent-workspace/domain-skills/<site>/
. 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.
仅当
BH_DOMAIN_SKILLS=1
时生效。否则忽略——
agent-workspace/domain-skills/
处于休眠状态,
goto_url
不会显示技能文件。
启用后,在制定操作方案前,请先搜索
agent-workspace/domain-skills/<host>/
目录。
goto_url
会返回当前导航主机对应的最多10个技能文件名。
若发现任何非显而易见的内容——私有API、稳定选择器、框架特性、URL模式、隐藏等待机制或站点特定陷阱——请提交PR到
agent-workspace/domain-skills/<site>/
目录。记录站点的持久结构(即地图,而非日志)。不要写入像素坐标(布局变化会导致失效)、任务描述或机密信息——该目录为公开目录。