Skip to content
Data
Skill

/test-electron-app

Drive the real running PostHog Electron app (live tRPC, workspace-server, real data) over CDP with agent-browser. Connect to the running app on port 9222, snapshot the accessibility tree to verify changes, click/type/navigate, and screenshot the actual desktop app only when

From plugin
posthog
38k156 skills11 agents1 command2 MCP
Install
$ npx -y skills add posthog/posthog --skill test-electron-app --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/test-electron-app

Context preview

The summary Claude sees to decide when to auto-load this skill.

Drive the real running PostHog Electron app (live tRPC, workspace-server, real data) over CDP with agent-browser. Connect to the running app on port 9222, snapshot the accessibility tree to verify changes, click/type/navigate, and screenshot the actual desktop app only when

SKILL.md

test-electron-app.SKILL.md
name: test-electron-app
description: Drive the real running PostHog Electron app (live tRPC, workspace-server, real data) over CDP with agent-browser. Connect to the running app on port 9222, snapshot the accessibility tree to verify changes, click/type/navigate, and screenshot the actual desktop app only when explicitly asked. Use when asked to test, verify, dogfood, screenshot or interact with the running app. For regression specs use the Playwright E2E suite.
allowed-tools: Bash(agent-browser:*), Bash(npx agent-browser:*), Bash(pnpm app:cdp*)

Test the real PostHog Electron app

Drive the actual running app over the Chrome DevTools Protocol with [agent-browser](https://github.com/vercel-labs/agent-browser). The dev app already launches with `--remote-debugging-port=9222` (see `apps/code/package.json`), so an agent can connect, snapshot the UI, interact, and (only when asked) screenshot the live app.

This exercises **real** state: live tRPC, workspace-server, GitHub/Slack and whatever profile is signed into `~/.posthog-code`. Pick the right surface:

| Goal | Tool | | --- | --- | | Verify or screenshot a change in the **real** app, live data | this skill (agent-browser + CDP :9222) | | **Regression** coverage in CI | Playwright E2E (`apps/code/tests/e2e/`) |

Prerequisites

npm i -g agent-browser && agent-browser install   # once

The app must be running with remote debugging. `pnpm dev` (or `pnpm dev:code`) already passes `--remote-debugging-port=9222`. Preflight + connect:

pnpm app:cdp        # checks agent-browser + that the app is up on :9222, then connects

If it reports the app is not reachable, the app isn't running. Start it, then retry `pnpm app:cdp`.

Launching the app yourself (background / no TTY)

Do **not** use `pnpm dev` from a non-interactive shell. It builds deps then hands off to the `phrocs` TUI process-multiplexer, which aborts without a controlling terminal (`bubbletea: could not open TTY: /dev/tty: device not configured`). An agent in a background shell has no TTY, so `pnpm dev` cannot launch it headlessly.

Build the workspace deps (TTY-safe, the same step `pnpm dev` runs first), then launch only the Electron app with its stdin held open:

pnpm build:deps                        # turbo build of @posthog/code deps
tail -f /dev/null | pnpm dev:code      # run in the background; leave it running

`pnpm dev:code` is `pnpm --filter code start`, i.e. `electron-vite dev --watch` — just the app, no `phrocs` TUI; it watches and rebuilds main/preload and hot-reloads the renderer (fine for screenshotting/interacting). The CDP port (`:9222`) is opened by the app itself in dev (the `remote-debugging-port` switch in `apps/code/src/main/bootstrap.ts`), not by a CLI flag.

The `tail -f /dev/null |` prefix is a harmless guard and no longer strictly required. The old `electron-forge start` ran an interactive "type `rs` to restart" stdin reader that hit EOF in a no-stdin shell, treated it as quit, and tore the Electron window down before the CDP port ever opened. `electron-vite dev` has no such reader, so a backgrounded `pnpm dev:code` with no stdin stays up on its own; keeping the pipe does no harm.

Then wait for the port and connect (poll, don't sleep blindly):

until curl -s localhost:9222/json/version >/dev/null; do sleep 1; done
agent-browser connect 9222

After you launch it: leave it up, then idle-shutdown

**Never auto-kill an instance you didn't start.** If `pnpm app:cdp` found the app already up on `:9222`, it's the user's own — when you're done just `agent-browser close` your session and leave the app running.

When *you* launched it, don't tear it down the instant you finish. The app survives between turns, so leave it up and end your turn by telling the user it's still running and asking if they want anything else — a follow-up needs no relaunch.

So a forgotten app doesn't linger, arm a **10-minute idle watchdog** at launch. Touch a marker file on launch and after every interaction; the watchdog tears the app down once that file sits untouched for 10 minutes (re-touching resets the clock):

touch /tmp/posthog-dev-lastuse        # arm now; re-run after each interaction

Then start the watchdog once, as a background task (touch the marker *first* or it fires immediately). It polls, then self-exits after it fires or once the marker is removed:

while sleep 30; do
  last=$(stat -f %m /tmp/posthog-dev-lastuse 2>/dev/null || echo 0)
  [ $(( $(date +%s) - last )) -ge 600 ] && break
done
pid=$(pgrep -f "remote-debugging-port=9222" | head -1)
[ -n "$pid" ] && kill -TERM "-$(ps -o pgid= -p "$pid" | tr -d ' ')" 2>/dev/null

To stop early (user says "done" / "shut it down"): close the session, group-kill the app, and drop the marker so the watchdog exits:

agent-browser close
pid=$(pgrep -f "remote-debugging-port=9222" | head -1)
[ -n "$pid" ] && kill -TERM "-$(ps -o pgid= -p "$pid" | tr -d ' ')" 2>/dev/null
rm -f /tmp/posthog-dev-lastuse

Group-killing the launcher (`kill -TERM -PGID`) takes down `tail`, `pnpm`, `electron-vite` and Electron together, so nothing — not even the `tail -f /dev/null` stdin pipe — lingers. Matching `remote-debugging-port=9222` hits only your dev instance (prod has no debug port and a separate `posthog-code-dev` profile), so it never touches the user's app. Verify with `curl -s localhost:9222/json/version` (fails) and `pgrep -fl posthog-code-dev` (empty).

Load the canonical commands

agent-browser serves version-matched docs. Read them before driving:

agent-browser skills get electron     # Electron-over-CDP workflow (authoritative)
agent-browser skills get core         # snapshot/interact/screenshot reference

The loop

agent-browser connect 9222                      # attach (skip if you ran pnpm app:cdp)
agent-browser snapshot -i                       # interactive elements only (the app is already dark)
agent-brows
Read more
Ships withposthog

:hedgehog: PostHog is the leading platform for building self-driving products. Our developer tools – AI observability, analytics, session replay, flags, experiments, error tracking, logs, and more – capture all the context agents need to diagnose problems, uncover opportunities, and ship fixes. Steer it all from Slack, web, desktop, or the MCP.

Get the whole plugin

Other skills on posthog.