Skip to content

feat(claude-code): make agent-browser the default browser tool, via an image-managed skill - #175

Merged
gatezh merged 4 commits into
masterfrom
feat/devcontainer-browser
Oct 8, 2026
Merged

gatezh merged 4 commits into
masterfrom
feat/devcontainer-browser

Conversation

@gatezh

@gatezh gatezh commented Sep 25, 2026 •

Copy link
Copy Markdown
Owner

What

Makes agent-browser the default browser tool for agents in both claude-code images, with Playwright as the fallback. This is done with one skill that the image ships, instead of a copy in every project.

Change Where
sandbox-playwright is rewritten and renamed devcontainer-browser, and ships at /etc/claude-code/.claude/skills/devcontainer-browser/, Claude Code's managed skills location. Every project gets it with nothing to copy, and it wins a name clash with a project skill. claude-code/.devcontainer/managed-skills/, Dockerfile
A claudeMd routing rule, loaded in every session (projects can't exclude it). managed-settings.json
permissions.deny blocks agent-browser install and upgrade: install --with-deps runs sudo apt-get, and upgrade bypasses the Renovate pin. agent-browser is not pre-allowed (see Notes); the README gives a one-line per-project opt-in. managed-settings.json, README
AGENT_BROWSER_CONFIG=/etc/agent-browser/config.json pins agent-browser's config. Otherwise the CLI auto-loads ./agent-browser.json, which can declare plugin executables and Chromium args, so a repo could run code through any agent-browser command. The image config turns on contentBoundaries and maxOutput (upstream's recommended agent config). agent-browser.json, Dockerfile
agent-browser moves from default into the shared stage, so the sandbox target has it too. It keeps master's cache mount and per-arch binary trim. The managed settings, skill and config COPYs come last in shared, so editing them doesn't rebuild Chromium or Claude Code. Dockerfile
The CI verify commands for both targets check agent-browser, both env vars, the managed skill, the image config, and the new managed-settings keys. ci.yml
devcontainer-upstream-sync 1.3.0 lists .claude/skills/sandbox-playwright/ as a retired path. Workflow 2 deletes it after confirming with the user. A leftover copy has a different name, so it would load alongside the new skill and contradict it. skill
README: a "Built in: browser skill" section, a migration note, and the "default target only" notes for agent-browser removed. It also fixes "Default-only: passwordless sudo", since sudo has been in both targets since the shared-layer refactor. README

The skill's routing

  • agent-browser: open the app, look, click, type, take screenshots, read the console. Measure viewport, DPR (set viewport <w> <h> 2), which srcset candidate loaded, and layout. Scripted multi-step checks, isolated sessions, network mocking and HAR, accessibility audits, React render profiling.
  • Playwright: a project's committed @playwright/test suite, vitest browser mode and Storybook tests, Firefox or WebKit, or command -v agent-browser finds nothing.

It keeps what made sandbox-playwright useful: the per-consumer executablePath wiring matrix, never installing or downloading a browser, discovering the dev-server port instead of assuming one, and the find pattern that works under RTK. For command usage it defers to agent-browser skills get core, which the CLI serves for the installed version, so the skill doesn't go stale on Renovate bumps.

