scenescout 1.0.0 โ 1.2.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 +32 -0
- package/README.md +186 -65
- package/dist/browsers.js +185 -0
- package/dist/cli.js +167 -39
- package/dist/clients.js +213 -0
- package/dist/code-routes.js +462 -0
- package/dist/engine/browser.js +88 -38
- package/dist/engine/collector.js +148 -7
- package/dist/engine/hover.js +42 -0
- package/dist/engine/launch.js +12 -5
- package/dist/engine/policy.js +55 -3
- package/dist/engine/probes.js +4 -1
- package/dist/engine/report.js +6 -1
- package/dist/installer.js +40 -12
- package/dist/mcp-server.js +61 -6
- package/dist/playbook.js +83 -0
- package/dist/scan.js +26 -2
- package/package.json +19 -7
- package/skills/scenescout/SKILL.md +11 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# scenescout
|
|
2
2
|
|
|
3
|
+
## 1.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 2932164: `scenescout install --browsers <list>` chooses what to download: `chromium` (the default, unchanged), `chromium-headless-shell` for the smallest working setup, `firefox`, `webkit`, or `all`. `scout_attach` takes a `browser` option, and `SCENESCOUT_BROWSER` sets the default. In Firefox and WebKit the engine keeps service workers from registering, because a request issued by one cannot be intercepted there and would pass the write policy. The missing-browser message and `doctor` now name the build that is actually missing, and the sizes quoted are the sizes on disk.
|
|
8
|
+
|
|
9
|
+
Pages are no longer given shared workers unless the mode is `destructive`. A request a shared worker sends cannot be intercepted in any browser, and a `DELETE` sent from one reached the server in read-only mode.
|
|
10
|
+
|
|
11
|
+
Hover no longer reports text that was already on the page and only moved to a new line, and the keyboard focus audit uses Option+Tab in WebKit on macOS, where plain Tab skips buttons and links.
|
|
12
|
+
- ad0f31d: `scenescout install --client <list>` registers the server with clients other than Claude Code: `cursor`, `vscode`, `codex`, `gemini`, `copilot` and `windsurf`. Clients that have a command for adding a server are registered through it; Cursor and Windsurf get an entry added to their JSON server list, with every other entry kept and an unreadable file left untouched. For VS Code, a `code` command that belongs to another editor is not used. The skill is installed only when `claude-code` is among the clients.
|
|
13
|
+
- 5504c63: The testing method now reaches every MCP client, not only Claude Code. A new `scout_playbook` tool returns it, the server's instructions tell an agent to call that tool before its first attach, and an `explore` prompt loads the method together with the target URL for clients that list server prompts as commands. It is the same text Claude Code loads as a skill, read from the same file.
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- d0aa6aa: The package description, keywords and README now present SceneScout as a tool for any MCP client, with Claude Code as one of them. `doctor --engine` ends with what to ask an agent instead of a Claude Code command.
|
|
18
|
+
|
|
19
|
+
## 1.1.0
|
|
20
|
+
|
|
21
|
+
### Minor Changes
|
|
22
|
+
|
|
23
|
+
- d3ebd73: Snapshots now list images that failed to load, under `BROKEN IMAGES`, read from the DOM. This catches an image whose URL answers 200 with something that is not an image, which the HTTP oracle cannot see because no request failed. Images that occupy no space (inside a closed panel, tracking pixels) are not reported.
|
|
24
|
+
|
|
25
|
+
An `<img>` is now named by its alt text and listed with the role `image`; it previously appeared as `generic "(unnamed)"`. For the uncommon `<img>` that is collected without a `data-testid` (one with `onclick` or an explicit role), this changes its element key, so states containing it are seen as new once.
|
|
26
|
+
- 5706a55: `scout_scan` now reads routes from source for React Router, Vue Router and Angular projects, including nested children, `<Route>` elements and Angular `loadChildren` files. These projects previously started with an empty route list and relied on link discovery alone, so a page nothing linked to was outside the completion contract. The reader is static and skips anything it cannot resolve: computed paths, spreads, identifiers, and relative paths whose parent is unknown.
|
|
27
|
+
- 6b6b786: The geometry oracle now reports a pinned control that sits underneath other pinned chrome, for example a sticky Save row covered by a fixed bar. Box overlap cannot tell which of two pinned elements is on top, so that pair was skipped; the new check hit-tests the control's centre in the page. It stays quiet for controls inside a scrollable pane, for dialogs, and for overlays covering half the viewport.
|
|
28
|
+
- 0d320b1: New write mode `observe` (`--observe`): nothing but `GET`, `HEAD` and `OPTIONS` requests leaves the page, except logging in, logging out and refreshing a token. Signing up and password changes are blocked. WebSocket frames are not inspected, and the engine says so when the app opens one. `read-only` lets an ordinary form `POST` through, which on a target holding real data creates a record. The skill now attaches in `observe` for a remote URL with no source unless told that form submissions are acceptable. Forms that could not be submitted stay in the gap ledger, worded as the mode's doing.
|
|
29
|
+
|
|
30
|
+
### Patch Changes
|
|
31
|
+
|
|
32
|
+
- 0d320b1: The login exemption in the write policy no longer applies to destructive-looking requests in any mode. A path that merely contained a word such as `session` or `auth` previously carried a request like `POST /api/session/123/delete` through `read-only`. A form navigation blocked by the write policy is now reported as blocked; it was reported as an off-origin navigation, and the follow-up note blamed the app for discarding data.
|
|
33
|
+
- 4107696: `scenescout doctor` now suggests `npx -y scenescout install` when the tool was installed from npm. It previously suggested `npm run setup`, which exists only in a source checkout.
|
|
34
|
+
|
|
3
35
|
## 1.0.0
|
|
4
36
|
|
|
5
37
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
# ๐ญ SceneScout
|
|
4
4
|
|
|
5
|
-
**Exploratory UI testing, driven by
|
|
5
|
+
**Exploratory UI testing, driven by the AI agent you already use.**
|
|
6
|
+
|
|
7
|
+
Works with Claude Code ยท Cursor ยท VS Code (Copilot) ยท Codex CLI ยท Gemini CLI ยท Copilot CLI ยท Windsurf ยท any [MCP](https://modelcontextprotocol.io) client
|
|
6
8
|
|
|
7
9
|
[](https://github.com/brunoboto96/SceneScout/actions/workflows/test.yml)
|
|
10
|
+
[](https://www.npmjs.com/package/scenescout)
|
|
8
11
|
[](LICENSE)
|
|
9
12
|

|
|
10
13
|

|
|
@@ -13,11 +16,11 @@
|
|
|
13
16
|
|
|
14
17
|
</div>
|
|
15
18
|
|
|
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.
|
|
19
|
+
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. Your coding agent is the brain; SceneScout is the hands, eyes, and memory. Any MCP client can drive it, and the testing method comes with the server, so the agent knows how to use the tools wherever it runs.
|
|
17
20
|
|
|
18
21
|
```
|
|
19
22
|
โโโโโโโโโโโโโโโโโโโโโโโ MCP (stdio) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
20
|
-
โ
|
|
23
|
+
โ Your coding agent โ โโโโโโโโโโโโโโโถ โ SceneScout engine โ
|
|
21
24
|
โ (intent, judgment, โ โโโโโโโโโโโโโโโ โ Playwright ยท oracles ยท memory โ
|
|
22
25
|
โ your subscription) โ tool results โ findings ยท report โ no LLM โ
|
|
23
26
|
โโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
@@ -28,9 +31,11 @@ Scripted E2E suites answer one question โ *"does this exact flow still work?"*
|
|
|
28
31
|
|
|
29
32
|
## ๐ See it work
|
|
30
33
|
|
|
31
|
-
This is a real run against the small demo app bundled in this repository. The
|
|
34
|
+
This is a real run against the small demo app bundled in this repository. The app has bugs planted in it on purpose, and two of them are visible on its dashboard:
|
|
35
|
+
|
|
36
|
+
<p align="center"><img src="examples/screenshots/dashboard-annotated.png" alt="The demo app's dashboard with two defects outlined in red: 1, a yellow badge covering the All orders button; 2, the weekly chart image failing to load" width="760" /></p>
|
|
32
37
|
|
|
33
|
-
|
|
38
|
+
**The broken chart is the demo app's bug, not this page's** โ it is one of the ten findings SceneScout filed, next to the badge sitting on a button. The red callouts were added for this README; the [unmarked screenshots](examples/screenshots/) are the ones the engine took.
|
|
34
39
|
|
|
35
40
|
An excerpt of the report it wrote โ [read the whole thing](examples/report.md):
|
|
36
41
|
|
|
@@ -41,19 +46,22 @@ An excerpt of the report it wrote โ [read the whole thing](examples/report.md)
|
|
|
41
46
|
> **๐ด [HIGH] Filtering orders by Archived fails, and the page shows an empty table instead of an error**
|
|
42
47
|
> Evidence: `GET /api/orders?status=archived โ HTTP 500`
|
|
43
48
|
>
|
|
44
|
-
> **๐ [MEDIUM] The "New: bulk import" badge sits on top of the All orders button**
|
|
49
|
+
> **๐ [MEDIUM] The "New: bulk import" badge sits on top of the All orders button** *(callout 1)*
|
|
45
50
|
> Evidence: `"All orders" overlaps "New: bulk import" (81%)` โ measured from layout boxes, no screenshot needed.
|
|
46
51
|
>
|
|
52
|
+
> **๐ก [LOW] The dashboard chart image is missing** *(callout 2)*
|
|
53
|
+
> Evidence: `GET /img/weekly-chart.png โ HTTP 404`
|
|
54
|
+
>
|
|
47
55
|
> **Gap ledger โ what was NOT tested:** 4/7 visited routes never design-audited ยท single-role run, so permission boundaries are untested
|
|
48
56
|
|
|
49
|
-
Every finding comes with a repro trace and a Playwright regression-test skeleton.
|
|
57
|
+
Every finding comes with a repro trace and a Playwright regression-test skeleton. To try it yourself, clone this repository, run `npm run demo:serve`, then `/scenescout --url http://127.0.0.1:4173` โ see [demo-app/](demo-app/). Its README lists every seeded defect and which oracle catches it.
|
|
50
58
|
|
|
51
59
|
---
|
|
52
60
|
|
|
53
61
|
## โจ Why it's different
|
|
54
62
|
|
|
55
|
-
- ๐ง **
|
|
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
|
|
63
|
+
- ๐ง **Your agent is the brain โ no API key.** The engine contains no LLM. Exploration runs on the agent and subscription you already have (Claude Code, Cursor, Copilot, Codex, Gemini CLI and others); SceneScout just gives it deterministic tools and the method for using them.
|
|
64
|
+
- ๐ **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. Images that failed to load are read from the DOM too. (Screenshots exist only for pixel-native residue like a canvas or a rendering glitch.)
|
|
57
65
|
- ๐ก๏ธ **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
66
|
- โ
**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
67
|
- ๐งญ **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.
|
|
@@ -68,13 +76,13 @@ SceneScout needs only a URL. Give it the source code as well and it gets noticea
|
|
|
68
76
|
|---|---|---|
|
|
69
77
|
| **You run it from** | the app's repository | any folder โ an empty `qa/` directory is fine |
|
|
70
78
|
| **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
|
|
79
|
+
| **How it finds pages** | ๐ reads routes from the source **and** follows links: file-based routing (Next.js, SvelteKit, Nuxt) and router configuration written in code (React Router, Vue Router, Angular). Routes built at runtime are not seen | ๐ follows same-origin links only โ pages nothing links to, or on another subdomain, stay unknown |
|
|
72
80
|
| **"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
81
|
| **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
82
|
| **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
83
|
| **Typical target** | `localhost` while you build | staging, a preview deploy, a client's site |
|
|
76
84
|
|
|
77
|
-
**Why the codebase helps.** The agent driving SceneScout is
|
|
85
|
+
**Why the codebase helps.** The agent driving SceneScout is a coding agent, which can already read your repository. With the source at hand 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
86
|
|
|
79
87
|
**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
88
|
|
|
@@ -87,7 +95,7 @@ SceneScout needs only a URL. Give it the source code as well and it gets noticea
|
|
|
87
95
|
```
|
|
88
96
|
|
|
89
97
|
> [!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.
|
|
98
|
+
> Only test sites you own or are authorized to test. A remote environment is more likely to hold real data, so for a remote URL with no source the skill attaches in **`observe`** mode: nothing but `GET` requests leaves the page. 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. Say so when that is acceptable on your target. See the [safety model](#-safety-model).
|
|
91
99
|
|
|
92
100
|
---
|
|
93
101
|
|
|
@@ -98,44 +106,37 @@ SceneScout needs only a URL. Give it the source code as well and it gets noticea
|
|
|
98
106
|
| | |
|
|
99
107
|
|---|---|
|
|
100
108
|
| **Node** | โฅ 20 |
|
|
101
|
-
| **An MCP client** |
|
|
109
|
+
| **An MCP client** | Claude Code, Cursor, VS Code with Copilot, Codex CLI, Gemini CLI, GitHub Copilot CLI, Windsurf, or [any other](#-other-mcp-clients) |
|
|
102
110
|
| **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
111
|
|
|
104
112
|
### 1๏ธโฃ Install
|
|
105
113
|
|
|
106
|
-
|
|
114
|
+
It is on npm. Nothing to clone:
|
|
107
115
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
/plugin marketplace add brunoboto96/SceneScout
|
|
112
|
-
/plugin install scenescout@scenescout-marketplace
|
|
116
|
+
```bash
|
|
117
|
+
npx -y scenescout install # Claude Code: skill + server + Chromium (one-time download)
|
|
118
|
+
npx -y scenescout install --client cursor # or: vscode, codex, gemini, copilot, windsurf (comma-separated for several)
|
|
113
119
|
```
|
|
114
120
|
|
|
115
|
-
|
|
121
|
+
Either way it downloads the browser and registers the server with the client you named. Claude Code also gets the method as a skill; every other client receives the same method from the server. [What each client gets](#-other-mcp-clients).
|
|
116
122
|
|
|
117
|
-
**
|
|
123
|
+
**Prefer a Claude Code plugin?** The skill and the server arrive together:
|
|
118
124
|
|
|
119
|
-
```
|
|
120
|
-
|
|
125
|
+
```
|
|
126
|
+
/plugin marketplace add brunoboto96/SceneScout
|
|
127
|
+
/plugin install scenescout@scenescout-marketplace
|
|
121
128
|
```
|
|
122
129
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
**C ยท From source**, to hack on it:
|
|
130
|
+
Then download the browser once with `npx -y scenescout install --browser-only`. The command becomes `/scenescout:scenescout`. A plugin's skill comes from this repository and its server from the latest npm release, so right after a release lands here the two can differ for a short while; `/plugin marketplace update scenescout-marketplace` brings the skill up to date.
|
|
126
131
|
|
|
127
|
-
|
|
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
|
+
**A client that is not in that list?** Run `npx -y scenescout install --browser-only` and [add the server to its config by hand](#-other-mcp-clients).
|
|
132
133
|
|
|
133
134
|
<details>
|
|
134
|
-
<summary>What <code>install</code>
|
|
135
|
+
<summary>What <code>install</code> actually does</summary>
|
|
135
136
|
|
|
136
|
-
1.
|
|
137
|
-
2. downloads the
|
|
138
|
-
3. registers the MCP server with Claude Code at user scope
|
|
137
|
+
1. puts 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,
|
|
138
|
+
2. downloads the browser SceneScout drives (skipped if you already have it). By default that is Chromium, as two builds: the full browser for headed runs and the headless shell every other run uses. [Choose something else](#-choosing-browsers) with `--browsers`,
|
|
139
|
+
3. registers the MCP server with Claude Code at user scope. Run through `npx`, the launcher is `npx -y scenescout serve`, with the absolute path of `npx` where one sits beside node, so it works under nvm/fnm. From a clone or a global install it is the absolute node path plus that install's `dist/mcp-server.js`.
|
|
139
140
|
|
|
140
141
|
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
|
|
|
@@ -150,25 +151,31 @@ claude mcp add --scope user scenescout -- npx -y scenescout serve
|
|
|
150
151
|
### 2๏ธโฃ Check it
|
|
151
152
|
|
|
152
153
|
```bash
|
|
153
|
-
npx -y scenescout doctor
|
|
154
|
-
npx -y scenescout doctor
|
|
154
|
+
npx -y scenescout doctor --engine # any client: node + build + browser
|
|
155
|
+
npx -y scenescout doctor # Claude Code: the above, plus the skill and the registration
|
|
155
156
|
```
|
|
156
157
|
|
|
157
158
|
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
|
|
|
159
160
|
### 3๏ธโฃ Run it
|
|
160
161
|
|
|
161
|
-
No app handy? `npm run demo:serve
|
|
162
|
+
No app handy? Clone this repository and run `npm run demo:serve`: the [demo app](demo-app/) starts on `http://127.0.0.1:4173`.
|
|
162
163
|
|
|
163
|
-
|
|
164
|
+
Open your agent inside the project you want to test (or, for a [remote URL](#-two-ways-to-use-it), any folder) and ask:
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
Use SceneScout to test http://localhost:3000 at medium level
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
In Claude Code the skill gives you a command with flags for the same thing:
|
|
164
171
|
|
|
165
172
|
```
|
|
166
173
|
/scenescout --level medium --url http://localhost:3000 --role qa
|
|
167
174
|
```
|
|
168
175
|
|
|
169
|
-
The
|
|
176
|
+
The agent scans the project (if there is one), attaches read-only, explores, and writes findings to `.scenescout/report.md`. That's it.
|
|
170
177
|
|
|
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`.
|
|
178
|
+
**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) ยท `--observe` / `--safe-write` / `--allow-destructive`.
|
|
172
179
|
|
|
173
180
|
---
|
|
174
181
|
|
|
@@ -196,11 +203,11 @@ Snapshots are cheap: re-snapshotting a route returns only *what changed*, with s
|
|
|
196
203
|
|
|
197
204
|
## ๐งฐ The toolbox
|
|
198
205
|
|
|
199
|
-
|
|
206
|
+
25 deterministic tools. The agent picks; you rarely call these by hand.
|
|
200
207
|
|
|
201
208
|
| Phase | Tools | What they do |
|
|
202
209
|
|---|---|---|
|
|
203
|
-
| **Set up** | `scout_scan` `scout_attach` `scout_session` |
|
|
210
|
+
| **Set up** | `scout_playbook` `scout_scan` `scout_attach` `scout_session` | Hand the testing method to an agent that has no skill loaded; discover routes; launch a browser in a write-mode; keep several authenticated roles alive at once |
|
|
204
211
|
| **Explore** | `scout_crawl` `scout_coverage` | Sweep every route in one call; ask what's still untested |
|
|
205
212
|
| **Look** | `scout_snapshot` `scout_hover` `scout_screenshot` | Read the structured scene (diffed); reveal tooltips/hover cards; capture pixels only when needed |
|
|
206
213
|
| **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 |
|
|
@@ -234,6 +241,7 @@ That refusal *is* the guarantee: an extensive report can only exist when nothing
|
|
|
234
241
|
|
|
235
242
|
## ๐ Safety model
|
|
236
243
|
|
|
244
|
+
- ๐ต **`observe`** (`--observe`) lets nothing but `GET` requests leave the page. The one exception is what a session needs in order to exist: logging in, logging out and refreshing a token. Signing up, changing or resetting a password and creating users are blocked like any other write. WebSocket frames are not inspected; the engine says so when the app opens a socket. It is what the skill picks for a remote URL with no source, where an ordinary form POST would create a real record. Forms that could not be submitted are listed in the gap ledger.
|
|
237
245
|
- ๐ข **`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
246
|
- ๐ก **`safe-write`** (`--safe-write`) lets the agent create data and edit/delete **only what it created** this run โ never pre-existing records.
|
|
239
247
|
- ๐ด **`destructive`** (`--allow-destructive`) allows everything, and only ever when *you* confirm the environment is disposable. The skill will never choose this itself.
|
|
@@ -258,37 +266,89 @@ A `๐ก WRITE-POLICY blocked` notice is the safety net doing its job, not an app
|
|
|
258
266
|
|
|
259
267
|
## ๐ฉบ Troubleshooting
|
|
260
268
|
|
|
261
|
-
Run `
|
|
269
|
+
Run `npx -y scenescout doctor` first โ it checks every setup item below (everything but the last row, which is about your app) and prints the fix.
|
|
262
270
|
|
|
263
271
|
| Symptom | Cause and fix |
|
|
264
272
|
|---|---|
|
|
265
|
-
| `/scenescout` isn't a known command | The skill isn't linked, or the session predates it. `
|
|
266
|
-
| The `scout_*` tools don't appear | The MCP server isn't registered, or points at an old path. `
|
|
267
|
-
|
|
|
268
|
-
| *"Executable not found in $PATH"* |
|
|
269
|
-
| *"
|
|
270
|
-
| Tools broke after moving the folder or changing node version | The registration stores absolute paths. `
|
|
273
|
+
| `/scenescout` isn't a known command | The skill isn't linked, or the session predates it. `npx -y scenescout install`, then start a **fresh** Claude Code session. |
|
|
274
|
+
| The `scout_*` tools don't appear | The MCP server isn't registered, or points at an old path. `npx -y scenescout install` re-registers it; `claude mcp list` should show `scenescout` as connected. |
|
|
275
|
+
| *"Executable not found in $PATH"* | The server was registered with a bare `node`. `npx -y scenescout install` registers an absolute path. |
|
|
276
|
+
| Installed as a plugin, and the tools fail with *"Executable not found in $PATH: npx"* | A plugin starts the server with a bare `npx`, which Claude Code can only find if it was launched from an environment that has Node on its `PATH`. Under nvm or fnm that means starting Claude Code from a terminal, not from a dock or launcher. Or use `npx -y scenescout install` instead, which registers the absolute path of `npx`. |
|
|
277
|
+
| *"โฆ build has not been downloaded yet"* on attach | The browser download was skipped or failed, or the run asked for a browser you did not install. Run the command the message names, for example `npx -y scenescout install --browser-only --browsers firefox`. On Linux, system libraries may be missing too: `npx playwright install --with-deps chromium`. |
|
|
278
|
+
| Tools broke after moving the folder or changing node version | The registration stores absolute paths. `npx -y scenescout install` refreshes them. |
|
|
271
279
|
| 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
280
|
|
|
273
281
|
### โฌ๏ธ Upgrading from an older version
|
|
274
282
|
|
|
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 `
|
|
276
|
-
- **Earlier names.** This tool was previously called SceneCraft (and, before that, frontend-tester). `
|
|
283
|
+
- **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 `npx -y scenescout install` so the installed skill matches the server.
|
|
284
|
+
- **Earlier names.** This tool was previously called SceneCraft (and, before that, frontend-tester). `scenescout install` 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
285
|
|
|
278
286
|
### ๐งน Uninstall
|
|
279
287
|
|
|
280
288
|
```bash
|
|
289
|
+
# Claude Code
|
|
281
290
|
claude mcp remove --scope user scenescout
|
|
282
291
|
rm -rf ~/.claude/skills/scenescout
|
|
292
|
+
# Codex / Gemini / Copilot CLI
|
|
293
|
+
codex mcp remove scenescout # likewise: gemini mcp remove โฆ, copilot mcp remove โฆ
|
|
283
294
|
```
|
|
284
295
|
|
|
285
|
-
|
|
296
|
+
For Cursor, Windsurf and VS Code, delete the `scenescout` entry from the client's MCP server list.
|
|
297
|
+
|
|
298
|
+
Nothing else is installed: `npx` runs the package from npm's cache. Per-project memory lives in each tested project's `.scenescout/` folder; delete it there if you want it gone.
|
|
286
299
|
|
|
287
300
|
---
|
|
288
301
|
|
|
302
|
+
## ๐ Choosing browsers
|
|
303
|
+
|
|
304
|
+
`install` downloads Chromium and nothing else unless you ask. `--browsers` takes one name, a comma-separated list, or `all`:
|
|
305
|
+
|
|
306
|
+
| `--browsers` | What is downloaded | About, on disk |
|
|
307
|
+
|---|---|---|
|
|
308
|
+
| `chromium` *(default)* | the full browser and the headless shell | 550 MB |
|
|
309
|
+
| `chromium-headless-shell` | the headless shell only: every run works except `headed` | 200 MB |
|
|
310
|
+
| `firefox` | Firefox | 270 MB |
|
|
311
|
+
| `webkit` | WebKit, the engine behind Safari | 290 MB |
|
|
312
|
+
| `all` | Chromium, Firefox and WebKit | 1.1 GB |
|
|
313
|
+
|
|
314
|
+
```bash
|
|
315
|
+
npx -y scenescout install --browsers chromium-headless-shell # the smallest working setup
|
|
316
|
+
npx -y scenescout install --browser-only --browsers firefox,webkit # add two more later
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Sizes vary by platform. The builds go to Playwright's shared cache, so a build another tool already fetched is not downloaded again.
|
|
320
|
+
|
|
321
|
+
To drive another browser, pass `browser` when attaching (`scout_attach { browser: "firefox" }`), or set `SCENESCOUT_BROWSER=webkit` in the server's environment to change the default. `scenescout doctor` checks the browser named by that variable in the shell it runs from, so check another one with `SCENESCOUT_BROWSER=webkit scenescout doctor`. Two things differ outside Chromium:
|
|
322
|
+
|
|
323
|
+
- **Service workers are not allowed to register** in Firefox and WebKit. The write policy works by intercepting requests, and only Chromium lets a request issued by a service worker be intercepted. An app that depends on its worker may behave differently there.
|
|
324
|
+
- **A Firefox or WebKit left behind by a crash is not cleaned up** on the next start the way a leftover Chromium is.
|
|
325
|
+
|
|
326
|
+
In every browser, pages are not given shared workers unless the mode is `destructive`: a request a shared worker sends cannot be intercepted anywhere, so the app is made to do that work on the page, where the policy sees it.
|
|
327
|
+
|
|
289
328
|
## ๐ Other MCP clients
|
|
290
329
|
|
|
291
|
-
The engine is a plain MCP server over stdio, so any client can drive it
|
|
330
|
+
The engine is a plain MCP server over stdio, so any client can drive it, and the testing method reaches the agent through the server itself (see the end of this section). `install` can register it for you:
|
|
331
|
+
|
|
332
|
+
```bash
|
|
333
|
+
npx -y scenescout install --client cursor # one client
|
|
334
|
+
npx -y scenescout install --client vscode,codex # several; add claude-code to keep that one too
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
| `--client` | How it is registered |
|
|
338
|
+
|---|---|
|
|
339
|
+
| `claude-code` *(default)* | `claude mcp add`, plus the skill |
|
|
340
|
+
| `cursor` | adds an entry to `~/.cursor/mcp.json`, keeping the others |
|
|
341
|
+
| `vscode` | VS Code's own `code --add-mcp`. A `code` command that belongs to another editor is not used |
|
|
342
|
+
| `codex` | `codex mcp add` |
|
|
343
|
+
| `gemini` | `gemini mcp add --scope user` |
|
|
344
|
+
| `copilot` | `copilot mcp add` (GitHub Copilot CLI) |
|
|
345
|
+
| `windsurf` | adds an entry to `~/.codeium/windsurf/mcp_config.json`, keeping the others |
|
|
346
|
+
|
|
347
|
+
A config file that is not valid JSON is left untouched, and the entry to add by hand is printed instead; a config that is a link into a dotfiles repository is written through the link. When a client that is registered through its own command is not installed, `install` says so and prints the command to run later. Cursor and Windsurf are files, so their entry is written whether or not the editor is installed yet. On Windows, a client installed through npm is a `.cmd` shim that `install` cannot start; it prints the command for you to run instead. Then restart the client and ask its agent: *"Use SceneScout to test http://localhost:3000"*.
|
|
348
|
+
|
|
349
|
+
What has been checked: registering through each command above was run against Codex CLI, Gemini CLI, GitHub Copilot CLI and VS Code, and Cursor's command line agent read the entry `install` wrote, connected and listed the tools. The Windsurf path follows its documentation. A full test session has been run in Claude Code, with and without the skill. If a client behaves differently for you, a correction is welcome (say which client version you checked).
|
|
350
|
+
|
|
351
|
+
To register by hand instead, the server entry is always the same command, `npx -y scenescout serve`:
|
|
292
352
|
|
|
293
353
|
<details>
|
|
294
354
|
<summary><strong>Cursor</strong> โ <code>~/.cursor/mcp.json</code> (or <code>.cursor/mcp.json</code> in a project)</summary>
|
|
@@ -327,14 +387,71 @@ args = ["-y", "scenescout", "serve"]
|
|
|
327
387
|
|
|
328
388
|
</details>
|
|
329
389
|
|
|
390
|
+
<details>
|
|
391
|
+
<summary><strong>Gemini CLI</strong> โ <code>~/.gemini/settings.json</code> (or <code>.gemini/settings.json</code> in a project)</summary>
|
|
392
|
+
|
|
393
|
+
```json
|
|
394
|
+
{
|
|
395
|
+
"mcpServers": {
|
|
396
|
+
"scenescout": { "command": "npx", "args": ["-y", "scenescout", "serve"] }
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
</details>
|
|
402
|
+
|
|
403
|
+
<details>
|
|
404
|
+
<summary><strong>Windsurf</strong> โ <code>~/.codeium/windsurf/mcp_config.json</code></summary>
|
|
405
|
+
|
|
406
|
+
```json
|
|
407
|
+
{
|
|
408
|
+
"mcpServers": {
|
|
409
|
+
"scenescout": { "command": "npx", "args": ["-y", "scenescout", "serve"] }
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
</details>
|
|
415
|
+
|
|
416
|
+
<details>
|
|
417
|
+
<summary><strong>Cline</strong> โ MCP Servers โ Configure โ Configure MCP Servers (or <code>~/.cline/mcp.json</code> for the CLI)</summary>
|
|
418
|
+
|
|
419
|
+
```json
|
|
420
|
+
{
|
|
421
|
+
"mcpServers": {
|
|
422
|
+
"scenescout": { "command": "npx", "args": ["-y", "scenescout", "serve"], "disabled": false, "autoApprove": [] }
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
</details>
|
|
428
|
+
|
|
429
|
+
<details>
|
|
430
|
+
<summary><strong>Zed</strong> โ <code>settings.json</code> (command palette: <code>zed: open settings file</code>)</summary>
|
|
431
|
+
|
|
432
|
+
```json
|
|
433
|
+
{
|
|
434
|
+
"context_servers": {
|
|
435
|
+
"scenescout": { "command": "npx", "args": ["-y", "scenescout", "serve"], "env": {} }
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
</details>
|
|
441
|
+
|
|
330
442
|
<details>
|
|
331
443
|
<summary><strong>Anything else</strong></summary>
|
|
332
444
|
|
|
333
|
-
Most clients accept the same `mcpServers` JSON shape shown for Cursor.
|
|
445
|
+
Most clients accept the same `mcpServers` JSON shape shown for Cursor.
|
|
334
446
|
|
|
335
447
|
</details>
|
|
336
448
|
|
|
337
|
-
**The
|
|
449
|
+
**The method travels with the server.** 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. Every other client gets the same text from the server, with nothing to copy:
|
|
450
|
+
|
|
451
|
+
- the server's instructions tell the agent to call `scout_playbook` before its first attach, and that tool returns the method,
|
|
452
|
+
- clients that list server prompts as commands also get an `explore` prompt, which loads the method and takes an optional URL, level and focus.
|
|
453
|
+
|
|
454
|
+
So in any client, a first message like *"Use SceneScout to test http://localhost:3000"* is enough. If an agent starts clicking without having called `scout_playbook`, tell it to call that first; how closely a model follows server instructions varies by client.
|
|
338
455
|
|
|
339
456
|
The CLI is also useful on its own:
|
|
340
457
|
|
|
@@ -349,7 +466,7 @@ npx -y scenescout status <path> # what a running engine is doing right now
|
|
|
349
466
|
|
|
350
467
|
```
|
|
351
468
|
src/
|
|
352
|
-
mcp-server.ts the
|
|
469
|
+
mcp-server.ts the 25 tools + per-session dispatch
|
|
353
470
|
scan.ts project discovery (framework, routes, auth)
|
|
354
471
|
cli.ts scan ยท serve ยท install ยท doctor ยท status
|
|
355
472
|
installer.ts setup logic (skill link, MCP registration, diagnostics)
|
|
@@ -366,9 +483,9 @@ src/
|
|
|
366
483
|
memory.ts cross-run storage + finding dedup
|
|
367
484
|
report.ts the gap ledger + report generation
|
|
368
485
|
โฆ collector ยท dispatch ยท fixtures ยท authloss ยท reaper
|
|
369
|
-
scripts/ the
|
|
486
|
+
scripts/ the 12 test suites (smoke/ holds the real-browser ones)
|
|
370
487
|
test-app/ fixtures for the real-browser smoke tests
|
|
371
|
-
skills/scenescout/ the
|
|
488
|
+
skills/scenescout/ the testing method (SKILL.md): a skill in Claude Code, served by the server everywhere else
|
|
372
489
|
docs/adr/ why it's built this way
|
|
373
490
|
```
|
|
374
491
|
|
|
@@ -391,14 +508,18 @@ The load-bearing choices are recorded as ADRs โ read the relevant one before c
|
|
|
391
508
|
|
|
392
509
|
## ๐ง Development
|
|
393
510
|
|
|
511
|
+
Working on SceneScout itself is the only reason to clone it:
|
|
512
|
+
|
|
394
513
|
```bash
|
|
395
|
-
|
|
396
|
-
npm
|
|
397
|
-
|
|
398
|
-
npm
|
|
514
|
+
git clone https://github.com/brunoboto96/SceneScout.git scenescout && cd scenescout
|
|
515
|
+
npm install # installs dependencies and builds
|
|
516
|
+
npm run setup # same as `scenescout install`, but registers THIS checkout (the skill is linked, so edits are live)
|
|
517
|
+
npm test # build + 12 suites: scan, oracle, policy, fixture, dispatch, design,
|
|
518
|
+
# contract, memory, install, hygiene, smoke, mcp-check
|
|
519
|
+
npm run demo # regenerate examples/ from the demo app
|
|
399
520
|
```
|
|
400
521
|
|
|
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
|
|
522
|
+
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 test` must pass.
|
|
402
523
|
|
|
403
524
|
## ๐ Security
|
|
404
525
|
|
|
@@ -411,7 +532,7 @@ Found a way past the write policy, or another security problem? Please report it
|
|
|
411
532
|
<details>
|
|
412
533
|
<summary><strong>Full capability list</strong> โ every behavior, for the curious</summary>
|
|
413
534
|
|
|
414
|
-
- **Structured render-state, not pixels.** Element lists with geometry; screenshots reserved for pixel-native residue (
|
|
535
|
+
- **Structured render-state, not pixels.** Element lists with geometry; screenshots reserved for pixel-native residue (canvas, rendering glitches). Images that failed to load are reported from the DOM, including ones whose URL answered 200 with something that is not an image.
|
|
415
536
|
- **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
537
|
- **Geometry oracles.** Overlap and off-screen defects computed from layout boxes.
|
|
417
538
|
- **Oracles after every action.** Console errors, page errors, failed requests, HTTP 4xx/5xx drained into every tool result.
|