/haunt-test
Run a phantom user test session against a running web application.
> /plugin marketplace add Chocolatine75/haunt > /plugin install haunt@haunt
How it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/haunt-test
Context preview
What this command does when you run it.
Run a phantom user test session against a running web application.
Command definition
haunt-test.md/haunt-test
Run a phantom user test session against a running web application.
Usage
/haunt-test <url> [--personas <list>] [--headed] [--steps N] [--verbose]
Arguments
- `url` — Target URL (required). Must be a running server, e.g. http://localhost:3000
- `--personas` — Comma-separated persona names (default: confused-beginner)
Available: confused-beginner, malicious-user, screen-reader-user
- `--headed` — Show the browser window in real time (default: headless)
- `--steps` — Max navigation steps per area (default: 3)
- `--email` — Email to log in with before testing
- `--password` — Password to log in with (use with --email)
- `--debug-auth` — Print each auth step verbosely (use when auth fails silently)
- `--yes` — Skip the cost estimate confirmation prompt (for scripted use)
- `--verbose` — Print intermediate reasoning and observations between tool calls (default: silent)
First run
If `haunt_spawn` is not available as a tool, print:
haunt is installing Chromium (first run, ~2 min).
Come back once done and run again.
Then stop. Do NOT debug.
Behavior
Phase 0 — Header
Print exactly:
haunt v0.1.0 — phantom user testing
Phase 0.5 — Auth (only if --email and --password are provided)
If credentials are present:
Print: `logging in as <email>...`
- If `--debug-auth`: print ` · auth flow started`
1. `haunt_spawn` at `target_url` with timeout: 5
- If `--debug-auth`: print ` · browser opened`
2. `haunt_capture_state` (`include_dom: true`) — look for a login form or link
- If `--debug-auth`: print ` · page loaded`
3. If not already on a login page, `haunt_navigate` to find and go to the login page (look for a "Login", "Sign in", or "Se connecter" link in the accessibility tree or DOM)
- If `--debug-auth`: print ` · login form found at <url>`
4. `haunt_navigate` — fill `<email>` in the email field
- If `--debug-auth`: print ` · email filled`
5. `haunt_navigate` — fill `<password>` in the password field
- If `--debug-auth`: print ` · password filled`
6. `haunt_navigate` — click the submit/login button
- If `--debug-auth`: print ` · submit clicked`
7. `haunt_capture_state` — verify auth succeeded: URL is no longer the login page, or a logged-in element (avatar, dashboard, username) is visible
- If `--debug-auth`: print ` · checking session...`
8. `haunt_get_cookies` — extract the session cookies
- If `--debug-auth`: print ` · cookies captured (<N>)`
9. `haunt_end_session`
Print: `authenticated — cookies captured`
Store the cookies. Pass them to every `haunt_spawn` call in Phase 2 via the `cookies` parameter.
If login fails (still on login page after submit, or error visible):
- If `--debug-auth`: print ` · login failed — session not detected`
Print `login failed — check your credentials` and stop.
Phase 1 — Recon (route discovery from real links)
Parse arguments:
- `target_url` — the URL argument
- `personas` — from `--personas` (default: `["confused-beginner"]`)
- `headless` — true unless `--headed`
- `steps` — from `--steps` (default: 3)
Print: `scouting...`
Spawn one browser session with the first persona and `timeout: 5`. Call `haunt_capture_state` with `include_dom: true`.
**Read real links from the DOM snapshot** — look for `href` attributes in `<a>` tags that start with `/` or the target origin. Extract distinct path segments. Do NOT guess common routes like /login or /dashboard unless you actually see them in the DOM.
Also read the accessibility tree for nav elements and any button/link text that suggests routes.
Call `haunt_end_session`. Build a page plan of up to 4 areas from the **real links you found**. If fewer than 4 real routes exist, test those — do not pad with guesses.
Print the discovered routes, e.g.: `routes: / /login /pricing /dashboard`
Phase 1.5 — Cost estimate
Compute:
- `route_count` = number of areas in the page plan (max 4)
- `steps_per_route` = value of `--steps` (default: 3)
- `browser_calls` = route_count × (steps_per_route × 2 + 3)
- (spawn + capture_state + [navigate + capture_state] × steps + end_session)
- `session_size` = "light" if browser_calls ≤ 6, "medium" if ≤ 16, "heavy" if > 16
Print exactly:
estimated: N routes · M steps each · ~K browser calls · [light|medium|heavy] session
proceed? [y/N]
- If `--yes` flag is present: skip the prompt and continue directly to Phase 2.
- Otherwise: wait for user input.
- If user types `y` or `yes`: continue to Phase 2.
- Any other input (including Enter alone): print `aborted.` and stop.
Phase 2 — Parallel testing
Print: `testing N areas...`
Run all sessions yourself — do NOT spawn sub-agents or agents.
**SILENCE RULE: unless `--verbose` is passed, print NOTHING between tool calls. No step labels, no "parallel" announcements, no reasoning summaries, no observations. Zero text output between the `testing N areas...` line and the final summary block. Think entirely silently.**
1. `haunt_spawn` for every area in a single message (all in parallel). If auth cookies were captured in Phase 0.5, pass them via the `cookies` parameter to every `haunt_spawn` call. 2. `haunt_capture_state` for all sessions (`include_screenshot: false`, `include_dom: false`) — all in parallel. 3. Reason as each persona with a **corner-case mindset — NOT the happy path** (silently unless `--verbose`):
- What non-obvious action would this user take that a developer would never think to test?
- What happens if they submit empty forms, enter wrong data types, go back after submitting?
- What if they navigate directly to a URL they shouldn't have access to?
- What breaks when they don't follow the expected flow?
Prioritize unexpected behavior over intended flows. 4. `haunt_navigate` for all sessions in a single message, with any `issues` spotted. Choose corner-case actions: submit empty forms, enter bad data, access protected URLs directly, trigger the same action twice. 5. Repeat capture → naviga
Read more
/haunt-test
Run a phantom user test session against a running web application.
Usage
/haunt-test <url> [--personas <list>] [--headed] [--steps N] [--verbose]
Arguments
- `url` — Target URL (required). Must be a running server, e.g. http://localhost:3000
- `--personas` — Comma-separated persona names (default: confused-beginner)
Available: confused-beginner, malicious-user, screen-reader-user
- `--headed` — Show the browser window in real time (default: headless)
- `--steps` — Max navigation steps per area (default: 3)
- `--email` — Email to log in with before testing
- `--password` — Password to log in with (use with --email)
- `--debug-auth` — Print each auth step verbosely (use when auth fails silently)
- `--yes` — Skip the cost estimate confirmation prompt (for scripted use)
- `--verbose` — Print intermediate reasoning and observations between tool calls (default: silent)
First run
If `haunt_spawn` is not available as a tool, print:
haunt is installing Chromium (first run, ~2 min). Come back once done and run again.
Then stop. Do NOT debug.
Behavior
Phase 0 — Header
Print exactly:
haunt v0.1.0 — phantom user testing
Phase 0.5 — Auth (only if --email and --password are provided)
If credentials are present:
Print: `logging in as <email>...`
- If `--debug-auth`: print ` · auth flow started`
1. `haunt_spawn` at `target_url` with timeout: 5
- If `--debug-auth`: print ` · browser opened`
2. `haunt_capture_state` (`include_dom: true`) — look for a login form or link
- If `--debug-auth`: print ` · page loaded`
3. If not already on a login page, `haunt_navigate` to find and go to the login page (look for a "Login", "Sign in", or "Se connecter" link in the accessibility tree or DOM)
- If `--debug-auth`: print ` · login form found at <url>`
4. `haunt_navigate` — fill `<email>` in the email field
- If `--debug-auth`: print ` · email filled`
5. `haunt_navigate` — fill `<password>` in the password field
- If `--debug-auth`: print ` · password filled`
6. `haunt_navigate` — click the submit/login button
- If `--debug-auth`: print ` · submit clicked`
7. `haunt_capture_state` — verify auth succeeded: URL is no longer the login page, or a logged-in element (avatar, dashboard, username) is visible
- If `--debug-auth`: print ` · checking session...`
8. `haunt_get_cookies` — extract the session cookies
- If `--debug-auth`: print ` · cookies captured (<N>)`
9. `haunt_end_session`
Print: `authenticated — cookies captured`
Store the cookies. Pass them to every `haunt_spawn` call in Phase 2 via the `cookies` parameter.
If login fails (still on login page after submit, or error visible):
- If `--debug-auth`: print ` · login failed — session not detected`
Print `login failed — check your credentials` and stop.
Phase 1 — Recon (route discovery from real links)
Parse arguments:
- `target_url` — the URL argument
- `personas` — from `--personas` (default: `["confused-beginner"]`)
- `headless` — true unless `--headed`
- `steps` — from `--steps` (default: 3)
Print: `scouting...`
Spawn one browser session with the first persona and `timeout: 5`. Call `haunt_capture_state` with `include_dom: true`.
**Read real links from the DOM snapshot** — look for `href` attributes in `<a>` tags that start with `/` or the target origin. Extract distinct path segments. Do NOT guess common routes like /login or /dashboard unless you actually see them in the DOM.
Also read the accessibility tree for nav elements and any button/link text that suggests routes.
Call `haunt_end_session`. Build a page plan of up to 4 areas from the **real links you found**. If fewer than 4 real routes exist, test those — do not pad with guesses.
Print the discovered routes, e.g.: `routes: / /login /pricing /dashboard`
Phase 1.5 — Cost estimate
Compute:
- `route_count` = number of areas in the page plan (max 4)
- `steps_per_route` = value of `--steps` (default: 3)
- `browser_calls` = route_count × (steps_per_route × 2 + 3)
- (spawn + capture_state + [navigate + capture_state] × steps + end_session)
- `session_size` = "light" if browser_calls ≤ 6, "medium" if ≤ 16, "heavy" if > 16
Print exactly:
estimated: N routes · M steps each · ~K browser calls · [light|medium|heavy] session proceed? [y/N]
- If `--yes` flag is present: skip the prompt and continue directly to Phase 2.
- Otherwise: wait for user input.
- If user types `y` or `yes`: continue to Phase 2.
- Any other input (including Enter alone): print `aborted.` and stop.
Phase 2 — Parallel testing
Print: `testing N areas...`
Run all sessions yourself — do NOT spawn sub-agents or agents.
**SILENCE RULE: unless `--verbose` is passed, print NOTHING between tool calls. No step labels, no "parallel" announcements, no reasoning summaries, no observations. Zero text output between the `testing N areas...` line and the final summary block. Think entirely silently.**
1. `haunt_spawn` for every area in a single message (all in parallel). If auth cookies were captured in Phase 0.5, pass them via the `cookies` parameter to every `haunt_spawn` call. 2. `haunt_capture_state` for all sessions (`include_screenshot: false`, `include_dom: false`) — all in parallel. 3. Reason as each persona with a **corner-case mindset — NOT the happy path** (silently unless `--verbose`):
- What non-obvious action would this user take that a developer would never think to test?
- What happens if they submit empty forms, enter wrong data types, go back after submitting?
- What if they navigate directly to a URL they shouldn't have access to?
- What breaks when they don't follow the expected flow?
Prioritize unexpected behavior over intended flows. 4. `haunt_navigate` for all sessions in a single message, with any `issues` spotted. Choose corner-case actions: submit empty forms, enter bad data, access protected URLs directly, trigger the same action twice. 5. Repeat capture → naviga
AI phantom users that test your app the way real users actually use it.
Repo: Chocolatine75/haunt

