`npx skills add remorses/playwriter` showed the GitHub owner in every
install command. Akarso already avoids that by hosting the skills.sh
discovery document on its own domain. Do the same on playwriter.dev.
The website now answers:
GET /.well-known/agent-skills/index.json
GET /.well-known/agent-skills/playwriter/SKILL.md
The SKILL.md bytes are imported from skills/playwriter/SKILL.md so the
served file cannot drift from git. The index includes a sha256 digest
because skills.sh checks it.
All public install commands now use:
npx -y skills add https://playwriter.dev
This covers the README, website docs, welcome page, and tutorial page.
The extension version is 0.0.113 because those HTML pages changed.
The tutorial page is also shorter than the previous daemon walkthrough.
That rewrite was already in the working tree with the skill URL change.
Session: ses_fd657bfa3ffe8lJ3G5L134SgMB
Compile executor input with vm.Script and connect dynamic import expressions to Node's main-context ESM loader. Relative module specifiers now resolve from each session working directory, while imported modules retain standard Node package resolution and permissions.
Document how local .js and .mjs helpers can accept Playwright objects, keep require and importModule as restricted alternatives, and add an integration test that imports a local module with a static built-in dependency.
Add a minor playwriter changeset with the VM execution change, user-facing example, resolution behavior, and permissions model.
Session: ses_ff521a317ffelw1fY4BzqzuaTl
New `playwriter stream start|stop|status` CLI commands and `stream.*`
executor API for streaming a browser tab live to RTMP endpoints
(X Live, Twitch, YouTube). Built for 24/7 auto-generated content:
render a page, stream it forever.
Architecture:
extension MediaRecorder (fMP4 chunks, tabCapture)
│ same WS recordingData messages as recording (no protocol
│ or extension changes, old extensions keep working)
▼
relay: StreamRelay pipes chunks to ffmpeg stdin
│ re-encode H.264 CBR + AAC, forced GOP (MediaRecorder
│ output is VFR with uncontrolled keyframes)
▼
-f flv rtmp://... (single) or tee muxer with per-output FIFO
threads + onfail=ignore (multi-destination, one encode)
ffmpeg is a child of the relay process, so streams survive CLI exit
and run indefinitely (no 15-min recording cap).
Details:
- defaults match X Live recommended encoder settings: 1920x1080,
9000 kbps, 30 fps, 3s keyframes, AAC 128k 44100Hz stereo; use
--video-bitrate 6000 --keyframe-interval 2 for Twitch
- binary/recordingData WS routing offers chunks to StreamRelay first,
falls back to RecordingRelay (tabId sets are disjoint because the
extension refuses a second capture of the same tab)
- /stream/start|stop|status endpoints under privileged auth
- stream keys never leak: destinations redacted in logs/status and
raw URLs scrubbed from ffmpeg stderr before storage
- backpressure: 32MB stdin cap kills a stalled stream instead of
buffering unbounded
- stop flow hardened after oracle review: shared stop promise for
concurrent stops, extension stop failures and forced/nonzero
ffmpeg exits report failure instead of false success
- --no-audio injects silent anullsrc track (X Live requires audio)
- tests: ffmpeg arg snapshots + real fMP4 pipe integration tests
(generate with ffmpeg testsrc, stream to local flv, ffprobe verify)
- docs: website/docs/streaming.mdx, short skill.md reference, README
Session: ses_0a8205a5cffeId4FJXly9O4aOr
Chrome's --remote-debugging-port shows a persistent automation infobar
that agents cannot dismiss, interrupting users mid-workflow. Playwriter
runs silently with no blocking dialogs, enabling fully autonomous agent
operation without user intervention.
Added to both README.md (markdown table + blockquote) and
website/src/content/index.mdx (ComparisonTable component).
Bundle the extension into the CLI so fresh AVPS and local source checkouts can start a Playwriter-ready Chrome for Testing or Chromium without separate installation steps. Also disable the packaged welcome tab, reuse Playwright\s managed Chromium fallback, surface searched browser paths on discovery failures, and document that managed browser launches already enable the tab-capture flags needed for recording on normal web pages.
All `-e` arguments in bash examples now use single quotes instead of double
quotes. This prevents bash from interpreting `$`, backticks, and backslashes
inside JS code — a major pain point for agents that construct playwriter
commands programmatically.
Changes across skill docs, README, and website copies:
- **Single quotes for one-liners**: `playwriter -s 1 -e 'await page.goto("...")'`
- **Heredoc preferred for multiline**: `<<'EOF'` disables all bash expansion
- **Quoting rules summary**: explains when to use single quotes vs heredoc vs `$'...'`
- **Rewrote mistake #6**: now explains *why* double quotes break (bash `$` expansion
silently corrupts regex like `/\$[\d.]+/` and template literals)
- **Added locator-scoped snapshot section**: shows `snapshot({ locator: page.locator("main") })`
which dramatically reduces output size from ~150 lines to ~20 lines by snapshotting
only a subtree instead of the full page
- **Added single-quote tip** to README quick start and SKILL.md stub
The locator-scoped snapshot feature already existed but wasn't documented.
Discovered during real-world Cloudflare dashboard automation where full page
snapshots were dominated by 60+ sidebar navigation links.
Closes#57
Highlights key differences: Playwriter uses your existing Chrome
(logins, extensions, cookies), can bypass captchas by disconnecting
the extension, lets you collaborate in the same browser window,
and gives full Playwright API + raw CDP access instead of a limited
shell command set.
The main selling point — using your actual Chrome session instead of
spawning a fresh browser — was buried in comparison tables halfway down.
Rewrote the tagline to highlight this upfront, added a short hero
paragraph explaining why fresh Chrome is a problem, and moved the
vs Playwright MCP comparison table to the top of the page.
The function is now exposed as `snapshot()` in the executor sandbox scope.
`accessibilitySnapshot` remains as a backward-compatible alias pointing to
the same function, so existing agents and saved commands continue to work.
Updated all code examples across skill.md, README, PLAYWRITER_AGENTS,
docs, tests, and the extension welcome page to use the shorter name.
PLAYWRITER_HOST now accepts full URLs like `https://x-tunnel.traforo.dev`
in addition to plain hostnames. Previously it always constructed
`http://${host}:19988` which broke when using traforo tunnels (HTTPS on
port 443).
Added `parseRelayHost()` utility that detects URL protocols and returns
correct HTTP/WebSocket base URLs. Updated all consumers:
- cli.ts: getServerUrl()
- mcp.ts: getLogServerUrl(), checkRemoteServer()
- executor.ts: checkExtensionStatus()
- utils.ts: getCdpUrl() (ws:// → wss:// for HTTPS hosts)
Plain hostnames still work as before (appends :19988).
Added docs/remote-access.md covering:
- Architecture: playwriter serve + traforo tunnel through Cloudflare
- Host and remote machine setup with env vars
- Use cases: remote Mac mini, user support, multi-machine, VM/devcontainer
- Security model: non-guessable URLs, token auth, localhost-only extension
endpoint, no open ports, visible automation, instant revocation
Standard Chrome DevTools Protocol HTTP discovery endpoints that allow
tools like Playwright to connect using just the HTTP URL without needing
to call getCdpUrl() first.
- /json/version returns browser info and webSocketDebuggerUrl
- /json/list returns array of connected targets
- Supports GET/PUT methods and trailing slashes for compatibility