Skip to content

fix(browser): treat no-op BROWSER values as unset so headless sessions can fall back#756

Merged
backnotprop merged 1 commit into
backnotprop:mainfrom
yonihorn:fix/browser-sentinel-handling
May 19, 2026
Merged

fix(browser): treat no-op BROWSER values as unset so headless sessions can fall back#756
backnotprop merged 1 commit into
backnotprop:mainfrom
yonihorn:fix/browser-sentinel-handling

Conversation

@yonihorn
Copy link
Copy Markdown
Contributor

@yonihorn yonihorn commented May 19, 2026

Summary

When $BROWSER (or $PLANNOTATOR_BROWSER) is set to a no-op sentinel like true, false, none, :, 0, or 1 — as Claude Code's agent view does (BROWSER=true) — openBrowser() shells out via Bun.$ and runs something equivalent to true http://localhost:NNNN. true(1) exits 0 without doing anything, the function returns success, and the server then sits in waitForDecision() forever. No browser appears, the URL isn't recoverable, and the session looks hung.

This is the BROWSER-sentinel branch of the same family as #163 (which fixed BROWSER=open / VS Code devcontainer scripts). The remaining sentinel case still affects every headless / background runner that conventionally sets BROWSER=true to disable browser launching.

Fix

packages/server/browser.ts:

  • Add isNoOpBrowserSentinel() recognising the documented no-op values (case- and whitespace-insensitive).
  • In openBrowser(), treat a sentinel-valued PLANNOTATOR_BROWSER / BROWSER as if the variable were unset, so we fall through to the platform default (open / xdg-open / cmd.exe /c start) instead of shelling out to the sentinel.
  • In shouldTryRemoteBrowserFallback(), treat the same sentinels as "no real handler configured" so the VS Code IPC fallback still fires in remote sessions where it would otherwise be skipped.

Net behaviour:

Env Before After
BROWSER=true (agent view) runs true http://... → no-op IPC fallback → platform default
BROWSER=/usr/bin/firefox spawns firefox spawns firefox (unchanged)
PLANNOTATOR_BROWSER='Google Chrome' (macOS) open -a chrome open -a chrome (unchanged)
unset platform default platform default (unchanged)

No protocol or stdout changes, no new dependencies, no surface-area additions.

Tests

Adds packages/server/browser.test.ts coverage:

  • shouldTryRemoteBrowserFallback now returns true when BROWSER / PLANNOTATOR_BROWSER are sentinels.
  • isNoOpBrowserSentinel recognises the documented values (incl. TRUE, none ) and rejects real handlers (/usr/bin/firefox, Google Chrome, open).

bun test is green (1167 pass / 0 fail). bun run typecheck is clean.

Refs #154 (BROWSER-sentinel cause; other code paths in that issue may still apply).

Fixes #724

…s can fall back

Claude Code's agent view (and similar background/headless environments) sets
$BROWSER=true to mean "do not launch a browser." The previous logic took that
literally and ran `true http://localhost:NNNN` via `Bun.$`, which exits 0 without
opening anything. The server then sits forever in waitForDecision() with no
visible UI and no way for the user to recover the URL.

Detect the documented no-op sentinels (`true`, `false`, `none`, `:`, `0`, `1`)
on both PLANNOTATOR_BROWSER and BROWSER and treat them as if the variable were
unset. This lets shouldTryRemoteBrowserFallback() reach the VS Code IPC
fallback in remote sessions and lets openBrowser() fall through to the
platform default when nothing else is configured.

Refs backnotprop#154.
@backnotprop
Copy link
Copy Markdown
Owner

Is this the fix for Claude Code's agent view ? Trying it now

@backnotprop
Copy link
Copy Markdown
Owner

great work

@backnotprop backnotprop merged commit 42c85f0 into backnotprop:main May 19, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Web UI does not open after ExitPlanMode on Windows + Claude Code (0.19.15) — server runs, plan captured

2 participants