Add in-container Playwright MCP so agents can navigate and screenshot apps they build #2
Labels
No labels
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
lz/agent-nexus#2
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Motivation
Agents that build web frontends should be able to verify their own work — that pages load, layouts aren't broken, console is clean, screenshots match expectations — without asking the operator to look. Today they can't. This issue adds a headless Chromium +
@playwright/mcpserver inside opt-in worker containers, exposed to Claude Code over HTTP MCP so the agent gets navigation, snapshot, click-by-locator, and screenshot tools.Companion to #3 (operator port forwarding). The two features are independent: agents browse their own apps internally, while the operator gets a separate forward-then-open path. There's no overlap.
Scope
--caps vision) so agents can pick whichever interaction style fits the task.Verified facts (worth knowing before implementing)
The original proposal doc got several things wrong; the implementation must use the corrected values:
@playwright/mcp(Microsoft official). Latest at time of writing is0.0.75. Fast-moving 0.x — pin a concrete version.--port N. Server exposes both/mcp(Streamable HTTP, modern) and/sse(legacy). Use/mcpfor Claude Code 2.1.x.corecaps, NOT behind--caps vision.--caps visionenables coordinate-based mouse tools (browser_mouse_click_xyetc.) — useful for development but not required for screenshots..mcp.jsonHTTP schema is{"type": "http", "url": "..."}— field name istype, nottransport.--no-sandboxwhen running as root (we do),--initto reap zombie processes, and--shm-size=1g(or--ipc=host) to keep Chromium from crashing on/dev/shmexhaustion.claudeversion before merging.Suggested implementation
1. New worker image tag
Create
worker/Dockerfile.playwright, extending the existing base image:Add to the
.forgejo/workflows/ci.ymlbuild matrix so it ships alongsidenexus-worker:latest.2. Entrypoint augmentation
worker/entrypoint-playwright.shruns the same boot sequence as the default entrypoint, then beforetmux new-session:Matches the forgejo-mcp registration shape at worker/entrypoint.sh#L91-L98.
3. Image selection at worker creation
worker_image TEXT NOT NULL DEFAULT 'nexus-worker:latest'to theworkerstable.row.worker_imageinstead ofconfig.WORKER_IMAGEwhen callingdocker.createContainer. Validate against an allowlist (nexus-worker:latest,nexus-worker-playwright:latest) on the way in from the form so the value can't escape.Init: trueandShmSize: 1073741824(1 GiB). Don't apply the shm bump to the default image — it's a real memory cost.4. Convention for screenshots
Document in
worker/CLAUDE.md(or similar) that agents should save screenshots to.agent/screenshots/<timestamp>-<short-desc>.pnginside the worktree so the operator can find them.Out of scope
--isolatedis available later if it becomes a problem.Verification
docker build -f worker/Dockerfile.playwright -t nexus-worker-playwright:latest worker/succeeds in CI.list mcp serversand confirmplaywrightis listed.python3 -m http.server 5173), have Claude navigate tohttp://localhost:5173via Playwright, take a screenshot, confirm the file lands at.agent/screenshots/..../dev/shmis sized correctly inside the container:df -h /dev/shmshows ~1 GiB.Open questions
Adding a related use case discovered while smoke-testing PR #31 (artifacts):
When an agent works on a UI feature of Nexus itself (operator-facing screens), the natural end-of-feature step is to drive the 10–15-step manual smoke autonomously instead of asking the operator to click through it. With this issue's Playwright MCP baked in, that becomes possible for any UI the agent runs locally (
pnpm dev,python3 -m http.server, etc.) — but the Nexus-testing-Nexus case still needs a Nexus instance the agent can reach.Two paths to make that work:
Practical implication for this issue: the proposed scope is correct as-is — single Playwright MCP per container,
--caps visionenabled, screenshots in.agent/screenshots/. The dind companion is purely additive: it lets the MCP point at a localhost URL that the agent itself stood up, which is already the dominant use case described here.The two issues together would let agents close the smoke-test loop for any feature they ship — Nexus-internal or otherwise. Worth implementing them in either order; they don't depend on each other.