checking-member-access
Explains what a member or a role can do in a PostHog project, using the access control MCP tools. Use when the user asks what someone can see or edit, who can…
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, test desktop changes against a local Django stack, snapshot the accessibility tree, inspect network requests, and screenshot
$ npx -y skills add posthog/posthog --skill test-electron-app --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/test-electron-appContext 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, test desktop changes against a local Django stack, snapshot the accessibility tree, inspect network requests, and screenshot
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, test desktop changes against a local Django stack, snapshot the accessibility tree, inspect network requests, and screenshot only when explicitly asked. Use when asked to test, verify, dogfood, screenshot, interact with the running app, or run a live backend-to-desktop E2E check. For regression specs use the Playwright E2E suite. allowed-tools: Bash(agent-browser:*), Bash(npx agent-browser:*), Bash(pnpm app:cdp*)
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/`) |
For a live backend-to-desktop test, read [`references/local-django-stack.md`](references/local-django-stack.md) before starting services.
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`.
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
**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).
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
agent
: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.
Repo: posthog/posthog
Explains what a member or a role can do in a PostHog project, using the access control MCP tools. Use when the user asks what someone can see or edit, who can…
Analyze the most expensive users in AI observability and explain why they cost so much. Use when the user asks about top spenders, expensive users, per-user…
Author continuously-running online evaluations in PostHog AI observability, grounded in real failure modes you've identified. Use when the user wants…
Find where an AI/LLM application is failing in production and surface the failure patterns, working from real traces. Use when someone wants to understand…
Investigate AI observability clusters — understand usage patterns in AI/LLM traffic, compare cluster behavior, compute cost/latency metrics, and drill into…
Investigate LLM spend in PostHog — total cost over time, cost by model, provider, user, trace, or custom dimension, token and cache-hit economics, and cost…