Boots the packaged Electron cockpit through Playwright's _electron launcher — the same
harness e2e/*.spec.ts uses — so an agent with no display can launch, screenshot, and inspect
the running app. All commands below run from apps/desktop.
Prerequisites
bun installat the repo root (or inapps/desktop) — the driver imports@playwright/testand launches the repo's localelectron; a tree that has never installed has neither. On a genuinely cold tree this first install is slow and needs a working native toolchain: it compilesnode-pty(a native module) and downloads the Electron binary.- The app is ESM (
"type": "module");driver.mjsruns undernode.
Build first
The driver launches out/main/index.js, so a build must precede every run — out/ is not
watched, so rebuild after editing src/:
bun run build # electron-vite build → out/{main,preload,renderer}
Agent path — the driver
node .claude/skills/run-desktop/driver.mjs --out /tmp/cockpit.png \
--eval "document.querySelector('[data-testid=cockpit-root] a')?.innerText"
It launches the built app, waits for [data-testid="cockpit-root"], writes the screenshot, and
prints the window title. Options:
--out <path>— screenshot destination, resolved against the current directory (defaultrun-desktop.pngin cwd).--transcripts <dir>— setsARGO_TRANSCRIPT_ROOT, so the observer reads a fixture world (<dir>/<project>/<session>.jsonl) instead of your own~/.claude/projects. Without it a clean machine lands on onboarding with an empty rail.--user-data <dir>— Electron's--user-data-dir. Argo's Project registry lives there, so writing aprojects.jsoninto it is what lands the app past onboarding with a Project already registered.e2e/rail.spec.ts'sbuildWorld()is the worked example of both flags.--testid <id>— print the inner text of[data-testid="<id>"].cockpit-rootis the renderer root, so it returns the whole tree's text; point this at a leaf testid to read one element as more get added.--eval <expr>— eval a JS expression in the renderer and print the JSON result.--wait <testid>— element to wait for before shooting (defaultcockpit-root).
Read the PNG back and confirm it shows the app — a green exit is not proof the window
rendered. With no --transcripts/--user-data the honest result is the onboarding empty state:
nothing is registered and nothing is observed.
Human path — dev server
For interactive work with hot reload (not for headless agents):
bun run dev # electron-vite dev; renderer on http://localhost:5173, opens a window
The same two environment seams work here: ARGO_TRANSCRIPT_ROOT=<dir> bun run dev points the
observer at a fixture world. There is no demo-seed switch — the rail shows what is actually
observed.
Gotchas
- Run the driver from
apps/desktop— it resolves the app root relative to its own file, but--outand any relative screenshot path resolve against your cwd. - Playwright's launcher emits benign teardown noise on close (
kill EPERM,<will force kill>) even on a clean run — judge success by the printed title and the PNG. - Stale
out/renders old code; if asrc/change isn't visible, you skipped the rebuild.
Troubleshooting
Cannot find module .../out/main/index.js→ runbun run build.waitFortimes out oncockpit-root→ the renderer failed to mount; pass--waitfor a testid you know exists, or runbun run devand read the DevTools console.- Driver import errors (
@playwright/testnot found) →bun installfirst.