Coding agents can read CSS. why-ui lets them inspect what the browser actually did.
Find the element covering a button, trace it toward local source, and independently verify the fix after the agent edits code.
Actual Chromium + production extension + MCP. Scripted fixture source edit. 100% sampled blockage → 0%. Evidence and reproduction.
CI · Release · Framework checks · Security
Requires Node 22.13+ and desktop Chrome 116+ with unpacked extensions allowed. CI uses Chromium 153, Linux/Node 22, and Windows/Node 24.
-
Download the extension ZIP. Extract it into a stable directory. In
chrome://extensions, enable Developer mode, select Load unpacked, and choose that directory. Pin the why-ui action. -
Install the GitHub release and pair:
npm install -g https://github.com/Yudis-bit/why-ui/releases/download/v0.1.0/why-ui-0.1.0.tgz why-ui pair
Open extension Options and enter the displayed one-time token and port.
-
Configure your agent's MCP connection below. Open your application in Chrome, select the why-ui action or press Alt+Shift+Y, then move the pointer over the interaction.
why-ui doctor --workspace /path/to/app checks the local installation and prints an
absolute-path MCP configuration, including for Windows. It never prints credentials.
TCP reachability alone does not prove a connected extension or armed tab.
Downloads include SHA256SUMS.txt. Distribution is GitHub-first; no npm-registry
publication is claimed. Prefer source builds? Instructions below.
For Claude Code, run from the application repository:
claude mcp add --transport stdio --scope local why-ui -- why-ui mcp --workspace /path/to/appUse /mcp to check the connection. If your agent cannot resolve the global command
(particularly a Windows npm shim), use the absolute Node command printed by why-ui doctor.
For Cursor, put this in the application's .cursor/mcp.json. Replace the paths with
those printed by why-ui doctor --workspace /path/to/app --json under mcpServer:
{
"mcpServers": {
"why-ui": {
"command": "node",
"args": ["/path/to/why-ui/bin/why-ui.js", "mcp", "--workspace", "/path/to/app"]
}
}
}Claude Code configuration · Cursor configuration. Client formats are documented; automated transport tests use the official MCP SDK. One daemon, one agent connection, and one armed tab are supported at a time.
Call inspect_interaction with {} after pointing at a reachable part of the target.
A fully covered or pointer-transparent target needs a known identity:
{ "target": { "selector": "#payment" }, "maxSamples": 64 }The tool returns a concise human-readable summary and structured evidence: target,
primary blocker, sampled surface, diagnosis, stacking explanation, local source
references with explicit certainty, limitations, and an inspectionId.
After the agent edits source and the application updates:
{ "inspectionId": "<returned inspectionId>", "stabilizationTimeoutMs": 10000 }Call this with verify_fix:
- VERIFIED_PASS: identity reconciles, source/runtime changed, fresh geometry and hits stabilize, the diagnosed failure is absent, and a meaningful Safe Core exists.
- VERIFIED_FAIL: fresh browser evidence still proves a failure, including a new blocker.
- VERIFY_INCONCLUSIVE: identity, readiness, or safe-region evidence is insufficient.
why-ui does not edit code or activate controls. Reflow is normal: old geometry does not establish the result. Verification semantics and thresholds.
flowchart LR
Chrome[Armed Chrome tab] --> Sensor[MAIN-world sensor]
Sensor --> Extension[MV3 extension]
Extension <-->|Authenticated loopback WebSocket| Daemon[Local daemon]
Daemon <-->|MCP stdio| Agent[Coding agent]
Agent -->|Source patch| App[Application]
App -->|HMR / reload| Chrome
Daemon --> Source[Workspace source resolution]
Browser hits establish interaction truth. why-ui explains relevant stacking contexts and maps bounded runtime hints toward local files. The agent reasons about the patch; why-ui independently reruns runtime assertions. Architecture.
Loopback 127.0.0.1 only. Single-use pairing binds an extension Origin and a 32-byte
secret; sessions use HMAC challenge-response. Auth lives in ~/.why-ui/auth.json, mode
0600 where supported. Human logs use stderr; MCP stdout is protocol only.
No cookies, page-storage values, input/textarea contents, full HTML/DOM, screenshots, network bodies, or Fiber props/state are collected during inspection. Bounded labels, IDs, classes, keys and source paths remain evidence visible to the agent. Threat model · Private vulnerability reporting.
React is optional. Tested development setups include Vite/React 18 and Next App Router / Turbopack / React 19 native HMR. Exact versions and limitations. Closed shadow interiors and iframe contents remain opaque. Missing maps become UNMAPPED; static correlations are heuristic. Source-map fetching stays on the app's same loopback origin. Ratios and Safe Core are estimates; handler correctness, keyboard behavior and exact geometric coverage are not proved.
If pairing expires, restart why-ui pair. For lost pairing, stop the MCP process, run
why-ui pair --reset, choose Forget pairing in Options, and pair again. Default port
is 9876; set --port and the Options port together if occupied. Re-arm after cross-origin
navigation. Keep the unpacked extension path stable.
git clone https://github.com/Yudis-bit/why-ui.git
cd why-ui
npm ci
npm run build
node bin/why-ui.js pairLoad dist/extension/ unpacked and configure the agent to run node with this checkout's
absolute bin/why-ui.js path. npm link optionally installs the why-ui command.
npx playwright install --with-deps chromium
npm run typecheck
npm test
npm run test:browser
npm run test:e2e
npm run test:dogfood
npm run test:package
npm run build:extensionContributing · Browser validation · Bridge protocol · Share a UI bug. Licensed under MIT.
