Task browser
The task browser is the headless browser a swarm session reaches through the playwright-cmd MCP server. It runs as python -I -m scripts.profiles.browser, a proxy in front of an upstream playwright-mcp node process. Two changes keep it from costing memory in sessions that never browse:
- It starts on the first tool call. Opening a session, and the harness listing its tools, no longer launch Playwright or
playwright-mcp(#4313). - Lanes that never browse do not mount it. Engineer, CI and planner homes render without the proxy; master, frontend, QA and documentation homes keep it (#4540).
Which homes mount it
The profile render decides per chain, the same way for Claude, Codex and Copilot homes.
| Chain contains | playwright-cmd mounted | Other playwright* MCP servers | Playwright Claude plugin |
|---|---|---|---|
master, qa or documentation | Yes | Removed, except playwright-ext-* | Disabled |
engineer, cicd or planner with the frontend overlay | Yes | Removed, except playwright-ext-* | Disabled |
engineer, cicd or planner alone | No | Removed, except playwright-ext-* | Disabled |
| No swarm role | No change | Kept as the bundle layers define them | Kept |
A playwright-ext-<account> server, the logged in extension browser an overlay declares, is never removed. The proxy’s presence is part of the render stamp, so a home rendered before the lane change renders again on its next launch.
The mounted entry carries no settings of its own:
{
"mcpServers": {
"playwright-cmd": {
"command": "/home/<user>/dev/tcc-ecosystem/.venv/bin/python",
"args": ["-I", "-m", "scripts.profiles.browser"]
}
}
}
The command is the detected workspace interpreter, or the interpreter running the render when none is found. To give an engineer, CI or planner seat the browser, run its task with the frontend profile (agentihooks ledger --slug <slug> task set <id> profile=frontend).
Start on first call
| Moment | What runs |
|---|---|
| Session opens | The Python proxy only. Playwright and playwright-mcp stay unstarted. |
Harness lists tools (tools/list) | Answered from the tool list cache when its key matches. With no matching cache, the upstream starts as on a first tool call, its list is written to the cache and the upstream stays running. |
First tool call, or a tools/list cache miss if that comes first | Playwright resolves the Chromium executable, then playwright-mcp starts headless and isolated with a 1920x1080 viewport. |
| Later tool calls | Reuse the same playwright-mcp session. |
Screenshots and other files a tool names land in the task folder: the swarm task workspace (AGENTIHOOKS_SWARM, AGENTIHOOKS_SWARM_TASK, or the master folder when no task is set), else ~/.agentihooks/browser. A filename argument keeps only its base name, so a call cannot write outside that folder.
Tool list cache
The cache is one file shared by every session on the machine: ~/.agentihooks/browser/tools.json.
{
"key": "/home/<user>/.nvm/versions/node/v26.7.0/lib/node_modules/@playwright/mcp/cli.js 1791681289445995681",
"tools": [{"name": "browser_close", "...": "..."}]
}
The key is the resolved path of the playwright-mcp on PATH and its modification time in nanoseconds. Upgrading or reinstalling playwright-mcp changes the key, and the next tools/list refreshes the file. An unreadable, malformed or mismatched file counts as a miss. With no playwright-mcp on PATH, nothing is cached and every tools/list starts the upstream, as before the change.
Inspect the cache and the live processes:
jq -r '.key, (.tools | length)' ~/.agentihooks/browser/tools.json
ps -eo pid,rss,args | grep -E 'scripts.profiles.browser|playwright-mcp' | grep -v grep
An idle session shows one scripts.profiles.browser line of about 55 MB resident and no playwright-mcp child. A child appears only after that session calls a browser tool.
Measured effect
Before #4313, at 21 live agent sessions, the browser helper held 1843 MB in all (node child 1070 MB, Python proxy 773 MB) with swap at 4011 of 4096 MB. Over 24 hours of transcripts, browser tools were called by 0 of 52 CI sessions, 2 of 177 engineer sessions and 6 of 284 master sessions; the engineer calls came from frontend homes.
After #4313 applied, the browser node helper was gone from every session started since then: browser memory per session fell from 37 to 120 MB to 0. Median resident memory per Claude session did not fall (engineer 392.5 to 402 MB, CI 447 to 458 MB), and swap stayed full (4096 to 4095 MB at 23 and 29 live sessions), because the Python proxy still ran at about 56 MB in every lane. #4540 removed that proxy from engineer, CI and planner homes.
Limitations
- The cache key covers the
playwright-mcpbinary only. A change to the launch flags that alters the tool set needs a binary update or the cache file removed. - A failed upstream start ends the proxy, and the session loses its browser tools until it restarts.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
A seat has no playwright-cmd tools | Its chain is engineer, CI or planner without the frontend overlay | Set the task’s profile to frontend |
Browser tools are missing or stale after a playwright-mcp upgrade on another path | The cache key matches the binary still first on PATH | Fix PATH, or delete ~/.agentihooks/browser/tools.json |
Every session starts playwright-mcp at once | No playwright-mcp on PATH, so nothing is cached | Install playwright-mcp through agentihooks deps ensure |
| The first browser call, or a tool listing after a cache miss, is slow | Playwright and the upstream start on that request | Expected once per session |
| Browser tools stop answering in a session | The upstream failed to start and the proxy ended | Restart the session; read the harness MCP log for the start error |