From browser
Manages named, independently-authenticated browser sessions over a pool of playwright-mcp desks. Supports create, resume, save, close, list, cleanup, and pool subcommands.
How this command is triggered — by the user, by Claude, or both
Slash command
/browser:sessionFiles this command reads when invoked
This command is limited to the following tools:
The summary Claude sees in its command listing — used to decide when to auto-load this command
# Browser Session - Named Concurrent Sessions (Lease-Desk) Run several **named**, independently-authenticated browser sessions at once over upstream `@playwright/mcp`, which by itself gives only one browser context per connection. This is the one capability upstream lacks (microsoft/playwright-mcp#1530); CPP recovers it as a thin wrapper - no fork (issue #421, design from `docs/reviews/2026-07-03-playwright-spike-419.md`). **Arguments:** `$ARGUMENTS` - Format: `<verb> [name] [url]` - Verbs: `create`, `resume`, `save`, `close`, `list`, `cleanup`, `pool` - Examples: - `/browser:session cr...
Run several named, independently-authenticated browser sessions at once over
upstream @playwright/mcp, which by itself gives only one browser context per
connection. This is the one capability upstream lacks
(microsoft/playwright-mcp#1530); CPP recovers it as a thin wrapper - no fork
(issue #421, design from docs/reviews/2026-07-03-playwright-spike-419.md).
Arguments: $ARGUMENTS
<verb> [name] [url]create, resume, save, close, list, cleanup, pool/browser:session create gmail https://mail.google.com - start a named session/browser:session resume gmail - re-open it later (restores saved login)/browser:session save gmail - persist its cookies/localStorage/browser:session close gmail - free its desk, keep its state/browser:session list - show sessions and desk occupancyplaywright-desk-1,
playwright-desk-2, ...) is registered at Claude Code startup. Mid-session MCP
registration is impossible in Claude Code, so the pool must pre-exist - see the spike.gmail, staging-checkout). Starting one
leases a free desk; each desk runs --isolated, so its context is blank and the
session's identity lives entirely in a portable storage-state file
(.claude/playwright-state/<name>.json).close frees the desk but keeps the state file; resume
leases whatever desk is free and restores the state into it. N desks therefore
multiplex any number of named sessions, and a session survives restarts as a file.scripts/playwright-desk.py owns
the ledger (which desk each session holds) and tells you which browser_* tool
namespace to drive and where the state file lives. You drive the browser and read/write
the state file.Desk N's tools are mcp__playwright-desk-N__browser_*. The helper reports the exact
mcp_prefix for each session so you never guess.
CPP_DIR=""
for dir in ~/Projects/claude-power-pack /opt/claude-power-pack ~/.claude-power-pack; do
if [ -d "$dir" ] && [ -f "$dir/CLAUDE.md" ]; then CPP_DIR="$dir"; break; fi
done
DESK="python3 ${CPP_DIR:-.}/scripts/playwright-desk.py"
# Show pool config + occupancy (creates nothing).
$DESK pool
If no mcp__playwright-desk-* tools are available in this session, the desk pool was
not registered before startup. STOP and tell the user:
The desk pool is not registered. Run
/cpp:init(Full tier -> "browser pool"), then restart Claude Code so theplaywright-desk-*MCP servers load at startup. (/qa:testand single-session work do not need the pool - they use plain upstreamplaywright-mcp.)
Do not attempt dynamic claude mcp add mid-session - it will not take effect until restart.
Extract <verb>, and where relevant <name> and an optional <url> from $ARGUMENTS.
For list, cleanup, and pool no name is needed.
Always call the helper with --json and act on the returned object (desk, mcp_prefix,
state_file, restore, free_desks_remaining, message). On a non-zero exit the object
has "ok": false and an error slug - relay message to the user and stop.
create <name> [url]$DESK create <name> --json
no_free_desk if the pool is full - offer close or
cleanup; exit code 2 / session_exists if the name is taken - suggest resume).--isolated context). If a url was given, navigate:
mcp__<desk>__browser_navigate(url=...).save.resume <name> [url]$DESK resume <name> --json
restore is true: the session has a saved state file. RESTORE it before anything
else:
Read the reported state_file.mcp__<desk>__browser_set_storage_state with those contents (this re-injects
cookies + origin localStorage into the blank desk).url if given, else the app's origin) - the session is logged in.restore is false: no state saved yet; treat like a fresh create.save <name>$DESK save <name> --json
state_file. YOU persist:
mcp__<desk>__browser_storage_state for the seated desk -> returns the storage
state JSON (cookies + origin storage).Write that JSON verbatim to the reported state_file.close, desk restarts, and Claude Code restarts.close <name> (add --discard to also delete the saved state)$DESK close <name> --json # frees the desk, keeps the state file
$DESK close <name> --discard --json # frees the desk and forgets the session entirely
close, optionally free the browser context too:
mcp__<desk>__browser_close (or navigate to about:blank) so the desk is clean for the
next lease. The --isolated desk discards its context on the next browser_navigate
regardless, so this is best-effort hygiene.list / pool$DESK list --json # sessions + status (active/detached) + desk + idle age
$DESK pool --json # desks, which are free, idle timeout, state dir
Render a short human-readable summary for the user.
cleanup [--idle-seconds N]$DESK cleanup --json # release desks idle beyond the pool's timeout
$DESK cleanup --idle-seconds 600 --json
Releases (detaches) idle sessions so their desks return to the pool. State files are kept
SESSION_TIMEOUT.Summarize what happened for the user - e.g. which desk a session is on, how many desks are free, and the next verb they'll likely want:
## Browser Session: gmail
Seated at: playwright-desk-1 (mcp__playwright-desk-1__browser_*)
State: .claude/playwright-state/gmail.json (restored)
Pool: 1/3 desks free
Next: `/browser:session save gmail` to persist, or `/browser:session close gmail` when done.
--isolated (blank context per lease); cross-session
bleed-through is prevented by starting blank and restoring only the named session's state.
Enlarge the pool by adding desks in .claude/playwright-pool.json and registering the
matching playwright-desk-N MCP servers via /cpp:init (then restart)..claude/playwright-sessions.json; it is the lease ledger the helper
owns. The pool config .claude/playwright-pool.json is yours to edit (desk count, idle
timeout)./qa:test uses one plain upstream session; only
reach for the pool when you genuinely need several named sessions concurrently.npx claudepluginhub cooneycw/claude-power-pack --plugin browser/puppeteerConfigures session to use Puppeteer MCP for browser automation and testing instead of Playwright, auto-adding --puppeteer flag to test commands and enabling screenshots.
/browser-fallbackAutomates Microsoft portal operations (PPAC, Fabric, Azure) lacking CLI/API coverage using Playwright browser control, capturing screenshots for audit and verification.
/record-browserRecords browser sessions from Playwright spec files, capturing video and converting to GIFs. Also supports --init for new spec templates and --config.
/agent-browserAutomates browser for web interaction and testing: navigate to URLs, take screenshots, fill forms, click elements, or run tests using Playwright CLI.
/exploreExplores web pages or navigation goals using browser automation. Analyzes with accessibility snapshots and reports elements, navigation options, content found.
/sessionRecords a verifiable QA session capturing trace, video, HAR, and console logs, then renders a pass/fail report with a link to review.