Problem
Today, show --port=<N> starts the dashboard HTTP server but skips acquireSingleton and startApp. This means a port-mode daemon:
- Serves the UI over HTTP, but never installs the unix-socket connection handler
- Cannot receive
kill, reveal, or annotate requests from CLI clients
- Doesn't participate in singleton ownership — a second
show can spawn a competing instance
Separately, show --annotate calls runInSession(...), which opens a second, separate dashboard (openDashboardForContext → its own window) instead of routing to the one the user already has open.
Proposed solution
-
Unify port and windowed modes through the singleton. Delete the port short-circuit in openDashboardApp; route both modes through acquireSingleton + startApp. Add a serveDashboardHeadless opener (no Chromium window) so --port serves the dashboard over HTTP while owning the singleton socket.
-
startApp changes. Accept an open function parameter (defaults to innerOpenDashboardApp), return the dashboard state, and fire-and-forget reveal() instead of awaiting it — reveal awaits connectionLanded, which blocks indefinitely in headless mode when no browser tab is connected yet.
-
Route show --annotate to the running daemon. Replace the runInSession detour with a spawn that dials the daemon's unix socket via --annotate, so annotation reuses the single open dashboard.
No new protocol, tokens, or HTTP endpoints — the existing unix socket (dashboardSocketPath()) is sufficient.
Prototype / fork
I have a working prototype as a patch-package patch against the built playwright-core bundle:
Branch: null-hype/playwright-cli@claude/dazzling-davinci-zq89f1
The branch includes:
patches/playwright-core+1.61.0-alpha-1781023400000.patch — the compiled JS patch
docs/upstream-headless-dashboard.md — the equivalent TypeScript source changes for an upstream PR to microsoft/playwright
Verified behavior
show --port=0 prints Listening on <url> + Waiting for dashboard connection + Dashboard is running pid=<N> and serves HTTP
- A second
show returns the same daemon pid (singleton ownership works)
show --annotate routes to the running daemon via the unix socket instead of spawning a second dashboard
- First annotate blocks until a browser tab is connected (by design — nothing to annotate with nobody watching)
Typical workflow (headless / devcontainer)
# Terminal 1 — start the long-lived daemon
playwright-cli show --port=3000
# Browser — open http://localhost:3000
# Terminal 2 — agent uses playwright-cli normally; dashboard shows live sessions
# When the agent calls `show --annotate`, the review appears in the already-open tab
Problem
Today,
show --port=<N>starts the dashboard HTTP server but skipsacquireSingletonandstartApp. This means a port-mode daemon:kill,reveal, orannotaterequests from CLI clientsshowcan spawn a competing instanceSeparately,
show --annotatecallsrunInSession(...), which opens a second, separate dashboard (openDashboardForContext→ its own window) instead of routing to the one the user already has open.Proposed solution
Unify port and windowed modes through the singleton. Delete the
portshort-circuit inopenDashboardApp; route both modes throughacquireSingleton+startApp. Add aserveDashboardHeadlessopener (no Chromium window) so--portserves the dashboard over HTTP while owning the singleton socket.startAppchanges. Accept anopenfunction parameter (defaults toinnerOpenDashboardApp), return the dashboard state, and fire-and-forgetreveal()instead of awaiting it —revealawaitsconnectionLanded, which blocks indefinitely in headless mode when no browser tab is connected yet.Route
show --annotateto the running daemon. Replace therunInSessiondetour with a spawn that dials the daemon's unix socket via--annotate, so annotation reuses the single open dashboard.No new protocol, tokens, or HTTP endpoints — the existing unix socket (
dashboardSocketPath()) is sufficient.Prototype / fork
I have a working prototype as a
patch-packagepatch against the builtplaywright-corebundle:Branch:
null-hype/playwright-cli@claude/dazzling-davinci-zq89f1The branch includes:
patches/playwright-core+1.61.0-alpha-1781023400000.patch— the compiled JS patchdocs/upstream-headless-dashboard.md— the equivalent TypeScript source changes for an upstream PR tomicrosoft/playwrightVerified behavior
show --port=0printsListening on <url>+Waiting for dashboard connection+Dashboard is running pid=<N>and serves HTTPshowreturns the same daemon pid (singleton ownership works)show --annotateroutes to the running daemon via the unix socket instead of spawning a second dashboardTypical workflow (headless / devcontainer)