| name | dev-inspector |
| description | Pick elements in the running dev app's browser and hand them to Claude. When the user refers to "this button", "that card", "the element I just clicked", or anything they've selected in the browser overlay, the picked element (source file + line, component name, CSS selector, DOM snippet, and screenshot) is auto-injected into the prompt via a UserPromptSubmit hook. Invoke this skill to start or verify the bridge — it auto-installs deps and starts the background daemon. The overlay is loaded client-side via bookmarklet or Tampermonkey userscript from http://127.0.0.1:53517/install; the skill never edits the dev app's source code. |
| user-invocable | true |
| allowed-tools | Read, Bash |
Dev Inspector
Bridges a running dev app to Claude Code. User clicks an element in their browser; the selection (source location, component, selector, screenshot) is auto-attached to their next prompt.
Architecture
Browser (dev app) standalone bridge daemon Claude Code
overlay.js ──POST──► localhost:53517 HTTP+WS agent
writes latest.json
│
▼
UserPromptSubmit hook reads+clears
latest.json → prepends to prompt
The bridge runs as a detached background daemon (not an MCP server), so it survives across Claude Code sessions, doesn't block on MCP handshake timeouts, and starts on first /dev-inspector call.
What /dev-inspector does
Every invocation runs ensure-running.sh first — fully idempotent, safe to re-run anytime. The skill never modifies the dev app's source code. The overlay is loaded into the running page via a bookmarklet or Tampermonkey userscript, served from the bridge's /install page.
- Install deps if
mcp-server/node_modules/.installed sentinel is missing or older than package.json.
- Register the
UserPromptSubmit hook in ~/.claude/settings.json if not already present. The hook only takes effect after restarting Claude Code — newly registered hooks are not picked up by the currently running session.
- Start the bridge daemon if
curl http://127.0.0.1:53517/health doesn't respond:
- Clear stale PID file if the previous process is dead.
nohup node server.js --no-mcp → detached background process.
- Save PID to
~/.claude/dev-inspector/bridge.pid, log to bridge.log.
- Wait up to 3s for
/health to go green.
- On first run only, open
http://127.0.0.1:53517/install in the default browser so the user can drag the bookmarklet or install the userscript. A sentinel at ~/.claude/dev-inspector/.install-opened suppresses this on subsequent runs.
- Print status: bridge health, hook path, and the install-page URL.
Skill invocation steps (what Claude runs)
bash ~/.claude/skills/dev-inspector/ensure-running.sh
That is the only action. Do not search the project for index.html, do not offer to edit any file in the dev app repo, and do not suggest adding a Vite plugin or build-time injection. The overlay is strictly client-side (bookmarklet / userscript).
After running: report bridge status, hook status, and the one-liner: "If you haven't already, open http://127.0.0.1:53517/install once to install the bookmarklet or userscript. Then on your dev app press Ctrl+Shift+C, click an element, and ask Claude about it."
If ensure-running.sh output shows the hook was newly registered (line: ✓ hook registered at: ...), also tell the user: "The UserPromptSubmit hook was just registered — restart Claude Code (exit and relaunch) for it to take effect. Selections clicked before restart won't be auto-injected." Skip this line on subsequent runs where the hook already existed.
Usage (user-facing)
/dev-inspector in Claude Code → bridge up, hook registered. First run auto-opens the install page.
- One-time setup on that page: either drag the bookmarklet to your bookmarks bar or install the Tampermonkey userscript (auto-runs on
localhost/127.0.0.1).
- Start your dev server (
npm run dev / whatever).
- Open the app. Click the bookmarklet (or let the userscript auto-run). A dark pill in the bottom-right reads
inspector: off (⌃⇧C).
- Press Ctrl+Shift+C to arm the picker (pill turns teal). A full-viewport transparent capture layer activates.
- Click any element — even disabled form controls (the capture layer bypasses
disabled-element event suppression via elementsFromPoint).
- Switch to Claude Code and type your instruction. The hook auto-injects the latest selection into the prompt.
Captured payload shape
{
"capturedAt": "2026-04-14T04:05:00Z",
"url": "http://localhost:5173/#editor",
"source": { "fileName": "src/components/CanvasArea.jsx", "lineNumber": 142, "columnNumber": 7 },
"component": { "name": "HotspotOverlay", "displayName": "HotspotOverlay" },
"selector": "div.canvas-area > div.hotspot-overlay[data-id='abc']",
"dom": { "tag": "div", "outerHTMLSnippet": "<div class=\"hotspot-overlay\" ...>...</div>" },
"screenshotPath": "~/.claude/dev-inspector/shots/2026-04-14T04-05-00Z.png",
"bounds": { "x": 240, "y": 310, "w": 180, "h": 44 }
}
source.fileName is captured from React fiber _debugSource — present in Vite + @vitejs/plugin-react dev builds, null in production.
Managing the daemon
- Check:
curl http://127.0.0.1:53517/health
- Logs:
tail -f ~/.claude/dev-inspector/bridge.log
- Stop:
kill $(cat ~/.claude/dev-inspector/bridge.pid) && rm ~/.claude/dev-inspector/bridge.pid
- Restart: stop, then
/dev-inspector again.
- Port collision:
DEV_INSPECTOR_PORT=53518 bash ~/.claude/skills/dev-inspector/ensure-running.sh, then re-open http://127.0.0.1:53518/install to grab an updated bookmarklet/userscript pointing at the new port.
Troubleshooting
- Bridge won't start →
tail ~/.claude/dev-inspector/bridge.log. Common cause: port already in use by a previous invocation that wasn't PID-tracked. lsof -i :53517 to find and kill it.
- Overlay loads but pill doesn't appear → hostname isn't
localhost/127.0.0.1. The userscript is guarded to those hosts; the bookmarklet runs anywhere but will only post to the local bridge.
- Hook injects nothing →
~/.claude/dev-inspector/latest.json doesn't exist (no clicks yet) or its mtime is ≤ .last-consumed (already injected into a previous prompt). Each selection is single-shot.
- No source file in payload → Build isn't emitting
_debugSource. Vite with the official React plugin emits it in dev; custom build setups may not. Production builds deliberately don't.
Files
SKILL.md — this file
ensure-running.sh — idempotent bootstrap; runs on every /dev-inspector invocation
mcp-server/bootstrap.cjs — self-bootstrapping entry (deps + server.js), only used if running as MCP
mcp-server/server.js — HTTP+WS bridge; --no-mcp skips MCP stdio handshake (daemon mode)
mcp-server/overlay.js — browser picker overlay (Ctrl+Shift+C, disabled-element safe)
mcp-server/package.json — deps (@modelcontextprotocol/sdk, ws)
hooks/inject-selection.sh — UserPromptSubmit hook, single-shot via mtime watermark
setup.sh — legacy, still works. Kept for backward compatibility; /dev-inspector invokes ensure-running.sh instead.