How this skill is triggered — by the user, by Claude, or both
Slash command
/debug-bridge:debug-bridgeThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Control web apps via WebSocket. Click, type, screenshot, inspect, capture network traffic, monitor navigation.
Control web apps via WebSocket. Click, type, screenshot, inspect, capture network traffic, monitor navigation.
The webapp MUST have the debug-bridge SDK installed and configured before agents can control it.
npm install debug-bridge-browser
Create src/debug-bridge.ts (or add to your app's entry point):
import { createDebugBridge } from 'debug-bridge-browser';
// ONLY runs in development - safe to leave in production builds
if (import.meta.env.DEV) {
const params = new URLSearchParams(window.location.search);
const session = params.get('session');
const port = params.get('port') || '4000';
if (session) {
const bridge = createDebugBridge({
url: `ws://localhost:${port}/debug?role=app&sessionId=${session}`,
sessionId: session,
appName: 'My App', // Shows in CLI when connected
appVersion: '1.0.0',
// Feature toggles (all true by default)
enableNetwork: true, // Capture fetch/XHR requests
enableNavigation: true, // Track route changes
enableConsole: true, // Capture console.log/error
enableErrors: true, // Capture unhandled errors
// Optional: filter which URLs to capture
networkUrlFilter: (url) => !url.includes('/analytics'),
maxNetworkBodySize: 10000, // Truncate large request/response bodies
});
bridge.connect();
// Optional: expose for manual debugging
(window as any).__debugBridge = bridge;
}
}
// main.tsx or App.tsx
import './debug-bridge'; // Add this import
?session=X&port=Y from URLrole=approle=agent┌─────────────┐ WebSocket ┌─────────────┐ WebSocket ┌─────────────┐
│ AI Agent │ ◄─────────────────► │ CLI Server │ ◄─────────────────►│ Webapp │
│ │ role=agent │ (port 4000) │ role=app │ (browser) │
└─────────────┘ └─────────────┘ └─────────────┘
Once the webapp has the SDK configured, agents can control it.
# 1. Start debug server (in tmux for persistence)
SESSION="debug-$(date +%s)"
PORT=$(shuf -i 4000-4999 -n 1)
tmux new-session -d -s "$SESSION"
tmux send-keys -t "$SESSION" "npx debug-bridge-cli connect --session $SESSION --port $PORT 2>&1 | tee debug-bridge-$PORT.log" C-m
# 2. Open webapp with debug params (webapp must have SDK installed!)
open "http://localhost:5173?session=$SESSION&port=$PORT"
# 3. Attach to tmux to use CLI
tmux attach -t "$SESSION"
| Command | Example | Description |
|---|---|---|
ui | ui | List interactive elements |
click <target> | click 3 or click "Sign In" | Click element |
type <target> <text> | type 1 "hello" or type "email" "[email protected]" | Type into input |
js <code> | js document.title | Run JavaScript, shows result |
screenshot | screenshot | Save viewport as PNG |
state | state | Get cookies, localStorage |
go <url> | go /login | Navigate to URL |
find <query> | find email | Search UI tree |
eval <code> | eval localStorage.clear() | Alias for js |
help | help | Show all available commands |
AI agents can't attach to terminals interactively. Use tmux send-keys to send commands and tmux capture-pane to read output:
# Send a command to the debug-bridge CLI
tmux send-keys -t "$SESSION" "screenshot" C-m
# Wait for result and read output
sleep 2
tmux capture-pane -t "$SESSION" -p | tail -20
# Run JavaScript in the browser
tmux send-keys -t "$SESSION" "js document.title" C-m
sleep 1
tmux capture-pane -t "$SESSION" -p | tail -5
# Trigger events (e.g., for testing visibility handlers)
tmux send-keys -t "$SESSION" 'eval window.dispatchEvent(new Event("focus"))' C-m
Key Pattern for AI Agents:
tmux send-keystmux capture-paneElements can be targeted by:
click 3 (element #3 from ui output)click "Submit" (matches button/link text)type "email" "[email protected]"click btn-656b07 (hash shown in ui output)// Connect as agent
const ws = new WebSocket(`ws://localhost:4000/debug?role=agent&sessionId=my-session`);
// Base message (required fields)
const msg = {
protocolVersion: 1,
sessionId: 'my-session',
timestamp: Date.now(),
requestId: crypto.randomUUID()
};
// Send commands
ws.send(JSON.stringify({ ...msg, type: 'request_ui_tree' }));
ws.send(JSON.stringify({ ...msg, type: 'click', target: { stableId: 'btn-abc' } }));
ws.send(JSON.stringify({ ...msg, type: 'type', target: { selector: '#email' }, text: '[email protected]' }));
ws.send(JSON.stringify({ ...msg, type: 'evaluate', code: 'document.title' }));
ws.send(JSON.stringify({ ...msg, type: 'request_screenshot' }));
ws.send(JSON.stringify({ ...msg, type: 'navigate', url: '/dashboard' }));
// UI Tree response
{ type: 'ui_tree', items: [{ stableId, role, text, label, visible, meta }] }
// Command success
{ type: 'command_result', success: true, result: any, duration: 5 }
// Screenshot
{ type: 'screenshot', data: 'base64...', width: 1920, height: 1080 }
// Error
{ type: 'command_result', success: false, error: { code: 'TARGET_NOT_FOUND', message: '...' } }
// Network request (auto-streamed)
{ type: 'network_request', requestId: 'net-1-1234', method: 'POST', url: '/api/users', initiator: 'fetch' }
// Network response (auto-streamed)
{ type: 'network_response', requestId: 'net-1-1234', status: 200, statusText: 'OK', duration: 45, ok: true, body: '{"id":1}' }
// Navigation event (auto-streamed)
{ type: 'navigation', url: '/dashboard', previousUrl: '/login', trigger: 'pushstate' }
// Console message (auto-streamed)
{ type: 'console', level: 'error', args: ['Failed to fetch user', '{"status":401}'] }
ui # Discover form elements
type "email" "[email protected]" # Fill email field
type "password" "secret123" # Fill password field
click "Sign In" # Click submit button
screenshot # Capture result for verification
go /register # Navigate to page
ui # List interactive elements
type 1 "John" # Fill first input by index
type 2 "[email protected]" # Fill second input
click "Submit" # Submit form
state # Check localStorage for saved data
ui # See current page state
js localStorage.getItem('token') # Check auth token
js window.__REDUX_STATE__ # Inspect app state
screenshot # Capture for analysis
# Network requests are auto-captured - watch the CLI output:
# 🌐 [POST] /api/login
# ✓ 200 OK (45ms)
# 🌐 [GET] /api/users/me
# ✗ 401 Unauthorized (12ms)
# Navigation is also tracked:
# 🔀 [pushstate] /dashboard
# 🔀 [popstate] /login
// Connect as agent and filter for network events
ws.onmessage = (e) => {
const msg = JSON.parse(e.data);
if (msg.type === 'network_response' && !msg.ok) {
console.log(`API Error: ${msg.status} on request ${msg.requestId}`);
}
if (msg.type === 'navigation') {
console.log(`User navigated to: ${msg.url}`);
}
};
| Error | Cause | Fix |
|---|---|---|
TARGET_NOT_FOUND | Element not in DOM | Run ui to refresh, verify element exists |
TARGET_NOT_VISIBLE | Element off-screen | scroll 0 500 first, then retry |
EVAL_DISABLED | App disabled eval | Use DOM commands instead |
SCREENSHOT_FAILED | Modern CSS (oklch) | Use js to inspect DOM directly |
| No connection | Webapp missing SDK | Verify SDK is installed and initialized |
| Missing network events | SDK config | Check enableNetwork: true in config |
| Missing navigation events | SDK config | Check enableNavigation: true in config |
| Telemetry | Auto-sent | Description |
|---|---|---|
ui_tree | On connect + changes | Interactive elements list |
dom_mutations | Continuous | DOM changes (batched) |
console | Continuous | Console.log/warn/error |
error | On error | Unhandled errors |
network_request | On fetch/XHR | Outgoing API calls |
network_response | On response | API responses with status/body |
navigation | On route change | URL changes (push/pop/replace/hash) |
state_update | On change | Custom app state (if configured) |
# Port already in use
lsof -ti:4000 | xargs kill -9
# Check if server is running
tmux attach -t debug-*
# View server logs
tail -f debug-bridge-*.log
# Webapp not connecting?
# 1. Check URL has ?session=X&port=Y
# 2. Check browser console for [DebugBridge] logs
# 3. Verify SDK is imported in dev mode
Guides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.
npx claudepluginhub stevengonsalvez/agent-bridge --plugin debug-bridge