Open URLs on Host Browser from Claude Code Devcontainers

URLs opened inside a devcontainer appear on your host browser. OAuth redirects, preview links, and documentation just work.

Fix xdg-open not working in devcontainers

When code inside a devcontainer tries to open a URL — whether it’s an OAuth redirect, a documentation link, a test coverage report, or a local dev server preview — nothing happens. There’s no browser inside the container. xdg-open, open, and $BROWSER all fail silently or error out.

This breaks:

$BROWSER replacement for containers

human-browser is a drop-in replacement for xdg-open and the system browser inside devcontainers. Set it as $BROWSER in your container, and any tool that opens URLs will have those URLs open on your host machine instead.

# In the devcontainer
export BROWSER=human-browser

# Now any tool that opens URLs works
claude  # Claude Code can open links
npm start  # Dev server preview opens on host
pytest --cov --cov-report=html  # Coverage report opens on host

How it works

human-browser sends the URL to the human daemon running on the host via the same TCP connection used for all container-to-host communication. The daemon opens the URL in the host’s default browser.

[Devcontainer]                          [Host]
$BROWSER → human-browser               human daemon (:19285)
    |  TCP                                  |  opens URL in
    └───── :19285 ──────────────────────────┘  default browser

Token-based authentication ensures only authorized containers can open URLs on the host.

Setup

The treehouse devcontainer Feature installs human-browser and sets $BROWSER automatically:

{
  "features": {
    "ghcr.io/stephanschmidt/treehouse/human:1": {}
  },
  "remoteEnv": {
    "HUMAN_DAEMON_ADDR": "localhost:19285",
    "HUMAN_DAEMON_TOKEN": "a1b2c3...",
    "BROWSER": "human-browser"
  }
}

Or set it manually:

export BROWSER=human-browser

Claude Code integration

Claude Code frequently needs to open URLs — for authentication, for showing documentation, for previewing changes. Inside a devcontainer without human-browser, these operations fail.

With $BROWSER=human-browser, Claude Code’s browser interactions work transparently. Authentication flows complete. Links open. Your workflow isn’t interrupted by “cannot open browser” errors.

Works with any tool

human-browser follows the standard $BROWSER convention. Any Linux tool that respects $BROWSER or calls xdg-open works:

If the tool opens URLs, human-browser handles it.