
Test PostHog Electron App
FreeInteract with the live PostHog Electron app for testing.
Free · Opens the source repo
What Test PostHog Electron App does
The Test PostHog Electron App skill allows developers to interact with a live instance of the PostHog Electron application through the Chrome DevTools Protocol (CDP). By leveraging the agent-browser tool, users can connect to the app running on port 9222, enabling them to perform a variety of tasks such as verifying changes, taking snapshots of the UI, and executing commands to click, type, or navigate within the app. This skill is particularly useful for testing and verifying the functionality of the application in a real-world scenario, as it operates on actual live data.
To get started, users must ensure that the PostHog Electron app is running with remote debugging enabled. The skill requires the agent-browser to be installed and set up correctly. Once the app is launched, users can connect to it and utilize commands to interact with the user interface. The skill emphasizes the importance of taking snapshots to verify UI changes instead of relying on screenshots, which should only be captured when explicitly requested.
This skill is designed for developers and testers who need to validate the functionality of the PostHog Electron app. It provides a seamless way to engage with the app's live state, making it easier to perform regression testing and ensure that new changes do not break existing functionality. The skill is also ideal for dogfooding the application, allowing users to experience the app as end-users would while providing immediate feedback on any issues encountered.
While the skill is powerful for testing and verification, it is not intended for automated regression testing in a CI/CD pipeline, where using the Playwright E2E suite would be more appropriate. Instead, it serves as a hands-on tool for real-time interaction with the application, making it an essential addition for developers working on the PostHog project.
When to use it
Use this skill when you need to test, verify, or interact with the running PostHog Electron application in real-time.
When not to use it
This skill is not suitable for automated testing in CI/CD environments; for that, consider using Playwright E2E instead.
What you can build with it
Verifying UI Changes
Use the skill to interact with the live app and take snapshots to confirm that recent changes are functioning as expected.
Dogfooding the Application
Engage with the live PostHog Electron app to experience its features and provide feedback based on real usage.
Manual Testing of Features
Utilize the skill for manual testing sessions, allowing for direct interaction with the app to uncover any potential issues.
How to install Test PostHog Electron App
View source1. Install with the skills CLI
npx skills add posthog/posthog/test-electron-app --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by posthogTest the real PostHog Electron app
Drive the actual running app over the Chrome DevTools Protocol with
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-browser click @e5 # act on a ref from the snapshot
agent-browser snapshot -i # ALWAYS re-snapshot after the UI changes — this is how you verify
agent-browser close # done; free the session
Verifying a change is snapshot, not screenshot. The accessibility tree
tells you what is on screen for almost no tokens, and it is how you confirm a test
worked. Do not capture a screenshot to check your own work — only run screenshot
when the user explicitly asks to see the app (see Screenshots).
Refs (@e1, @e2, …) are reassigned on every snapshot and go stale the moment
the UI changes. Re-snapshot before the next ref interaction.
The renderer uses data-testid heavily, so prefer stable locators over refs
when you know the target:
agent-browser find testid new-task-button click
agent-browser find role button click --name "New task"
agent-browser find text "Settings" click
Screenshots
Only screenshot when the user explicitly asks for one ("screenshot", "show
me", "what does it look like"). To confirm a change worked, use agent-browser snapshot — the accessibility tree is the cheap default and is almost always
enough. Auto-capturing a screenshot to "confirm" your work just burns image
tokens.
agent-browser screenshot /tmp/app.png # viewport (absolute path = clickable)
agent-browser screenshot --full /tmp/app.png # full page instead of viewport
Navigate to the target view first (click through the UI), then capture. agent-browser prints the saved path. Repeated captures reuse the connected session, so batches are fast.
Always let the user open the capture
When the user asked for a screenshot, they want to look at it, so close the loop every time:
- Save to and report an absolute path (
/tmp/app.png, never a bareout.png). Claude Code renders absolute paths as clickable links, so the path itself opens the PNG on click. - Offer to open it for them, and on a yes run
open /tmp/app.png(macOS opens it in Preview). If the request was clearly "screenshot it so I can see it", just open it instead of asking. - The user can also open it themselves at any time with
!open /tmp/app.png.
Repo specifics
- Port:
9222(override withPOSTHOG_CODE_CDP_PORT). Collides with Chrome's default debugging port; ifconnectattaches to the wrong target, list and pick the PostHog window:agent-browser tabthenagent-browser tab --url "*". - Multiple targets: the app has a main renderer window (page title contains
"PostHog") plus possible webviews/devtools.
agent-browser tablists them; switch withagent-browser tab <index>. - Never pass
--color-scheme dark: that global flag makes agent-browser apply device emulation that forces a 1280x720 viewport and renders this Electron window blank, and it sticks in the daemon (only restarting the agent-browser daemon clears it, notclose). The app is already dark, so plainagent-browser snapshot/agent-browser screenshotis what you want. - Auth / data: you drive whatever is signed into
~/.posthog-code. If the app shows onboarding or sign-in, that is the real boot state. Do not mutate production data (don't create real tasks/PRs) while exploring. - Boot timing: after launching the app, give it a few seconds before
connecting; the renderer settles after
#root > *appears and "Loading" clears.
Running alongside prod
PostHog orchestrates the agent, so the usual loop is: prod (the installed app) runs the agent, and the dev build (pnpm dev) is the system under test. They coexist by design (apps/code/src/main/bootstrap.ts): dev runs as posthog-code-dev with its own app name, userData and single-instance lock, so it never collides with prod.
- agent-browser always targets dev. Only the dev build exposes CDP on
:9222; prod has no debug port, soconnect 9222can't accidentally drive prod. - Separate auth/state. The dev instance has its own
posthog-code-devprofile; it is not signed in just because prod is. Sign into the dev window once; its state persists. - One dev instance only. Dev's single-instance lock, fixed dev callback port (
8238) and:9222mean a secondpnpm devcollides and quits. Run prod + one dev. - What reloads. Renderer/UI changes hot-reload; just re-snapshot. Main-process/Electron changes need a dev restart to take effect.
Troubleshooting
- Connection refused on :9222: the app isn't running with the debug flag.
Start it (see Launching the app yourself for the headless recipe). Verify the
port:
lsof -i :9222orcurl -s localhost:9222/json/version. - App launches then immediately exits; CDP never opens: the old
electron-forge"quit on stdin EOF" behavior is gone underelectron-vite, so thetail -f /dev/null |prefix is optional and not the fix here. This is now usually a build error, the single-instance lock (another dev instance running) or a crash — check thepnpm dev:codeoutput. Notepnpm devcannot run headlessly at all — itsphrocsTUI needs a TTY; usepnpm dev:code. - Snapshot is empty / wrong window: you're on the wrong target. Run
agent-browser taband switch to the "PostHog" page. - Can't type into an input: try
agent-browser keyboard type "text"(types at current focus) oragent-browser keyboard inserttext "text"to bypass key events.
Frequently asked questions about Test PostHog Electron App
Similar skills
Agent Host Debug Logs
Analyze Agent Host debug logs for deeper insights.
Code OSS Dev - Launch + Debug
Launch and debug Code OSS with isolated profiles.
Phoenix CLI
Debug LLM applications with structured analysis tools.
Power Automate Debugging
Diagnose and fix Power Automate flow errors effectively.
Arize Trace
Inspect and export traces for LLM applications.
Runtime Behavior Probe
Investigate real runtime behavior with precision.
