exploring-the-wizard · v3.0 · 2026-06-24 · sha256 ee6a681e05326f8a
exploring-the-wizard v3.0A
Immutable. This exact content is served forever at /api/v1/blob/ee6a681e05326f8a.
---
name: exploring-the-wizard
description: Run, drive, and explore the PostHog wizard headlessly against an app — boot it on the app and decide each screen yourself over the wizard-ci MCP tools (open_app / read_state / perform_action / run_agent), snapshotting the TUI to see what happened. Use to test or explore the wizard end-to-end.
compatibility: Designed for Claude Code working on the PostHog wizard codebase.
metadata:
author: posthog
version: "3.0"
---
# Exploring the wizard as an agent
Drive a real wizard run yourself: boot it on an app, read each screen, decide, act,
snapshot. You do this through the **`wizard-ci` MCP tools**, which are already bound
in this repo (registered in `.mcp.json`). For _how_ it works underneath, read
[`e2e-harness/ARCHITECTURE.md`](../../../e2e-harness/ARCHITECTURE.md).
If you don't see the `wizard-ci` tools (`open_app`, `read_state`, …), the server
isn't approved yet — ask the user to approve `wizard-ci`, then retry.
## Set up
Ask the user for the absolute path to their PostHog key file — e.g. "What's the
path to your phx key file?" — plus the project id and region if you don't have
them. Clone or copy the target app to a **throwaway `/tmp` copy** (never a real
fixture). Never print or commit the key.
## Drive
1. **`open_app({ appDir, keyFile, projectId, region })`** — boots a live wizard on
the app and returns the first screen. `appDir` is the throwaway copy.
2. **`read_state`** — current screen, run phase, secret-free session, tasks, and
the actions legal right now. Call after every move.
3. **`perform_action({ action, params? })`** — commit a decision: `confirm_setup`,
`dismiss_outage`, `choose` (a setup question, e.g. `{ key, value }`),
`set_mcp_outcome`, `dismiss_slack`, `keep_skills`.
4. **`render_screen`** — render the current TUI to ANSI so you can _see_ it.
5. **`run_agent`** — kicks off the **real integration** in the background and
returns immediately; it bootstraps credentials, so it's what advances `auth`
and `run`. Then **poll `read_state`** — `runPhase` goes `running → completed`
and the screen advances to `outro`.
A typical walk:
```
open_app → intro → perform_action confirm_setup
read_state → health-check → perform_action dismiss_outage
read_state → auth → run_agent (returns at once; integration runs in background)
read_state (poll) → runPhase running → completed, screen → outro
outro → perform_action dismiss_outro → … → keep_skills
```
Snapshot with `render_screen` at each key moment and save each frame to a numbered
file — `/tmp/wz-explore-snaps/NN-<screen>.txt`, incrementing `NN` in visit order —
so the run leaves a readable, ordered record you and the user can review afterward
(the same shape the CI route's `.txt` frames take). Capture the run screen as it
progresses, not just on screen changes.
## Key facts
- **State → screen.** You never navigate; you commit a decision (an action) and the
router re-derives the active screen. Name actions, not keys.
- **`auth` and `run` advance only via `run_agent`.** They expose no action and
don't self-advance. `run_agent` returns immediately and runs the integration in
the background — poll `read_state` for `runPhase` (`running → completed`).
Everything else is an instant commit.
- **`run_agent` creates real PostHog resources** (a dashboard + insights) in the
project; each run duplicates them.
- **A green run ≠ a valid integration.** `runPhase=completed` means the flow
finished, not that the wizard understood the framework (e.g. it'll treat a Wasp
app as react-router). Read what it actually changed.
- **None of this ships.** The harness lives in `e2e-harness/`, out of `src/`.