agentsclimarketplace

Playwright cli setup

Skill AgentiaPT/vela-slides/.claude/skills/playwright-cli-setup

THE DEFAULT tool for ad-hoc / interactive Vela browser work — explore or test the app, screenshot a state, reproduce a bug, poke a selector, drive presenter/gallery flows, verify a UX change, run bench/vela-interaction-bench.sh. Drives a live offline Vela render via Playwright CLI (@playwright/cli), a persistent warm browser you steer one command at a time (open, snapshot, click, press, eval), inspecting state + output between steps. Prefer this over the committed `vela-drive.js` scripts (skill: vela-live-render) — those are for repeatable, committed automation only (CI, benchmark, recorded demo), NOT one-off exploration. Also prefer over writing throwaway Playwright .js files. Covers container setup (blocked CDNs, file:// block, pinned Chromium) and per-agent session isolation for parallel browser tests.From its SKILL.md

Install
npx -y skills add AgentiaPT/vela-slides --skill playwright-cli-setup

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

9.4 KB, ~2.3k tokens by cl100k_base, as published. Nobody here has run it

Playwright CLI ↔ Vela setup (this container)

@playwright/cli keeps a persistent browser as a background session (-s=<name>) and you drive it one command at a time — open, goto, snapshot, click e15, press ArrowRight, eval "…" — reading state between steps instead of running a blind script. window globals survive across invocations, so a helper installed once (e.g. a timing harness) stays live. Output (snapshots, console logs) is written to .playwright-cli/ (gitignored); read only what you need.

It is a different package from playwright and from Playwright MCP. Prefer it here for interactive/exploratory driving; it's cheaper on context than MCP (nothing streams into the conversation unless you read a file).

Setup — do this once per fresh container

1. Restore the locked deps, then install the CLI isolated (see Supply-chain safety below for why it's not committed):

npm ci --ignore-scripts                                                   # locked tree first
npm install --no-save --no-audit --no-fund --ignore-scripts @playwright/[email protected]

2. Config is already committed at .playwright/cli.config.json (the default config path, read from the repo root). It solves the two things that otherwise fail:

{
  "allowUnrestrictedFileAccess": true,
  "browser": {
    "browserName": "chromium",
    "launchOptions": {
      "executablePath": "/opt/pw-browsers/chromium-1194/chrome-linux/chrome",
      "headless": true,
      "args": ["--no-sandbox"]
    }
  }
}

Recreate it if missing. Update executablePath if the image's Chromium moves (ls /opt/pw-browsers/).

Supply-chain safety (why @playwright/cli is NOT committed)

This repo pins its supply chain via a committed package-lock.json (exact versions + sha512), npm ci --ignore-scripts in CI, npm audit gating, and a 7-day release-cooldown (.npmrc: ignore-scripts=true, see docs/SECURITY.md).

@playwright/[email protected] transitively depends on a days-old alpha of playwright (nested in its own node_modules, so it does not override the repo's locked top-level playwright). Committing it would pull that fresh alpha into the audited, shipped dependency tree — against the cooldown policy. So it is deliberately kept out of package.json / package-lock.json and installed as an isolated, dev/test-only tool. The install is hardened accordingly:

  • @playwright/[email protected] — exact version pin, no range (no surprise upgrades).
  • --ignore-scripts — blocks pre/post-install hooks (belt-and-suspenders with .npmrc: ignore-scripts=true); the #1 npm supply-chain vector.
  • --no-save — never writes to package.json/package-lock.json; the audited, shipped tree stays exactly as locked. npm still verifies the registry sha512 on download.
  • Ephemeral & unshippednode_modules/ is gitignored; the CLI never enters the Vela artifact, a release, or CI's locked install.
  • Always run npm ci --ignore-scripts first so the top-level playwright/etc. match the lockfile (an ad-hoc npm install earlier can drift them).

Before bumping the pin, check the new version's transitive playwright dep (npm view @playwright/cli@<v> dependencies) and prefer a version that resolves a stable playwright once one ships.

Drive a Vela deck

# 1. Build an OFFLINE render (transpiled, deck injected via STARTUP_PATCH).
#    Do NOT serve.py / esm.sh here — the React/lucide CDNs are blocked.
node tools/vela-dev/scripts/render-offline.js examples/vela-demo.vela /tmp/vout

# 2. Open a persistent session on the render (file:// works via the config).
npx playwright-cli -s=vela open "file:///tmp/vout/render.html"

# 3. Wait for hydration (~2–4s; offline app.js transpiles then mounts).
npx playwright-cli -s=vela eval "({b:!!window.__velaBooted, blocks:document.querySelectorAll('[data-block-type]').length})" --raw

# 4. Drive it. Examples:
npx playwright-cli -s=vela press f            # enter presentation (auto-selects 1st module)
npx playwright-cli -s=vela press ArrowRight   # next slide
npx playwright-cli -s=vela screenshot --filename=/tmp/slide.png
npx playwright-cli -s=vela eval "(document.querySelector('[data-block-type=heading]')||{}).textContent" --raw

# 5. Housekeeping.
npx playwright-cli list
npx playwright-cli -s=vela close
npx playwright-cli kill-all        # nuke stale/zombie browsers

Tip: node_modules/.bin/playwright-cli skips npx resolution overhead in loops.

Parallel agents — isolating concurrent browser tests

Multiple agents can drive Vela at once, but they share one machine-wide session registry (~/.cache/...) and one per-cwd output dir. Verified isolation ladder, weakest → strongest:

axishowwhat it isolatesgotcha
session name-s=agentA vs -s=agentBthe browser + page state (independent — one advancing slides doesn't move the other)same registry & same .playwright-cli/ output dir
registryPWTEST_DAEMON_SESSION_DIR=/tmp/agentA-daemon (per agent)the whole session daemon — an agent's sessions are invisible to another's list/close-all/kill-allmust set it on every command for that agent
workspace/cwdrun each agent from its own dir / git worktreesession namespace and the .playwright-cli/ output dir (both keyed off findWorkspaceDir(cwd))needs a separate checkout

Recommended patterns

  • Best: give each parallel agent its own git worktree (the Agent tool's isolation: "worktree"). Different cwd ⇒ different workspace ⇒ separate session namespace and separate .playwright-cli/ output, for free. Add a unique -s=<name> per agent too.
  • Same cwd: give each agent a unique -s=<name> and a unique PWTEST_DAEMON_SESSION_DIR — otherwise one agent's close-all/kill-all kills every agent's browsers (the single biggest footgun). Output files still land in the shared .playwright-cli/ (timestamped names rarely collide, but they intermix).

Two things that make this easy here: the offline file:// render needs no port, so parallel sessions never collide on a port (unlike serving over HTTP); and each deck can render to its own /tmp/<agent>-render dir. Cost: each session is a full Chromium (~200-300 MB RAM) — cap concurrency to the box, and never use the global close-all/kill-all from a parallel agent unless its registry is isolated.

Vela-specific hooks & selectors (for eval / interaction)

whathow
boot donewindow.__velaBooted === true and #root innerText non-empty
headless UI batteryawait window.__velaRunUITests() (see part-uitest.jsx)
current slide blocks[data-block-type] elements (text signature changes on nav)
current heading[data-block-type=heading]
in presentation?<header> is removed while presenting
gallery open?[data-testid=gallery-close] present
gallery scroll rail[data-scroll-container]
enter/exit presentkey f (or F5); Escape exits
next / prev slideArrowRight / ArrowLeft
open gallerykey g

Note: window.__velaGetCurrentSlide is gated behind local mode (off in offline renders) — use the DOM signals above instead.

Gotchas already solved (don't rediscover)

  • file:// is blocked by default"Access to file: protocol is blocked". Fixed by allowUnrestrictedFileAccess: true in the config (or env PLAYWRIGHT_MCP_ALLOW_UNRESTRICTED_FILE_ACCESS=1). Config is read at open time — if you change it, close and re-open the session.
  • Bundled playwright-core wants a newer Chromium than the image ships (expects ~1229, image has 1194) → the CDN download is blocked, so the config's executablePath points at the pinned build. Don't run playwright install.
  • CDNs (esm.sh / React / lucide / Babel) are blocked → never use serve.py's default importmap HTML; always render-offline.js (vendored UMD + Node transpile).
  • One harmless console error on every load (ERR_INVALID_URL / font fetch) — ignore it; the app renders fully.
  • Don't pkill background jobs from a Bash tool here — the sandbox may SIGKILL the shell (exit 144). Use playwright-cli close / kill-all for browsers.

Ready-made benchmark

bench/vela-interaction-bench.sh uses exactly this setup to measure slide-nav / interaction latency and thumbnail-scroll FPS. See bench/README.md.

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.