- Classify the connection up front (browser.py): read DevToolsActivePort + Local State and return ok / cdp-disabled / permission-blocked / browser-closed in ~0.01s, without opening a tab. Each blocked state's error carries its own fix, so the agent relays one line and retries instead of hanging or exploring.
- Defer the marker tab until after the websocket connects, so a failed connection doesn't leave a stray tab.
- Reuse stays in the right profile: on daemon reuse, verify the controlled tab still belongs to the selected context and re-anchor if it drifted or closed (verify_profile). On a stale session, re-attach the same tab instead of grabbing an arbitrary page.
- admin.py routing: a 403 is permission-blocked on its own (focus the profile, don't tell the user to re-tick the checkbox); browser-closed opens/focuses the selected profile.
- Drop the BH_CLOUD_ONLY env var and its guard.
Focusing the plugin on Claude Code for now; Grok falls back to
.claude-plugin/plugin.json anyway, so .grok-plugin was redundant.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
browser-harness is the single source of truth for its own plugin: the
browser-use/plugins marketplace remote-sources this repo (pinned SHA)
instead of vendoring a copy, so there is no drift. Ships skills only;
the CLI stays a one-time install prerequisite.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude Code's marketplace schema expects a string source (".") for a
local plugin; xAI's .grok-plugin keeps {type:local}. Host-specific by
design. Keeps the xAI pin commit (f20e4a) reachable as an ancestor.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Packages browser-harness as an installable plugin for the xAI Grok and
Claude Code plugin marketplaces. Ships skills only; the browser-harness
CLI stays a one-time install prerequisite (skills/browser-harness/references/install.md).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds domain-skills/hubspot/private-app-webhooks.md covering the
subscription editor drawer flow, the React-Select coordinate-click
requirement, the "SubscribeLoading" button-text trap, the two-step
save (drawer Subscribe → top-right Commit changes), and verification
via the read-only /webhooks tab.
Pairs with the existing private-app-creation.md and private-app-rotation.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds close_tab(target=None) alongside new_tab()/switch_tab() as the
missing symmetric tab operation. Accepts a targetId string, a tab dict
from list_tabs()/current_tab(), or no argument to close the currently
attached tab.
Each Chrome tab is a separate renderer process (~50-200MB); closing
unused tabs after an automation task prevents resource bloat.
The green-circle prefix didn't fit the harness theme. Horse echoes the project name (browser-harness) and pairs naturally with chess-knight imagery.
Also fixes a latent slice bug: the prefix is 3 UTF-16 units (surrogate pair + space), so unmark uses slice(3) and removes the trailing space cleanly. The previous 🟢 + slice(2) left the space behind, which would slowly accumulate leading spaces across switch_tab cycles.
Several users flagged that the install.md demo prompts the agent to ask
whether to star browser-harness on their behalf, which reads as star-farming.
Drop the star ask entirely — the demo still opens the repo page so the user
can see the harness has attached, but no longer solicits a star.
A single BH_TMP_DIR conflated two storage concerns with opposite
constraints: sock/port/pid files are bound by AF_UNIX sun_path (104
bytes on macOS, 108 on Linux) and must live in a short path; log files
and screenshots have no length limit and benefit from a deep, indexable,
persistent location. Forcing both into one dir means callers either
bury screenshots under /tmp or risk silently overrunning sun_path.
Decouple with a new BH_RUNTIME_DIR for sock/port/pid. BH_TMP_DIR keeps
log/screenshot duty. BH_RUNTIME_DIR falls back to BH_TMP_DIR, then to
/tmp on POSIX or tempfile.gettempdir() on Windows, so single-dir callers
keep working unchanged.