Verification

  • Merged master (shared-layer refactor perf(claude-code): install Claude Code last and cache CI layers #183/#adeef37, agent-browser 0.38.2, Claude Code 2.1.294) with no rebase or force-push.
  • Both targets built locally (arm64). The CI verify string for each target was extracted from ci.yml and passes in its image, including after the final commit.
  • In the built default image, against a local page with agent-browser 0.38.2:
    • session id --scope worktree output is unaffected by content boundaries, so the skill's export AGENT_BROWSER_SESSION="$(…)" works;
    • get text and eval --stdin output is wrapped in AGENT_BROWSER_PAGE_CONTENT markers;
    • set viewport 390 844 2 gives devicePixelRatio 2;
    • a malformed ./agent-browser.json is ignored. With AGENT_BROWSER_CONFIG unset, the same file warns (control), so the pin is what skips it (load_config returns early).
  • Layer cache: a one-byte SKILL.md edit reran only the last two COPY layers; Chromium, Claude Code and agent-browser stayed CACHED.
  • hadolint v2.12.0 (the version hadolint-action@v3.0.0 uses) with .hadolint.yaml, and actionlint, pass.
  • Earlier, in a claude-code default container (agent-browser 0.38.1) against a live Next.js site: srcset picks at DPR 2, console, errors, close, and open --enable react-devtools followed by react renders start/stop.

Not covered

  • The Playwright MCP plugin stays for now. Removing it is Remove the Playwright MCP plugin once agent-browser is the default browser tool (review 2026-11-25) #174, with a review on 2026-11-25. The skill tells agents not to reach for it while agent-browser is available.
  • ralphex-fe has Chromium and its own managed-settings.json but no agent-browser. The same pattern applies there, as a follow-up.
  • Consumers keep their sandbox-playwright copy until they delete it; the migration note and upstream-sync's retired-path entry cover that.
  • agent-browser under the claude-sandbox firewall hasn't been exercised. It drives local Chromium over CDP, so no new domains should be needed, but worth watching.

Notes

  • Why no pre-allow: Bash(agent-browser *) approves any arguments. --config <file> overrides the config pin (the CLI flag is checked first), and --executable-path / --args start any binary, so a page that tricks the agent could run code without a prompt. Prefix rules can't block that reliably (agent-browser --json install gets past a deny rule). Instead, the first agent-browser command in a project prompts and shows the full command; "don't ask again" keeps the answer, or a trusted project can opt in with one line in .claude/settings.local.json.

…n image-managed skill

Replaces the per-project sandbox-playwright skill with devcontainer-browser,
shipped by the image at /etc/claude-code/.claude/skills/ (Claude Code's
managed skills location). Every project gets it without a copy, and it wins
a name clash with a project skill.

- devcontainer-browser: agent-browser first, for opening the app, UI checks,
  screenshots, DPR/srcset measurement, scripted checks and React render
  profiling. Playwright only for a project's committed @playwright/test
  suite, vitest browser mode or Storybook tests, Firefox/WebKit, or a
  missing agent-browser. Keeps the executablePath wiring matrix and the
  never-download-a-browser rules. Defers agent-browser command docs to the
  version-matched `agent-browser skills get core`.
- managed-settings.json: a claudeMd routing rule loaded in every session,
  and permissions.allow for Bash(agent-browser:*).
- agent-browser moves from the default target into base, so the sandbox
  target has it too; sandbox also sets AGENT_BROWSER_EXECUTABLE_PATH.
- CI verify checks agent-browser, its env var, the managed skill, and both
  new managed-settings keys on both targets.
- devcontainer-upstream-sync 1.3.0: sandbox-playwright is a retired path
  (delete), since a leftover copy would load alongside the new skill.
- README: built-in browser skill section, migration note, and the
  "default target only" notes for agent-browser removed.

Removing the Playwright MCP plugin is separate: #174 (review 2026-11-25).
gatezh added 3 commits October 8, 2026 11:51
…rowser

# Conflicts:
#	.github/workflows/ci.yml
#	claude-code/.devcontainer/Dockerfile
…ached

- Pin agent-browser's config with AGENT_BROWSER_CONFIG=/etc/agent-browser/config.json.
  Without it, the CLI auto-loads ./agent-browser.json, which can declare plugin
  executables and Chromium args, so a repo could run code under the
  pre-allowed Bash(agent-browser *) rule. The image config turns on
  contentBoundaries and maxOutput, following upstream's recommended agent config.
- Managed permissions.deny for `agent-browser install` / `upgrade`: install
  --with-deps runs sudo apt-get, and upgrade bypasses the Renovate pin.
- Write the allow rule in the space form the permissions docs use.
- Move the managed settings/skill COPYs to the end of the shared stage, so
  editing the skill no longer rebuilds Chromium and Claude Code.
- Skill: drop the `ss` step (iproute2 is sandbox-only, so in the default
  target it silently printed nothing), and replace the maintainer section,
  which repeated the README and told agents to delete project files.
- upstream-sync: add the Workflow 2 step for `retired: delete`, confirmed
  with the user like every other adopt step.
Bash(agent-browser *) approves any arguments. --config overrides the
AGENT_BROWSER_CONFIG pin (the CLI flag is checked first), and
--executable-path / --args start any binary, so a page that tricks the agent
could run code without a prompt. Prefix rules can't block these reliably
(`agent-browser --json install` gets past the deny rules).

The image keeps the deny rules, the config pin and the skill routing; agent-browser
prompts on first use. The README gives a one-line per-project opt-in in
.claude/settings.local.json for trusted projects.
@gatezh
gatezh merged commit bbf32b7 into master Oct 8, 2026
11 checks passed
gatezh added a commit that referenced this pull request Oct 8, 2026
…config changes

#175 added two files the image copies in, managed-skills/devcontainer-browser/SKILL.md
and agent-browser.json, but build-claude-code.yml's push paths didn't include them.
An edit to either alone would merge to master and never be published.
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.

1 participant