Skip to content

Add browser manager and explicit browser selection#454

Open
gregpr07 wants to merge 15 commits into
mainfrom
codex/browser-manager-impl
Open

Add browser manager and explicit browser selection#454
gregpr07 wants to merge 15 commits into
mainfrom
codex/browser-manager-impl

Conversation

@gregpr07

@gregpr07 gregpr07 commented Jun 18, 2026

Copy link
Copy Markdown
Member

Summary by cubic

Adds manager mode with explicit browser ids and isolated runtimes: create with browser_new("private" | "cloud"), then select with browser(id) before using page helpers. Also adds PyPI packaging with uv install, a browser-harness skill command, XDG-based workspace paths, cloud auth login/import with leaner status, a repo-local ./browser-harness launcher, tighter diagnostics and JS evaluation, and opt‑out telemetry.

  • New Features

    • Manager daemon/client manage create/list/switch/close across isolated runtime/tmp/download/artifact dirs with safe cleanup; multiple clients can select the same browser via an active binding context.
    • Local profiles: browser_profiles([verbose]) lists stable ids (e.g. google-chrome:Default), browser_use_profile(id) selects one; the CLI subcommand browser-harness profiles [--verbose] runs without starting the daemon.
    • Cloud auth: auth login/status/logout/import using OAuth PKCE, device code, or safe stdin key import; prefers BROWSER_USE_API_KEY, otherwise stores a scoped key under BH_AUTH_PATH; cloud responses include a live_url when available; status output trimmed to essentials.
    • Packaging and install: published to PyPI with a release workflow; install via uv tool install browser-harness; browser-harness skill prints the canonical skill body; materializes SKILL.md in packages for non-symlink installs; new docs/browser-connection.md; shorter install guide.
    • Filesystem: default workspace and runtime live under ${XDG_CONFIG_HOME:-~/.config}/browser-harness/; override with BH_HOME, BH_CONFIG_DIR, or BH_RUNTIME_DIR; manager endpoint via BH_MANAGER_ROOT/BH_MANAGER_SOCKET.
    • Dev experience: repo-local ./browser-harness launcher runs the working tree without a venv and uses a checkout-specific manager root under /tmp; new browser-harness-manager entrypoint.
    • Reliability: JS helpers retry only on CDP “Illegal return statement”; press_key no longer emits a stray char with modifiers; treat explicit BU_CDP_URL as remote; clearer Chrome permission popup guidance; manager mode skips legacy daemon auto-start.
    • Telemetry: low-cardinality, best-effort, opt-out telemetry; disable with BH_TELEMETRY=0 or BROWSER_HARNESS_TELEMETRY=0.
  • Migration

    • Update scripts to browser_new("private" | "cloud") → keep the returned id → browser(id) before page helpers.
    • Replace list_local_profiles() with browser_profiles() and use_local_profile(id) with browser_use_profile(id).
    • Workspace paths now default to ${XDG_CONFIG_HOME:-~/.config}/browser-harness/agent-workspace/; adjust any hard-coded references or set BH_CONFIG_DIR/BH_HOME.
    • Remote CDP flows are unchanged; set BU_CDP_WS or BU_CDP_URL to use a specific endpoint.
    • For cloud browsers, set BROWSER_USE_API_KEY, run browser-harness auth login (supports device code and stdin), or browser-harness auth import once.

Written for commit 07e56f7. Summary will update on new commits.

Review in cubic

@browser-harness-review

browser-harness-review Bot commented Jun 18, 2026

Copy link
Copy Markdown

⛔ Skill review blocked

An automated security review found 1 finding(s) across 1 file(s).

  • interaction-skills/profile-sync.mdmalicious_code

Skill authorship is restricted to maintainers. Please do not attempt to self-fix — a maintainer will review and follow up.

Comment thread src/browser_harness/auth.py Fixed
Comment thread src/browser_harness/auth.py Fixed
Comment thread src/browser_harness/auth.py Fixed
Comment thread src/browser_harness/auth.py Fixed

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 5 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/browser_harness/auth.py">

<violation number="1" location="src/browser_harness/auth.py:457">
P2: TTY API-key entry can crash on aborted input because `EOFError` from `getpass` is not handled. Convert prompt failures to `AuthError` so CLI exits cleanly with error status.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

Comment thread src/browser_harness/auth.py Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 issues found and verified against the latest diff

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="tests/unit/test_run_manager_mode.py">

<violation number="1" location="tests/unit/test_run_manager_mode.py:42">
P2: All three tests leak BH_MANAGER_MODE into os.environ — run.main() calls setdefault('BH_MANAGER_MODE', '1') but no test cleans it up. Can cause test-order-dependent failures in any test that reads BH_MANAGER_MODE.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread src/browser_harness/manager_client.py Outdated
Comment thread src/browser_harness/manager_daemon.py Outdated
Comment thread src/browser_harness/auth.py
Comment thread tests/unit/test_run_manager_mode.py Outdated
Comment thread src/browser_harness/manager_helpers.py Outdated
Comment thread src/browser_harness/helpers.py Outdated
@gregpr07 gregpr07 changed the title Codex/browser manager impl Jun 19, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 34 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/release.yml">

