diff --git a/cli/VERSION b/cli/VERSION index b19b5211..85f7059b 100644 --- a/cli/VERSION +++ b/cli/VERSION @@ -1 +1 @@ -v0.8.0 +v0.8.1 diff --git a/cli/cmd_browser.go b/cli/cmd_browser.go index 181c83cf..4263e4d0 100644 --- a/cli/cmd_browser.go +++ b/cli/cmd_browser.go @@ -62,12 +62,16 @@ USAGE homelab browser run [--url URL] [--shared-context] [--keep-open] [--port N] [--timeout S] homelab browser open [--shared-context] [--timeout S] -WHEN TO USE THIS (not the headless @playwright/mcp browser) - A site LOADS fine but a gated action FAILS or HANGS — a submit/login/checkout - spins forever, or ONE request 500s / aborts while its siblings 200. That is - the signature of headless / anti-bot detection (navigator.webdriver, UA - "HeadlessChrome", disable-devtool traps). Switch to this command — it presents - as a real Chrome and typically succeeds first try. +WHEN TO USE THIS — escalation only; DEFAULT to the headless/MCP browser + Default to the Playwright MCP / headless browser for ALL routine browsing and + automation — it's interactive (snapshot per step), fast to start, isolated. + Reach for THIS command ONLY when headless is demonstrably blocked: a site + LOADS fine but a gated action FAILS or HANGS — a submit/login/checkout spins + forever, or ONE request errors while its siblings 200. That is the signature + of headless / anti-bot detection (navigator.webdriver, UA "HeadlessChrome", + disable-devtool traps). It presents as a real Chrome and usually succeeds + first try — but it's the shared cluster browser (slower startup, one batch + run, no per-step feedback), so it's the escalation path, never the default. ERROR-CODE CHEAT-SHEET (diagnose BEFORE retrying) ERR_FILE_NOT_FOUND (-6) request intercepted/resolved locally by the diff --git a/cli/cmd_browser_test.go b/cli/cmd_browser_test.go index ee6bc25d..668897d3 100644 --- a/cli/cmd_browser_test.go +++ b/cli/cmd_browser_test.go @@ -137,6 +137,18 @@ func TestBrowserHelpHasDiagnosticCheatSheet(t *testing.T) { } } +func TestBrowserHelpIsTiered(t *testing.T) { + // --help must frame this as the ESCALATION path (default to headless first), + // matching ~/code/CLAUDE.md and chrome-service.md — non-conflicting agent + // instructions. Guard against a regression to "co-equal choice" wording. + h := browserHelp() + for _, want := range []string{"Default to the", "escalation"} { + if !strings.Contains(h, want) { + t.Errorf("browser --help must carry the tiered/default-headless framing; missing %q", want) + } + } +} + func TestStealthJSEmbeddedMatchesCanonical(t *testing.T) { // The embedded copy must never drift from the source of truth that the // in-cluster callers use, else the CLI's stealth and the cluster's diverge. diff --git a/docs/architecture/chrome-service.md b/docs/architecture/chrome-service.md index e1b5208d..000eec90 100644 --- a/docs/architecture/chrome-service.md +++ b/docs/architecture/chrome-service.md @@ -184,9 +184,12 @@ inject `CHROME_CDP_URL`, vendor `stealth.js`). Agents on the devvm reach this browser through the **`homelab browser`** CLI (`cli/`, ADR-0013) — the packaged, discoverable form of the ad-hoc -`connect_over_cdp` recipe. Use it when a site loads but a gated action -(submit/login) silently fails or hangs — the signature of headless / anti-bot -detection. +`connect_over_cdp` recipe. It is the **escalation path, not the default**: +agents default to the Playwright MCP / headless browser for all routine +automation, and reach for `homelab browser` ONLY when headless is blocked — a +site loads but a gated action (submit/login) silently fails or hangs, the +signature of headless / anti-bot detection. (Same tiered rule lives in +`~/code/CLAUDE.md` and `homelab browser --help`.) ```text devvm: homelab browser run flow.js