scenescout 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,15 @@
1
+ # scenescout
2
+
3
+ ## 1.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - First release on npm.
8
+
9
+ SceneScout is an MCP server that lets an AI agent explore a running web app like a curious user and write a coverage-checked report. The engine contains no model and needs no API key: the agent supplies judgment, the engine supplies a structured view of the page, always-on correctness oracles, a write policy enforced at the network layer, cross-run memory and a report that lists what it did not test.
10
+
11
+ - **Install** as a Claude Code plugin, with `npx -y scenescout install`, or from source. Any MCP client can drive it with `npx -y scenescout serve`.
12
+ - **24 tools**, all prefixed `scout_`. Earlier pre-release builds used `ft_`; there are no aliases.
13
+ - **Works with or without the source code.** Next to a codebase, routes are read from Next.js, SvelteKit and Nuxt projects. Against a remote URL, routes are discovered from same-origin links.
14
+ - **Read-only by default.** `PUT`, `PATCH`, `DELETE` and destructive-looking requests are blocked on the wire. `safe-write` lets a run edit and delete only the records it created.
15
+ - **A demo app and a sample report** are in the repository: `npm run demo:serve`, and `examples/report.md`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 brunoboto96
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,429 @@
1
+ <div align="center">
2
+
3
+ # ๐Ÿ”ญ SceneScout
4
+
5
+ **Exploratory UI testing, driven by an AI agent.**
6
+
7
+ [![test](https://github.com/brunoboto96/SceneScout/actions/workflows/test.yml/badge.svg)](https://github.com/brunoboto96/SceneScout/actions/workflows/test.yml)
8
+ [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
9
+ ![node >= 20](https://img.shields.io/badge/node-%E2%89%A5%2020-339933?logo=node.js&logoColor=white)
10
+ ![MCP server](https://img.shields.io/badge/MCP-server-8A2BE2)
11
+
12
+ [๐Ÿ‘€ See it work](#-see-it-work) ยท [โœจ Why](#-why-its-different) ยท [๐ŸŽฏ Two ways to use it](#-two-ways-to-use-it) ยท [๐Ÿš€ Quickstart](#-quickstart) ยท [๐Ÿงฐ Toolbox](#-the-toolbox) ยท [๐Ÿ”Œ Other clients](#-other-mcp-clients) ยท [๐Ÿ”’ Safety](#-safety-model) ยท [๐Ÿฉบ Troubleshooting](#-troubleshooting)
13
+
14
+ </div>
15
+
16
+ SceneScout is an [MCP](https://modelcontextprotocol.io) server that hands an agent a *structured view* of a running web app โ€” every element, its geometry, and a set of always-on correctness oracles โ€” and lets the agent explore it like a curious user. Claude Code is the brain; SceneScout is the hands, eyes, and memory.
17
+
18
+ ```
19
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” MCP (stdio) โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
20
+ โ”‚ Claude Code + skill โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ถ โ”‚ SceneScout engine โ”‚
21
+ โ”‚ (intent, judgment, โ”‚ โ—€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ Playwright ยท oracles ยท memory โ”‚
22
+ โ”‚ your subscription) โ”‚ tool results โ”‚ findings ยท report โ€” no LLM โ”‚
23
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
24
+ ```
25
+
26
+ Scripted E2E suites answer one question โ€” *"does this exact flow still work?"* โ€” and say nothing about the 95% of the app they don't touch. SceneScout covers both gaps: it finds what's **broken** (crashes, dead ends, permission leaks) *and* reports how the product could be **better** (confusing flows, weak hierarchy, design-system drift), with concrete measurements.
27
+
28
+
29
+ ## ๐Ÿ‘€ See it work
30
+
31
+ This is a real run against the small demo app bundled in this repository. The screenshot was taken by SceneScout; the badge sitting on top of a button and the missing chart are two of the nine findings it filed.
32
+
33
+ <p align="center"><img src="examples/screenshots/dashboard.png" alt="The demo app's dashboard: a yellow badge covers the All orders button, and the weekly chart image is broken" width="720" /></p>
34
+
35
+ An excerpt of the report it wrote โ€” [read the whole thing](examples/report.md):
36
+
37
+ > **๐Ÿ”ด [HIGH] A double-click on Create order creates two orders**
38
+ > Evidence: `2ร— click fired the same state-changing request 2ร— (POST /api/orders)`
39
+ > The submit button stays enabled while the request is in flight, and the endpoint accepts the repeat.
40
+ >
41
+ > **๐Ÿ”ด [HIGH] Filtering orders by Archived fails, and the page shows an empty table instead of an error**
42
+ > Evidence: `GET /api/orders?status=archived โ†’ HTTP 500`
43
+ >
44
+ > **๐ŸŸ  [MEDIUM] The "New: bulk import" badge sits on top of the All orders button**
45
+ > Evidence: `"All orders" overlaps "New: bulk import" (81%)` โ€” measured from layout boxes, no screenshot needed.
46
+ >
47
+ > **Gap ledger โ€” what was NOT tested:** 4/7 visited routes never design-audited ยท single-role run, so permission boundaries are untested
48
+
49
+ Every finding comes with a repro trace and a Playwright regression-test skeleton. Try it yourself in two minutes: `npm run demo:serve`, then `/scenescout --url http://127.0.0.1:4173` โ€” see [demo-app/](demo-app/). It also documents [one defect the tool deliberately does not flag](demo-app/README.md#what-it-deliberately-does-not-catch).
50
+
51
+ ---
52
+
53
+ ## โœจ Why it's different
54
+
55
+ - ๐Ÿง  **Claude is the brain โ€” no API key.** The engine contains no LLM. Exploration runs on your Claude Code subscription; SceneScout just gives it deterministic tools.
56
+ - ๐Ÿ“ **Structured scene, not pixels.** The agent reads element lists *with layout geometry*, not screenshots. Overlap and off-screen bugs are computed from boxes โ€” deterministic, no vision guessing. (Screenshots exist only for pixel-native residue like broken images.)
57
+ - ๐Ÿ›ก๏ธ **Read-only by default, enforced on the wire.** Destructive actions are blocked at the network layer, not by asking the model nicely. Opt into writes only against disposable data.
58
+ - โœ… **Completion is a contract, not a vibe.** The engine knows the app's routes and *refuses* to file an "extensive" report while any known route is unvisited, unexercised, or un-audited. "Explored a bit and stopped" is structurally impossible.
59
+ - ๐Ÿงญ **It remembers.** UI states are fingerprinted and stored in the project's `.scenescout/`. Run N+1 skips what run N already covered, and every run starts smarter than the last.
60
+
61
+ ---
62
+
63
+ ## ๐ŸŽฏ Two ways to use it
64
+
65
+ SceneScout needs only a URL. Give it the source code as well and it gets noticeably better.
66
+
67
+ | | ๐Ÿ  **Next to the codebase** *(recommended)* | ๐ŸŒ **Against a remote URL** |
68
+ |---|---|---|
69
+ | **You run it from** | the app's repository | any folder โ€” an empty `qa/` directory is fine |
70
+ | **It plays the role of** | a developer-tester who can read the code | a black-box QA tester, like a person with a browser |
71
+ | **How it finds pages** | ๐Ÿ“‚ reads file-based routes from the source (Next.js, SvelteKit, Nuxt) **and** follows links. Code-routed apps fall back to links | ๐Ÿ”— follows same-origin links only โ€” pages nothing links to, or on another subdomain, stay unknown |
72
+ | **"Did we cover everything?"** | checked against the routes found in source *plus* discovered links โ€” an unvisited one blocks the report | checked against the pages it managed to discover |
73
+ | **Setup it figures out** | framework, dev command, saved Playwright logins (`playwright/.auth/`), whether the app uses `data-testid` | none โ€” you pass the URL, and the path to a login state if the app needs one |
74
+ | **What a finding looks like** | the symptom, **plus** the file behind it and a suggested fix | the symptom, a repro trace, and a regression-test skeleton |
75
+ | **Typical target** | `localhost` while you build | staging, a preview deploy, a client's site |
76
+
77
+ **Why the codebase helps.** The agent driving SceneScout is Claude Code, which can already read your repository. With the source at hand โ€” and a file-routed framework โ€” it knows the app's static routes before opening the browser, so coverage is measured against the real app instead of whatever happened to be linked. It can also check a suspicion against the code before reporting it: "there is no way to export this table" is a much stronger finding once the agent has confirmed no export handler exists. And when something breaks it can open the component or handler responsible and tell you *where* and *how* to fix it โ€” "the save button does nothing" becomes "`OrderForm` swallows the rejected promise in `onSubmit`; surface the error and re-enable the button".
78
+
79
+ **Why it still works without it.** Everything SceneScout *observes* comes from the running page โ€” elements, layout geometry, console and network errors, design-audit scores, task-ease measurements โ€” and none of that needs source code. Point it at a URL you are allowed to test and it behaves like a thorough QA tester: it explores, reproduces, and files findings with evidence.
80
+
81
+ ```
82
+ # next to the code โ€” run inside the app's repository
83
+ /scenescout --url http://localhost:3000
84
+
85
+ # remote โ€” run from any folder; memory and the report are kept there
86
+ /scenescout --url https://staging.example.com --role ./auth/qa.json
87
+ ```
88
+
89
+ > [!IMPORTANT]
90
+ > Only test sites you own or are authorized to test. A remote environment is more likely to hold real data. The default **read-only** mode blocks `PUT`/`PATCH`/`DELETE` and destructive-looking requests, but an ordinary form submission (a plain `POST`: contact form, comment, order, signup) still reaches the server and can create a record. On a site with real data, tell the agent which forms not to submit. See the [safety model](#-safety-model).
91
+
92
+ ---
93
+
94
+ ## ๐Ÿš€ Quickstart
95
+
96
+ ### ๐Ÿ“ฆ Prerequisites
97
+
98
+ | | |
99
+ |---|---|
100
+ | **Node** | โ‰ฅ 20 |
101
+ | **An MCP client** | [Claude Code](https://claude.ai/code) is the first-class one (it loads the skill); [others work too](#-other-mcp-clients) |
102
+ | **A web app to test** | SceneScout tests a *live* app: start yours locally first (e.g. `npm run dev`, `make dev-up`), or have the URL of a deployed one you're allowed to test |
103
+
104
+ ### 1๏ธโƒฃ Install
105
+
106
+ Pick one. All three end with the same 24 tools.
107
+
108
+ **A ยท Claude Code plugin** โ€” the skill and the server in one step:
109
+
110
+ ```
111
+ /plugin marketplace add brunoboto96/SceneScout
112
+ /plugin install scenescout@scenescout-marketplace
113
+ ```
114
+
115
+ Then download the browser once: `npx -y scenescout install --browser-only`. The command is `/scenescout:scenescout`.
116
+
117
+ **B ยท npm, for Claude Code or any other MCP client:**
118
+
119
+ ```bash
120
+ npx -y scenescout install # skill + Chromium (~150 MB, one-time) + registers the server with Claude Code
121
+ ```
122
+
123
+ Using a different client? Skip the registration and [add the server to its config](#-other-mcp-clients) instead: `npx -y scenescout install --browser-only`.
124
+
125
+ **C ยท From source**, to hack on it:
126
+
127
+ ```bash
128
+ git clone https://github.com/brunoboto96/SceneScout.git scenescout && cd scenescout
129
+ npm install # installs dependencies and builds
130
+ npm run setup # same as `scenescout install`, pointed at this checkout
131
+ ```
132
+
133
+ <details>
134
+ <summary>What <code>install</code> / <code>npm run setup</code> actually does</summary>
135
+
136
+ 1. links the `/scenescout` skill into `~/.claude/skills/` (or `$CLAUDE_CONFIG_DIR/skills/`) โ€” a `scenescout` folder it didn't create is moved aside to a `.backup-โ€ฆ` copy, never deleted. When run through `npx` it copies instead of linking, because the npx cache is temporary,
137
+ 2. downloads the Chromium build SceneScout drives (skipped if you already have it),
138
+ 3. registers the MCP server with Claude Code at user scope, using an **absolute** node path so it works under nvm/fnm.
139
+
140
+ Re-run it any time: after moving the folder or switching node versions it refreshes the stored paths. It exits non-zero if any step failed, so it is safe to chain. Opt out of a step with `--no-register` or `--skip-browser`.
141
+
142
+ If `claude` isn't on the PATH of the shell you ran it from, it prints the registration command instead of running it:
143
+
144
+ ```bash
145
+ claude mcp add --scope user scenescout -- npx -y scenescout serve
146
+ ```
147
+
148
+ </details>
149
+
150
+ ### 2๏ธโƒฃ Check it
151
+
152
+ ```bash
153
+ npx -y scenescout doctor # routes B and C (from source: npm run doctor)
154
+ npx -y scenescout doctor --engine # route A, or another MCP client: node + build + browser only
155
+ ```
156
+
157
+ Every line should be a โœ“. Anything that isn't prints the exact command that fixes it. Then **start a fresh session** in your client so it picks up the new tools.
158
+
159
+ ### 3๏ธโƒฃ Run it
160
+
161
+ No app handy? `npm run demo:serve` in a source checkout starts the [demo app](demo-app/) on `http://127.0.0.1:4173`.
162
+
163
+ From Claude Code, inside the project you want to test (or, for a [remote URL](#-two-ways-to-use-it), any folder):
164
+
165
+ ```
166
+ /scenescout --level medium --url http://localhost:3000 --role qa
167
+ ```
168
+
169
+ The skill scans the project (if there is one), attaches read-only, explores, and writes findings to `.scenescout/report.md`. That's it.
170
+
171
+ **Common flags** โ€” `--level minimal|medium|extensive` ยท `--url <app>` ยท `--role <name\|path>` (a Playwright storage-state to explore as: a name found by the scan, or a path to the JSON file) ยท `--safe-write` / `--allow-destructive`.
172
+
173
+ ---
174
+
175
+ ## ๐Ÿ”„ How a run works
176
+
177
+ One curiosity loop, repeated โ€” breadth first, then judgment where it matters:
178
+
179
+ ```
180
+ scan โ”€โ”€โ–ถ attach โ”€โ”€โ–ถ crawl โ”€โ”€โ–ถ investigate โ”€โ”€โ–ถ measure โ”€โ”€โ–ถ report
181
+ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
182
+ routes browser every route reproduce & journeys + gap-checked
183
+ & auth (r/o) in ONE call file findings design audit markdown
184
+ ```
185
+
186
+ 1. **Scan** the project โ€” framework, routes, auth states.
187
+ 2. **Attach** a browser (read-only unless you said otherwise).
188
+ 3. **Crawl** every known route in a *single* call โ€” per-route HTTP status, element counts, oracle violations, dead ends.
189
+ 4. **Investigate** what the crawl flagged: navigate, snapshot, reproduce, file a structured finding.
190
+ 5. **Measure** task ease (`scout_journey`) and design quality (`scout_design_audit`) on representative pages.
191
+ 6. **Report** โ€” the engine checks the gap ledger and writes `.scenescout/report.md`.
192
+
193
+ Snapshots are cheap: re-snapshotting a route returns only *what changed*, with stable refs (measured on a 130-element page: 10.7 kB โ†’ 0.7 kB).
194
+
195
+ ---
196
+
197
+ ## ๐Ÿงฐ The toolbox
198
+
199
+ 24 deterministic tools. The agent picks; you rarely call these by hand.
200
+
201
+ | Phase | Tools | What they do |
202
+ |---|---|---|
203
+ | **Set up** | `scout_scan` `scout_attach` `scout_session` | Discover routes; launch a browser in a write-mode; keep several authenticated roles alive at once |
204
+ | **Explore** | `scout_crawl` `scout_coverage` | Sweep every route in one call; ask what's still untested |
205
+ | **Look** | `scout_snapshot` `scout_hover` `scout_screenshot` | Read the structured scene (diffed); reveal tooltips/hover cards; capture pixels only when needed |
206
+ | **Act** | `scout_click` `scout_type` `scout_select` `scout_upload` `scout_press` `scout_scroll` `scout_navigate` `scout_back` `scout_run_plan` | Drive the UI like a user; `scout_run_plan` batches a whole mechanical sequence into one call |
207
+ | **Assess** | `scout_design_audit` `scout_journey` | Score a page's craft/a11y/consistency; measure how hard a task is to complete |
208
+ | **Record** | `scout_note` `scout_finding` `scout_resolve` `scout_report` | Curate durable notes; file deduped findings; mark fixes; generate the report |
209
+ | **Close** | `scout_close` | Tear down one session or all |
210
+
211
+ A few that punch above their weight:
212
+
213
+ - **`scout_crawl`** โ€” the entire breadth pass in one tool call. No visiting routes one-by-one.
214
+ - **`scout_run_plan`** โ€” up to 20 actions (fill form โ†’ submit โ†’ check) with semantic targets (`testid=โ€ฆ`, `text=โ€ฆ`), aborting at the first anomaly.
215
+ - **`scout_journey`** โ€” wraps one goal and reports interaction count, screens seen, and **backtracks**; an abandoned journey is a finding no passing E2E suite can produce.
216
+ - **`scout_upload`** โ€” generates a *valid* in-memory fixture (real PDF/PNG, kind inferred from `accept`) so file-upload flows stop being a blind spot.
217
+ - **`scout_click {clicks: 2}`** โ€” the impatient-user probe: states whether a double-click fired the same state-changing request twice (the classic double-submit bug).
218
+
219
+ ---
220
+
221
+ ## ๐Ÿ“Š Test levels
222
+
223
+ Each level is an **enforced contract** โ€” `scout_report` checks it before finalizing.
224
+
225
+ | Level | What it guarantees | Rough size |
226
+ |---|---|---|
227
+ | `minimal` | Every route visited, โ‰ฅ1 design audit, key journeys as plans, crawl problems triaged. Remaining gaps **disclosed**. | ~40 actions |
228
+ | `medium` *(default)* | minimal + design audits across several routes + every element class exercised + every form submitted valid **and** invalid | ~150 actions |
229
+ | `extensive` | medium + fuzzing, back/refresh/deep-link resilience, keyboard-only pass, a journey per module, โ‰ฅ2 roles compared, anonymous auth-surface walk. **Refuses to finalize while any gap remains.** | budget-capped |
230
+
231
+ That refusal *is* the guarantee: an extensive report can only exist when nothing known was left untested.
232
+
233
+ ---
234
+
235
+ ## ๐Ÿ”’ Safety model
236
+
237
+ - ๐ŸŸข **`read-only` by default.** Destructive-labeled elements (delete/revoke/archive/โ€ฆ) **and** all `PUT/PATCH/DELETE` + destructive `POST`s are blocked at the network layer โ€” see [`src/engine/policy.ts`](src/engine/policy.ts). Non-destructive `POST`s are allowed, because submitting forms is how a tester finds validation bugs โ€” so read-only means *nothing existing is changed or removed*, not *nothing is ever created*.
238
+ - ๐ŸŸก **`safe-write`** (`--safe-write`) lets the agent create data and edit/delete **only what it created** this run โ€” never pre-existing records.
239
+ - ๐Ÿ”ด **`destructive`** (`--allow-destructive`) allows everything, and only ever when *you* confirm the environment is disposable. The skill will never choose this itself.
240
+ - ๐Ÿ“‚ Findings, memory, and reports live in a `.scenescout/` folder where you ran it. It ignores itself in git, so a stray `git add -A` never commits test data.
241
+
242
+ A `๐Ÿ›ก WRITE-POLICY blocked` notice is the safety net doing its job, not an app bug.
243
+
244
+ ---
245
+
246
+ ## ๐Ÿ“‹ What you get
247
+
248
+ `.scenescout/report.md` โ€” a deduplicated, worst-first report with:
249
+
250
+ - ๐Ÿ› **Findings** with repro traces and generated Playwright regression-test skeletons.
251
+ - ๐Ÿ’ฏ **Page scores** (0โ€“100: a11y ยท craft ยท consistency ยท task-clarity), ranked worst-first, with stale scores from old runs marked as such.
252
+ - ๐Ÿ‘ฅ **A role capability matrix** โ€” what each role could and couldn't reach.
253
+ - ๐Ÿงพ **A gap ledger** โ€” everything *not* done, so the report is honest about its own coverage.
254
+
255
+ ๐Ÿ‘€ Watch a run live: `node dist/cli.js status <project-path>`.
256
+
257
+ ---
258
+
259
+ ## ๐Ÿฉบ Troubleshooting
260
+
261
+ Run `npm run doctor` first โ€” it checks every setup item below (everything but the last row, which is about your app) and prints the fix.
262
+
263
+ | Symptom | Cause and fix |
264
+ |---|---|
265
+ | `/scenescout` isn't a known command | The skill isn't linked, or the session predates it. `npm run setup`, then start a **fresh** Claude Code session. |
266
+ | The `scout_*` tools don't appear | The MCP server isn't registered, or points at an old path. `npm run setup` re-registers it; `claude mcp list` should show `scenescout` as connected. |
267
+ | `npm install` fails at the build step | The build needs the dev dependencies (TypeScript). Don't pass `--omit=dev` or set `NODE_ENV=production` when installing from a clone. |
268
+ | *"Executable not found in $PATH"* | The server was registered with a bare `node`. `npm run setup` registers the absolute path. |
269
+ | *"Executable doesn't exist โ€ฆ chromium"* | The browser download was skipped or failed. `npx playwright install chromium` (on Linux add `--with-deps`). |
270
+ | Tools broke after moving the folder or changing node version | The registration stores absolute paths. `npm run setup` refreshes them. |
271
+ | Attach fails or every route lands on the login page | Your app isn't running at `--url`, or the `--role` storage state has expired โ€” regenerate it the way your project's Playwright setup does. |
272
+
273
+ ### โฌ†๏ธ Upgrading from an older version
274
+
275
+ - **Tools are now `scout_*`.** Up to v0.23 they were prefixed `ft_`. The rename happened before the first npm release, with no aliases, so an agent's context carries one tool list rather than two. Re-run `npm run setup` so the installed skill matches the server.
276
+ - **Earlier names.** This tool was previously called SceneCraft (and, before that, frontend-tester). `npm run setup` cleans up after both: it removes the old skill link and the old `scenecraft` MCP registration when they point at this install, and the first attach in a project moves its `.scenecraft/` memory folder to `.scenescout/` so earlier coverage and findings carry over.
277
+
278
+ ### ๐Ÿงน Uninstall
279
+
280
+ ```bash
281
+ claude mcp remove --scope user scenescout
282
+ rm -rf ~/.claude/skills/scenescout
283
+ ```
284
+
285
+ Then delete the clone. Per-project memory lives in each tested project's `.scenescout/` folder; delete it there if you want it gone.
286
+
287
+ ---
288
+
289
+ ## ๐Ÿ”Œ Other MCP clients
290
+
291
+ The engine is a plain MCP server over stdio, so any client can drive it. The server entry is always the same command โ€” `npx -y scenescout serve` โ€” only the config file differs. Download the browser once with `npx -y scenescout install --browser-only`.
292
+
293
+ <details>
294
+ <summary><strong>Cursor</strong> โ€” <code>~/.cursor/mcp.json</code> (or <code>.cursor/mcp.json</code> in a project)</summary>
295
+
296
+ ```json
297
+ {
298
+ "mcpServers": {
299
+ "scenescout": { "command": "npx", "args": ["-y", "scenescout", "serve"] }
300
+ }
301
+ }
302
+ ```
303
+
304
+ </details>
305
+
306
+ <details>
307
+ <summary><strong>VS Code</strong> (GitHub Copilot agent mode) โ€” <code>.vscode/mcp.json</code></summary>
308
+
309
+ ```json
310
+ {
311
+ "servers": {
312
+ "scenescout": { "type": "stdio", "command": "npx", "args": ["-y", "scenescout", "serve"] }
313
+ }
314
+ }
315
+ ```
316
+
317
+ </details>
318
+
319
+ <details>
320
+ <summary><strong>Codex CLI</strong> โ€” <code>~/.codex/config.toml</code></summary>
321
+
322
+ ```toml
323
+ [mcp_servers.scenescout]
324
+ command = "npx"
325
+ args = ["-y", "scenescout", "serve"]
326
+ ```
327
+
328
+ </details>
329
+
330
+ <details>
331
+ <summary><strong>Anything else</strong></summary>
332
+
333
+ Most clients accept the same `mcpServers` JSON shape shown for Cursor. From a source checkout, the command is `node` with the absolute path to `dist/mcp-server.js`.
334
+
335
+ </details>
336
+
337
+ **The skill is what makes it good.** The tools are only hands and eyes; [`skills/scenescout/SKILL.md`](skills/scenescout/SKILL.md) is the method โ€” what to look at first, when to stop, what counts as a finding. Claude Code loads it as a skill. In another client, give the agent that file as its instructions (a rule, a custom mode, or pasted into the first message).
338
+
339
+ The CLI is also useful on its own:
340
+
341
+ ```bash
342
+ npx -y scenescout scan <path> # project discovery: framework, routes, saved logins
343
+ npx -y scenescout status <path> # what a running engine is doing right now
344
+ ```
345
+
346
+ ---
347
+
348
+ ## ๐Ÿ“ Project layout
349
+
350
+ ```
351
+ src/
352
+ mcp-server.ts the 24 tools + per-session dispatch
353
+ scan.ts project discovery (framework, routes, auth)
354
+ cli.ts scan ยท serve ยท install ยท doctor ยท status
355
+ installer.ts setup logic (skill link, MCP registration, diagnostics)
356
+ engine/
357
+ browser.ts the engine class: attach, snapshot, actions, crawl, plans
358
+ probes.ts in-page scroll + overlay + focus probes (needs a browser too)
359
+ fingerprint.ts route + element-set identity (state hashing)
360
+ oracles.ts console/page/network/HTTP error detection
361
+ policy.ts the write-policy safety net
362
+ ownership.ts safe-write: which records did this run create?
363
+ uploads.ts disk uploads, fenced to the project by real path
364
+ journey.ts task-ease measurement from the action log
365
+ design.ts the design audit + page scoring
366
+ memory.ts cross-run storage + finding dedup
367
+ report.ts the gap ledger + report generation
368
+ โ€ฆ collector ยท dispatch ยท fixtures ยท authloss ยท reaper
369
+ scripts/ the 11 test suites (smoke/ holds the real-browser ones)
370
+ test-app/ fixtures for the real-browser smoke tests
371
+ skills/scenescout/ the Claude Code skill (SKILL.md)
372
+ docs/adr/ why it's built this way
373
+ ```
374
+
375
+ > Design principle: logic that *doesn't* need Playwright lives outside `browser.ts`, so it can be unit-tested without launching a browser. That's why `fingerprint`, `policy`, `memory`, `report`, etc. are their own modules.
376
+
377
+ ---
378
+
379
+ ## ๐Ÿง  Design decisions
380
+
381
+ The load-bearing choices are recorded as ADRs โ€” read the relevant one before changing a rule it covers:
382
+
383
+ - [1 ยท Completion is an enforced contract, not a claim](docs/adr/0001-completion-is-a-contract-not-a-vibe.md)
384
+ - [2 ยท The write policy is enforced on the wire, not in the prompt](docs/adr/0002-enforce-the-write-policy-at-the-network-layer.md)
385
+ - [3 ยท A gap-ledger entry must be actionable, and suppression must be visible](docs/adr/0003-a-noisy-ledger-is-a-broken-ledger.md)
386
+ - [4 ยท Findings dedup on machine signals, and a merge must never lose a finding](docs/adr/0004-dedup-on-machine-signals-not-prose.md)
387
+ - [5 ยท Testable logic lives outside `browser.ts`](docs/adr/0005-keep-testable-logic-out-of-the-browser-module.md)
388
+ - [6 ยท Nothing in this repo names or is tuned for a tested app](docs/adr/0006-stay-project-agnostic.md)
389
+
390
+ ---
391
+
392
+ ## ๐Ÿ”ง Development
393
+
394
+ ```bash
395
+ npm run build # tsc
396
+ npm test # build + 11 suites: scan, oracle, policy, fixture, dispatch, design,
397
+ # contract, memory, install, smoke, mcp-check
398
+ npm run dev # run the CLI from source (tsx)
399
+ ```
400
+
401
+ Contributing? Start with [VISION.md](VISION.md) (what is in scope) and [CONTRIBUTING.md](CONTRIBUTING.md) (how changes land), then see [CLAUDE.md](CLAUDE.md) for the house rules โ€” chiefly: bug fixes need a regression test at the cheapest layer that can fail, keep the repo project-agnostic (ADR 6), and `npm run build && npm test` must pass before committing.
402
+
403
+ ## ๐Ÿ” Security
404
+
405
+ Found a way past the write policy, or another security problem? Please report it privately โ€” see [SECURITY.md](SECURITY.md).
406
+
407
+ ## ๐Ÿ“„ License
408
+
409
+ [MIT](LICENSE).
410
+
411
+ <details>
412
+ <summary><strong>Full capability list</strong> โ€” every behavior, for the curious</summary>
413
+
414
+ - **Structured render-state, not pixels.** Element lists with geometry; screenshots reserved for pixel-native residue (broken images, canvas).
415
+ - **Diff snapshots with stable refs.** Re-snapshots return only what changed (10.7 kB โ†’ 0.7 kB on a 130-element page); old refs stay valid.
416
+ - **Geometry oracles.** Overlap and off-screen defects computed from layout boxes.
417
+ - **Oracles after every action.** Console errors, page errors, failed requests, HTTP 4xx/5xx drained into every tool result.
418
+ - **Multi-role, genuinely concurrent.** Commands to *different* sessions run in parallel; safe-write ownership is shared, so role A can create what role B approves. The report renders a role capability matrix.
419
+ - **Task ease, not just correctness.** `scout_journey` measures interaction cost, distinct screens, path, and backtracks.
420
+ - **Design audit with page scores.** Two tiers (โš  measurable defects / โ†’ craft suggestions incl. AI-slop tells), per-page 0โ€“100 score persisted per route, plus an automatic overlay/modal probe on every snapshot. Shared shell scored once, separately.
421
+ - **Scrolls like a user โ€” and notices when it can't.** Reports `SCROLL LOCKED` for a leaked modal scroll-lock, finds the real inner scroll pane on app-shell layouts, and flags `UNREACHABLE` controls clipped inside `overflow:hidden`.
422
+ - **Uploads like a user.** Answers a styled file-chooser or sets a hidden input directly, with a valid in-memory fixture; `filePath` is fenced to the project under test; files violating `accept` are flagged at selection.
423
+ - **Auth via Playwright storage states.** Expired tokens caught at attach; repeated login-bounces raise `SESSION AUTH LOST`; a bounced route is recorded as *not* covered โ€” a dead session can't certify routes it never reached.
424
+ - **A trustworthy gap ledger.** Entries must be actionable (a search box or wizard sub-step isn't "form filled but never submitted"); API/download URLs never enter the route contract.
425
+ - **Honest reporting.** Shared chrome counted once, stale scores marked, role matrix compares only roles that actually attempted a route.
426
+ - **Cross-run written knowledge.** `scout_note` curates `.scenescout/ASSUMPTIONS.md` โ€” app model, personas, constraints, risks โ€” in prose.
427
+ - **Daemon-grade robustness.** Per-tool watchdogs, orphaned-browser reaping, bounded teardown, live status via `scenescout status <project>`.
428
+
429
+ </details>