<violation number="1" location=".github/workflows/release.yml:16">
P1: Release workflow uses mutable action tags instead of immutable commit SHAs, creating CI/CD supply-chain risk for PyPI publishing.</violation>
</file>

<file name="install.md">

<violation number="1" location="install.md:14">
P2: Install instructions use unconditional `rm -rf` on generic skill directory names, risking deletion of legitimate user skills</violation>
</file>

<file name="src/browser_harness/manager_client.py">

<violation number="1" location="src/browser_harness/manager_client.py:97">
P2: `stop_manager_if_running` ignores the response from `send_request` and unconditionally returns `True` on successful transport, misleading callers if the daemon rejects shutdown.</violation>
</file>

<file name="src/browser_harness/local_profiles.py">

<violation number="1" location="src/browser_harness/local_profiles.py:86">
P2: Changing profile_config_path() to return settings.json risks silent data loss because set_default_profile_id() overwrites the entire file without reading existing content. The docs describe settings.json as "selected local Chrome profile and future preferences", indicating it is a shared settings document. Future preferences stored there will be clobbered on every profile change.</violation>
</file>

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

contents: read
id-token: write
steps:
- uses: actions/checkout@v4

@cubic-dev-ai cubic-dev-ai Bot Jun 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Release workflow uses mutable action tags instead of immutable commit SHAs, creating CI/CD supply-chain risk for PyPI publishing.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/release.yml, line 16:

<comment>Release workflow uses mutable action tags instead of immutable commit SHAs, creating CI/CD supply-chain risk for PyPI publishing.</comment>

<file context>
@@ -0,0 +1,25 @@
+      contents: read
+      id-token: write
+    steps:
+      - uses: actions/checkout@v4
+      - uses: actions/setup-python@v5
+        with:
</file context>
Fix with cubic
Comment thread install.md
uv tool install -e .
command -v browser-harness
uv tool install browser-harness
for root in "${CODEX_HOME:-$HOME/.codex}/skills" "$HOME/.agents/skills"; do

@cubic-dev-ai cubic-dev-ai Bot Jun 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Install instructions use unconditional rm -rf on generic skill directory names, risking deletion of legitimate user skills

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At install.md, line 14:

<comment>Install instructions use unconditional `rm -rf` on generic skill directory names, risking deletion of legitimate user skills</comment>

<file context>
@@ -1,176 +1,79 @@
-uv tool install -e .
-command -v browser-harness
+uv tool install browser-harness
+for root in "${CODEX_HOME:-$HOME/.codex}/skills" "$HOME/.agents/skills"; do
+  rm -rf "$root/browser-harness" "$root/browser" "$root/browser-use"
+done
</file context>
Fix with cubic
except (FileNotFoundError, ConnectionRefusedError, TimeoutError, OSError, ValueError, KeyError, TypeError):
return False
try:
manager_runtime.send_request(sock, token, {"meta": "shutdown"})

@cubic-dev-ai cubic-dev-ai Bot Jun 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: stop_manager_if_running ignores the response from send_request and unconditionally returns True on successful transport, misleading callers if the daemon rejects shutdown.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/browser_harness/manager_client.py, line 97:

<comment>`stop_manager_if_running` ignores the response from `send_request` and unconditionally returns `True` on successful transport, misleading callers if the daemon rejects shutdown.</comment>

<file context>
@@ -87,6 +87,24 @@ def _manager_socket_alive(path: Path) -> bool:
+    except (FileNotFoundError, ConnectionRefusedError, TimeoutError, OSError, ValueError, KeyError, TypeError):
+        return False
+    try:
+        manager_runtime.send_request(sock, token, {"meta": "shutdown"})
+        return True
+    except (OSError, ValueError, AttributeError):
</file context>
Fix with cubic


def profile_config_path() -> Path:
return config_dir() / "settings.json"

@cubic-dev-ai cubic-dev-ai Bot Jun 21, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Changing profile_config_path() to return settings.json risks silent data loss because set_default_profile_id() overwrites the entire file without reading existing content. The docs describe settings.json as "selected local Chrome profile and future preferences", indicating it is a shared settings document. Future preferences stored there will be clobbered on every profile change.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/browser_harness/local_profiles.py, line 86:

<comment>Changing profile_config_path() to return settings.json risks silent data loss because set_default_profile_id() overwrites the entire file without reading existing content. The docs describe settings.json as "selected local Chrome profile and future preferences", indicating it is a shared settings document. Future preferences stored there will be clobbered on every profile change.</comment>

<file context>
@@ -77,18 +79,14 @@ def payload(self) -> dict:
 
 
 def profile_config_path() -> Path:
+    return config_dir() / "settings.json"
+
+
</file context>
Fix with cubic
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants