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.
browser-harness -c '
new_tab("https://docs.browser-use.com")
wait_for_load()
print(page_info())
'
browser-harness -c '
# any python. helpers pre-imported. daemon auto-starts.
'
run.py calls ensure_daemon() before exec — you never start/stop manually unless you want to.
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.
browser-harness -c '
start_remote_daemon("work") # default — clean browser, no profile
# start_remote_daemon("work", profileName="my-work") # reuse a cloud profile (already logged in)
# start_remote_daemon("work", profileId="<uuid>") # same, but by UUID
# start_remote_daemon("work", proxyCountryCode="de", timeout=120) # DE proxy, 2-hour timeout
# start_remote_daemon("work", proxyCountryCode=None) # disable the Browser Use proxy
'
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.
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:
agent-workspace/agent_helpers.py; daemon/bootstrap and remote session admin live in the core package.Installed at ~/Developer/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.
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:
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")
'
time.sleep() generously for JS-heavy SPAs (X, LinkedIn need 3-5s)js(...) with innerText grabs everything including below-fold contentInstalled at ~/Developer/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.
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).
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")
'
time.sleep() generously for JS-heavy SPAs (X, LinkedIn need 3-5s)js(...) with innerText grabs everything including below-fold contentbrave://inspect/#remote-debugging instead of chrome://inspect/.... The harness auto-discovers Brave's data dir.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.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.
davidondrej/skills; verify local paths, tools, credentials, and agent features before acting.