feat(agents): a browser subagent checks UI changes in a real browser, and a pipeline step uses it (#17) #91

Merged
cmoriarty merged 4 commits from claude/playwright-test-subagent into main 2026-09-27 15:54:50 -04:00
Owner

Closes #17.

Braid's agents could run Playwright spec files but not drive a browser and look at the result. This adds a fourth read-only subagent, browser, that drives headless Chromium through Playwright MCP, and a pipeline step, agent.test.browser, that uses it to check a UI change before the commit.

Changes

  • browser subagent (on by default): 13 of Playwright MCP's 24 tools (9,251 chars of schema instead of 17,678), no whole-page snapshot, no shell, no edits. It reports PASS / FAIL / UNCLEAR with screenshot names and quoted console errors. No other agent gets the browser.
  • Measured on opencode 1.18.21: a task child inherits its parent prompt's tool map, so Playwright is switched off in each agent's config rather than in any prompt; tools_for no longer sends playwright*.
  • Pinned server: @playwright/mcp@0.0.80 (Chromium 1243, the image's revision), pre-installed in the image (OSF_PLAYWRIGHT_MCP), headless and isolated, screenshots to <run>/screenshots. The self-check fails on a version drift.
  • Run plugin: drops filename from Playwright calls (a relative one wrote into the worktree) and refuses a second browser task while one is busy.
  • Guidance: implementation steps are told to serve the app on $PREVIEW_PORT and give browser the URL.
  • agent.test.browser: in default, git-flow, minimalist, git-flow-hotfix and quick-fix, after the last test lane; runs only when UI files changed, the app can be served and the run has browser (new browser_check condition). It writes .osf/test/browser.json; a report still saying fail fails the step.
  • Console: browser calls read browser · <action> in the subagents panel with each screenshot under its call, served by GET /api/runs/{id}/screenshots/{name} (screenshot-shaped names only).
  • Merged with main after agent-step-names; the step follows agent.test.unit / agent.test.e2e.

Verification

  • Fast lane and full lane (OSF_URL at a --status fixture) pass on the merged tree: backend 1832, UI unit 431, browser 99/99.
  • tests/integration/test_browser_live.py (-m needs_opencode) against opencode 1.18.21: the primary has no browser tools, browser has exactly the allowlist, a second browser task is refused while the first reports, and the screenshot lands outside the worktree. It fails when the prompt-level glob or the filename drop is put back.
  • The subagents panel checked in a real browser at desktop and phone widths.
  • One earlier full-lane run had agent-view.spec.ts "flows a few characters a frame" fail once on a loaded machine; it passed 3/3 alone and in every later run.

Not verified

  • qwen3.8-27b actually driving the browser (every run used a scripted fake model).
  • The Docker image build with the new npm install -g.
  • A saved settings roster from before this change lacks browser, so its check is skipped until browser is ticked in settings.

🤖 Generated with Claude Code

Closes #17. Braid's agents could run Playwright spec files but not drive a browser and look at the result. This adds a fourth read-only subagent, `browser`, that drives headless Chromium through Playwright MCP, and a pipeline step, `agent.test.browser`, that uses it to check a UI change before the commit. ## Changes - **`browser` subagent** (on by default): 13 of Playwright MCP's 24 tools (9,251 chars of schema instead of 17,678), no whole-page snapshot, no shell, no edits. It reports PASS / FAIL / UNCLEAR with screenshot names and quoted console errors. No other agent gets the browser. - **Measured on opencode 1.18.21:** a `task` child inherits its parent prompt's tool map, so Playwright is switched off in each agent's config rather than in any prompt; `tools_for` no longer sends `playwright*`. - **Pinned server:** `@playwright/mcp@0.0.80` (Chromium 1243, the image's revision), pre-installed in the image (`OSF_PLAYWRIGHT_MCP`), headless and isolated, screenshots to `<run>/screenshots`. The self-check fails on a version drift. - **Run plugin:** drops `filename` from Playwright calls (a relative one wrote into the worktree) and refuses a second `browser` task while one is busy. - **Guidance:** implementation steps are told to serve the app on `$PREVIEW_PORT` and give `browser` the URL. - **`agent.test.browser`:** in `default`, `git-flow`, `minimalist`, `git-flow-hotfix` and `quick-fix`, after the last test lane; runs only when UI files changed, the app can be served and the run has `browser` (new `browser_check` condition). It writes `.osf/test/browser.json`; a report still saying fail fails the step. - **Console:** browser calls read `browser · <action>` in the subagents panel with each screenshot under its call, served by `GET /api/runs/{id}/screenshots/{name}` (screenshot-shaped names only). - Merged with `main` after `agent-step-names`; the step follows `agent.test.unit` / `agent.test.e2e`. ## Verification - Fast lane and full lane (`OSF_URL` at a `--status` fixture) pass on the merged tree: backend 1832, UI unit 431, browser 99/99. - `tests/integration/test_browser_live.py` (`-m needs_opencode`) against opencode 1.18.21: the primary has no browser tools, `browser` has exactly the allowlist, a second browser task is refused while the first reports, and the screenshot lands outside the worktree. It fails when the prompt-level glob or the filename drop is put back. - The subagents panel checked in a real browser at desktop and phone widths. - One earlier full-lane run had `agent-view.spec.ts` "flows a few characters a frame" fail once on a loaded machine; it passed 3/3 alone and in every later run. ## Not verified - qwen3.8-27b actually driving the browser (every run used a scripted fake model). - The Docker image build with the new `npm install -g`. - A saved settings roster from before this change lacks `browser`, so its check is skipped until `browser` is ticked in settings. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Braid's agents could run Playwright spec files through bash but could not drive a browser and
look at what was on screen. Now a fourth read-only subagent, `browser`, drives headless Chromium
through Playwright MCP, and `agent.test.browser` has it check a UI change before the commit.

- Measured on opencode 1.18.21: a task child inherits its parent prompt's tool map, so
  Playwright is switched off per agent in the run config, not in any prompt. `browser` gets 13
  of the server's 24 tools (9,251 chars of schema, not 17,678); no whole-page snapshot.
- The server is pinned to @playwright/mcp@0.0.80 (Chromium 1243, as the image installs),
  pre-installed in the image, headless and isolated, and writes screenshots to <run>/screenshots.
- The run's plugin drops `filename` from Playwright calls (one wrote into the worktree) and
  refuses a second `browser` task while one is busy.
- Implementation steps are told to serve the app on $PREVIEW_PORT and hand `browser` the URL.
- agent.test.browser runs in default, git-flow, minimalist, git-flow-hotfix and quick-fix when UI
  files changed, the app can be served and the run has `browser`; a report still saying fail
  fails the step.
- The console titles browser calls `browser · <action>` and shows each screenshot under its
  call, served by GET /api/runs/{id}/screenshots/{name}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
agent-step-names renamed the test lanes to agent.test.*; agent.test.browser now follows
agent.test.unit (default) and agent.test.e2e (minimalist, quick-fix), and the change's
agent-delegation and pipeline-steps deltas are rebuilt on the renamed specs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Archive browser-subagent
Some checks failed
deploy / deploy (push) Has been cancelled
b5a241a81d
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cmoriarty deleted branch claude/playwright-test-subagent 2026-09-27 15:54:50 -04:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cmoriarty/braid!91
No description provided.