AI phantom users that test your app the way real users actually use it.
> /plugin marketplace add Chocolatine75/haunt> /plugin install haunt@haunt
FAQ
haunt is a Claude Code plugin with hand-picked skills for testing work, indexed on Flowy. Install it with the command on its page. Its skills do not fire on their own yet. Request auto-invocation to have Flowy route them as you prompt. Free and open source.
Repo: Chocolatine75/haunt
A Claude Code plugin that tests your app the way real users break it.
You're shipping faster than ever with AI. You're also shipping more bugs โ you just don't know it yet.
Because you test your app the way you built it. You click the right buttons. You fill the right fields. You follow the happy path you designed.
Your users don't.
They submit empty forms. They paste garbage into your inputs. They bookmark random URLs. They click "submit" three times before your loading state kicks in. Every one of those moments is a silent churn event you'll never see in your logs.
Haunt fixes this. It unleashes AI phantom users on your app while you build โ a confused beginner, a user who breaks every input, someone navigating keyboard-only. Real Chromium browser, AI-driven behavior, structured bug report out.
We ran Haunt on a SaaS app after months of manual testing. 2 minutes, 6 bugs:
haunt v0.1.0 โ phantom user testing
scouting...
routes: / /signup /dashboard /pricing
testing 4 areas...
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
4 areas tested ยท 6 issues found
[!!!] 1 critical
[!!] 4 major
[!] 1 minor
> Signup form crashes the server with a 500 on empty submission โ no error shown
> Authenticated users can reach /signup and /login with no redirect
fix first: add server-side validation to the signup handler โ empty submission
currently returns a 500, leaving users with a blank broken screen
report: .haunt-reports/2026-04-20-confused-beginner.md
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
The developer had tested the signup form. But they'd tested it knowing what to fill in.
The report ends with a "For Claude" section โ paste it into your next prompt and it fixes every issue in order of severity, with the likely file for each one.
## For Claude
1. [CRITICAL] http://localhost:3000/signup โ Add server-side validation before
processing signup: check email and password are non-empty, return a 400 with
an error message if missing. Likely in app/signup/page.tsx.
2. [MAJOR] http://localhost:3000/signup โ Add middleware or page-level session
check to redirect authenticated users to /dashboard. Likely in middleware.ts.
...
Find bugs. Read report. Fix with one prompt. Run again.
/plugin install haunt
/reload-plugins
No API key. No config. Chromium installs itself on first run. Requires: Claude Code ยท Node.js 18+
# Default โ a confused first-time user explores your app
/haunt:haunt-test http://localhost:3000
# Watch it happen in real time
/haunt:haunt-test http://localhost:3000 --headed
# Adversarial โ probes every input and URL
/haunt:haunt-test http://localhost:3000 --personas malicious-user
# Accessibility โ keyboard-only, finds every broken interaction
/haunt:haunt-test http://localhost:3000 --personas screen-reader-user
# Full sweep โ all three personas at once
/haunt:haunt-test http://localhost:3000 --personas confused-beginner,malicious-user,screen-reader-user
# Test authenticated areas โ Haunt logs in first, then explores
/haunt:haunt-test http://localhost:3000 --email you@example.com --password secret
Reports saved to .haunt-reports/ โ structured markdown with YAML frontmatter.
Full flag reference: docs/cli.md
Each phantom user has a different way of going off-script.
| Persona | Who they are | What they do |
|---|---|---|
๐ confused-beginner | First-time user with no context | Submits forms empty, enters wrong data types, modifies URLs, hits back after submit, ignores instructions |
๐ malicious-user | User who pushes on everything | Tries unexpected inputs in every field, accesses URLs directly, probes what's reachable without logging in |
โฟ screen-reader-user | Keyboard-only user | Tabs through every element, triggers modal edge cases, checks if errors are announced, finds unlabeled buttons |
Your app has specific failure modes. Write the user who finds them.
name: Impatient Power User
description: Moves fast, skips steps, expects things to just work
system_prompt: |
You move fast and skip everything that looks optional.
Double-click buttons. Refresh mid-flow. Skip required fields and submit anyway.
If something needs more than 2 steps, try to skip one.
Report anything that breaks when you don't follow the expected sequence.
browser:
headless: true
viewport: { width: 1440, height: 900 }
scenarios:
- name: Speed run
goal: Break the experience by going too fast
max_steps: 10
/haunt:haunt-test http://localhost:3000 --personas ./personas/power-user.yaml
/haunt-test your command
โ
โโโ scouting reads real links from your app's DOM
โ maps up to 4 areas to test
โ
โโโ spawns N phantoms one browser per area, all parallel
โ โโโ ๐ป /signup confused beginner tries to register
โ โโโ ๐ป /dashboard tries the main app without context
โ โโโ ๐ป /pricing looks at plans, looks for a CTA
โ โโโ ๐ป /editor lands directly, no onboarding
โ
โโโ report issues ranked by impact
"For Claude" section auto-fixes everything
No AI vision. No magic. Just a real browser reading your accessibility tree โ and an AI deciding what a confused user would do next.
MIT โ fork it, extend it, add personas, run it in CI.
If Haunt finds something real in your app, we'd love to hear what it caught.
.claude-plugin/
marketplace.json
plugin.json
.gitignore
agents/
haunt-orchestrator.md
haunt-page-tester.md
haunt-reporter.md
bin/
haunt-summary.sh
commands/
haunt-test.md
demo/
.eslintrc.json
.gitignore
app/
admin/
page.tsx
api/
auth/
[...nextauth]/
route.ts
settings/
route.ts
signup/
route.ts
dashboard/
page.tsx
favicon.ico
fonts/
GeistMonoVF.woff
GeistVF.woff
globals.css
layout.tsx
login/
page.tsx
page.tsx
pricing/
page.tsx
settings/
page.tsx
signup/
page.tsx
components/
Navbar.tsx
SessionWrapper.tsx
lib/
auth.ts
db.ts
middleware.ts
next.config.mjs
package-lock.json
package.json
postcss.config.mjs
prisma/
schema.prisma
seed.ts
README.md
tailwind.config.ts
tsconfig.json
docs/
cli.md
LICENSE
mcp-server/
.gitignore
biome.json
dist/
node_modules/
playwright/
playwright-core/
bin/
install_media_pack.ps1
install_webkit_wsl.ps1
reinstall_chrome_beta_linux.sh
reinstall_chrome_beta_mac.sh
reinstall_chrome_beta_win.ps1
reinstall_chrome_stable_linux.sh
reinstall_chrome_stable_mac.sh
reinstall_chrome_stable_win.ps1
reinstall_msedge_beta_linux.sh
reinstall_msedge_beta_mac.sh
reinstall_msedge_beta_win.ps1
reinstall_msedge_dev_linux.sh
reinstall_msedge_dev_mac.sh
reinstall_msedge_dev_win.ps1
reinstall_msedge_stable_linux.sh
reinstall_msedge_stable_mac.sh
reinstall_msedge_stable_win.ps1
browsers.json
cli.js
index.d.ts
index.js
index.mjs
lib/
androidServerImpl.js
bootstrap.js
browserServerImpl.js
cli/
browserActions.js
driver.js
installActions.js
program.js
programWithTestStub.js
client/
android.js
api.js
artifact.js
browser.js
browserContext.js
browserType.js
cdpSession.js
channelOwner.js
clientHelper.js
clientInstrumentation.js
clientStackTrace.js
clock.js
connect.js
connection.js
consoleMessage.js
coverage.js
debugger.js
dialog.js
disposable.js
download.js
electron.js
elementHandle.js
errors.js
eventEmitter.js
events.js
fetch.js
fileChooser.js
fileUtils.js
frame.js
harRouter.js
input.js
jsHandle.js
jsonPipe.js
localUtils.js
locator.js
network.js
page.js
platform.js
playwright.js
screencast.js
selectors.js
stream.js
timeoutSettings.js
tracing.js
types.js
video.js
waiter.js
webError.js
worker.js
writableStream.js
generated/
bindingsControllerSource.js
clockSource.js
injectedScriptSource.js
pollingRecorderSource.js
storageScriptSource.js
utilityScriptSource.js
webSocketMockSource.js
inprocess.js
inProcessFactory.js
mcpBundle.js
mcpBundleImpl.js
outofprocess.js
protocol/
serializers.js
validator.js
validatorPrimitives.js
remote/
playwrightConnection.js
playwrightPipeServer.js
playwrightServer.js
playwrightWebSocketServer.js
serverTransport.js
server/
android/
android.js
backendAdb.js
artifact.js
bidi/
bidiBrowser.js
bidiChromium.js
bidiConnection.js
bidiDeserializer.js
bidiExecutionContext.js
bidiFirefox.js
bidiInput.js
bidiNetworkManager.js
bidiOverCdp.js
bidiPage.js
bidiPdf.js
third_party/
bidiCommands.d.js
bidiKeyboard.js
bidiProtocol.js
bidiProtocolCore.js
bidiProtocolPermissions.js
bidiSerializer.js
firefoxPrefs.js
browser.js
browserContext.js
browserType.js
callLog.js
chromium/
appIcon.png
chromium.js
chromiumSwitches.js
crBrowser.js
crConnection.js
crCoverage.js
crDevTools.js
crDragDrop.js
crExecutionContext.js
crInput.js
crNetworkManager.js
crPage.js
crPdf.js
crProtocolHelper.js
crServiceWorker.js
defaultFontFamilies.js
protocol.d.js
clock.js
codegen/
csharp.js
java.js
javascript.js
jsonl.js
language.js
languages.js
python.js
types.js
console.js
cookieStore.js
debugController.js
debugger.js
deviceDescriptors.js
deviceDescriptorsSource.json
dialog.js
dispatchers/
androidDispatcher.js
artifactDispatcher.js
browserContextDispatcher.js
browserDispatcher.js
browserTypeDispatcher.js
cdpSessionDispatcher.js
debugControllerDispatcher.js
debuggerDispatcher.js
dialogDispatcher.js
dispatcher.js
disposableDispatcher.js
electronDispatcher.js
elementHandlerDispatcher.js
frameDispatcher.js
jsHandleDispatcher.js
jsonPipeDispatcher.js
localUtilsDispatcher.js
networkDispatchers.js
pageDispatcher.js
playwrightDispatcher.js
streamDispatcher.js
tracingDispatcher.js
webSocketRouteDispatcher.js
writableStreamDispatcher.js
disposable.js
dom.js
download.js
electron/
electron.js
loader.js
errors.js
fetch.js
fileChooser.js
fileUploadUtils.js
firefox/
ffBrowser.js
ffConnection.js
ffExecutionContext.js
ffInput.js
ffNetworkManager.js
ffPage.js
firefox.js
protocol.d.js
formData.js
frames.js
frameSelectors.js
har/
harRecorder.js
harTracer.js
harBackend.js
helper.js
index.js
input.js
instrumentation.js
javascript.js
launchApp.js
localUtils.js
macEditingCommands.js
network.js
overlay.js
page.js
pipeTransport.js
playwright.js
progress.js
protocolError.js
recorder/
recorder.js
chat.js
recorderApp.js
recorderRunner.js
recorderSignalProcessor.js
recorderUtils.js
throttledFile.js
registry/
browserFetcher.js
dependencies.js
index.js
nativeDeps.js
oopDownloadBrowserMain.js
screencast.js
screenshotter.js
selectors.js
socksClientCertificatesInterceptor.js
socksInterceptor.js
trace/
recorder/
snapshotter.js
snapshotterInjected.js
tracing.js
viewer/
traceViewer.js
transport.js
types.js
usKeyboardLayout.js
utils/
ascii.js
comparators.js
crypto.js
debug.js
debugLogger.js
disposable.js
env.js
eventsHelper.js
expectUtils.js
fileUtils.js
happyEyeballs.js
hostPlatform.js
httpServer.js
image_tools/
colorUtils.js
compare.js
imageChannel.js
stats.js
linuxUtils.js
network.js
nodePlatform.js
pipeTransport.js
processLauncher.js
profiler.js
socksProxy.js
spawnAsync.js
task.js
userAgent.js
wsServer.js
zipFile.js
zones.js
videoRecorder.js
webkit/
protocol.d.js
webkit.js
wkBrowser.js
wkConnection.js
wkExecutionContext.js
wkInput.js
wkInterceptableRequest.js
wkPage.js
wkProvisionalPage.js
wkWorkers.js
serverRegistry.js
third_party/
pixelmatch.js
tools/
backend/
browserBackend.js
common.js
config.js
console.js
context.js
cookies.js
devtools.js
dialogs.js
evaluate.js
files.js
form.js
keyboard.js
logFile.js
mouse.js
navigate.js
... 369 moreยฉ 2026 Flowy ยท Free and open source
Built for Claude Code ยท Not affiliated with Anthropic