agent-react-devtools
Give your AI agent eyes into your React app. Inspect component trees, read props and state, and profile rendering performance — all from the command line. Inspired by Vercel's agent-browser and Callstack's agent-device.
The project is in early development and considered experimental. Pull requests are welcome!
Features
- Walk the full component tree with props, state, and hooks
- Search for components by display name
- Profile renders: find slow components, excessive re-renders, and commit timelines
- Persistent background daemon that survives across CLI calls
- Token-efficient output built for LLM consumption
Install
npm install -g agent-react-devtools
Or run it directly:
npx agent-react-devtools start
Quick Start
agent-react-devtools start
agent-react-devtools status
Daemon: running (port 8097)
Apps: 1 connected, 24 components
Uptime: 12s
Last event: app connected 3s ago
Browse the component tree:
agent-react-devtools get tree --depth 3
@c1 [fn] App
├─ @c2 [fn] Header
│ ├─ @c3 [fn] Nav
│ └─ @c4 [fn] SearchBar
├─ @c5 [fn] TodoList
│ ├─ @c6 [fn] TodoItem key=1
│ ├─ @c7 [fn] TodoItem key=2
│ ├─ @c8 [fn] TodoItem key=3
│ └─ ... +47 more TodoItem
└─ @c9 [fn] Footer
53 components shown (1,843 total)
Host components ( View a subtree rooted at a specific component: Inspect a component's props, state, and hooks: Find components by name: Profile rendering performance: Tree output flags:
Components with errors or warnings are annotated in tree and search output: Use the Block until a condition is met. Useful in scripts or agent workflows where the daemon starts before the app: Exits with code 0 when the condition is met, or code 1 on timeout. For Vite, Next.js, and Create React App, run For standard React Native and Expo projects, To undo these changes: Add a single import as the first line of your entry point (e.g. This handles everything: deleting the Vite hook stub, initializing react-devtools-core, and connecting via WebSocket. Your app is never blocked — if the daemon isn't running, it times out after 2 seconds. For Vite apps, use the plugin instead — no changes to your app code needed: export default defineConfig({
plugins: [reactDevtools(), react()],
}); The plugin only runs in dev mode ( Options: Both of the following steps are required. For a bare React Native app: const projectConfig = {};
const config = mergeConfig(getDefaultConfig(__dirname), projectConfig); module.exports = withAgentReactDevTools(config); For Expo: const config = getDefaultConfig(__dirname); module.exports = withAgentReactDevTools(config); Apply Add this import to a user-owned module that is always reachable from the app
entry—for example, bare React Native's The import makes the bootstrap part of Metro's dependency graph. The Metro
wrapper then executes that module before application modules; its textual
position among imports does not control the execution order. The client and daemon use port 8097 by default: For an Android device connected over USB, forward the DevTools port before
launching the app: This integration connects only from a native development runtime. Native
production builds exit without connecting; browser and default/server imports
resolve to no-op modules. If Configure the two steps above manually when Metro uses ESM ( When using Add the skill to your AI coding assistant for richer context: This works with Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, Goose, OpenCode, and Windsurf. You can also install via the Claude Code plugin marketplace: Codex discovers project skills from If your assistant does not auto-load skills, add something like this to your project's This project uses agent-react-devtools to inspect the running React app. MIT, etc.) are filtered by default to keep output compact. Use --all to include them. Host components with keys or custom element names (e.g. ) are always shown.
agent-react-devtools get tree @c5 --depth 2@c1 [fn] TodoList
├─ @c2 [fn] TodoItem key=1
├─ @c3 [fn] TodoItem key=2
└─ @c4 [fn] TodoItem key=3agent-react-devtools get component @c6@c6 [fn] TodoItem key=1
props:
id: 1
text: "Buy groceries"
done: false
onToggle: ƒ
hooks:
State: false
Callback: ƒagent-react-devtools find TodoItem@c6 [fn] TodoItem key=1
@c7 [fn] TodoItem key=2
@c8 [fn] TodoItem key=3agent-react-devtools profile start
... interact with the app ...
agent-react-devtools profile stop
agent-react-devtools profile slowSlowest (by avg render time):
@c5 [fn] TodoList avg:4.2ms max:8.1ms renders:6 causes:props-changed changed: props: items, onDelete
@c4 [fn] SearchBar avg:2.1ms max:3.4ms renders:12 causes:hooks-changed changed: hooks: #0
@c2 [fn] Header avg:0.8ms max:1.2ms renders:3 causes:parent-renderedCommands
Daemon
agent-react-devtools start [--port 8097] # Start daemon
agent-react-devtools stop # Stop daemon
agent-react-devtools status # Connection statusComponents
agent-react-devtools get tree [@c1 | id] [--depth N] [--all] [--max-lines N] # Component hierarchy (subtree)
agent-react-devtools get component <@c1 | id> # Props, state, hooks
agent-react-devtools find <name> [--exact] # Search by display name
agent-react-devtools count # Component count by type
agent-react-devtools errors # Components with errors/warnings
Components are labeled --depth N — limit tree depth--all — include host components (filtered by default)--max-lines N — hard cap on output lines@c1, @c2, etc. You can use these labels or numeric IDs interchangeably.
@c5 [fn] Form ⚠2 ✗1errors command to list only components with issues:agent-react-devtools errors@c5 [fn] Form ⚠2 ✗1
@c8 [fn] Input ✗3Wait
agent-react-devtools wait --connected [--timeout 30] # Block until an app connects
agent-react-devtools wait --component App [--timeout 30] # Block until a component appearsProfiling
agent-react-devtools profile start [name] # Begin a profiling session
agent-react-devtools profile stop # Stop and collect data
agent-react-devtools profile report <@c1 | id> # Render report for a component
agent-react-devtools profile slow [--limit N] # Slowest components by avg duration
agent-react-devtools profile rerenders [--limit N] # Most re-rendered components
agent-react-devtools profile timeline [--limit N] # Commit timeline
agent-react-devtools profile commit <N | #N> [--limit N] # Single commit detail
agent-react-devtools profile export <file> # Export as React DevTools Profiler JSON
agent-react-devtools profile diff <before.json> <after.json> [--limit N] [--threshold N] # Compare two exportsConnecting Your App
Quick setup
init in the project root to
patch the appropriate web entry or config:npx agent-react-devtools initinit also configures Metro and a
reachable app module. It supports existing CommonJS (.js/.cjs) Metro
configs and creates one when none exists. Use the manual setup below for ESM,
TypeScript, JSON/package-field, custom --config, or ambiguous Metro setups.npx agent-react-devtools uninitWeb one-line import
src/main.tsx):import "agent-react-devtools/connect";Vite plugin
// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { reactDevtools } from "agent-react-devtools/vite";
vite dev), not in production builds.reactDevtools({ port: 8097, host: "localhost" });React Native
Before React Native 0.87, standalone DevTools connected automatically without
code changes. React Native 0.87 removed that path, so the setup below is now
required.
npm install --save-dev agent-react-devtoolsnpx agent-react-devtools init performs both steps automatically for the
common CommonJS Metro configurations and entries it recognizes: package.json
main, Expo Router's root layout, bare index., and Expo App.. It patches
all available platform-specific entries when a shared entry does not exist.
The CLI first preflights every target and leaves files unchanged when it cannot
safely identify the config or entry. uninit removes only its marked edits.1. Wrap the final Metro config
// metro.config.js
const { getDefaultConfig, mergeConfig } = require("@react-native/metro-config");
const { withAgentReactDevTools } = require("agent-react-devtools/metro");
// metro.config.js
const { getDefaultConfig } = require("expo/metro-config");
const { withAgentReactDevTools } = require("agent-react-devtools/metro");
withAgentReactDevTools outermost, after all other Metro configuration
and wrappers. It preserves the final config's existing serializer hooks and
adds the agent bootstrap after React Native's own pre-main initialization.2. Import the bootstrap from the entry graph
index.js or Expo Router's
app/_layout.tsx:import "agent-react-devtools/react-native";Run and verify
# Terminal 1
agent-react-devtools start
Terminal 2 — restart Metro after changing metro.config.js
npx react-native start
Expo: npx expo start
Terminal 3
agent-react-devtools status
agent-react-devtools wait --connected --timeout 30
agent-react-devtools get treeadb reverse tcp:8097 tcp:8097status reports zero connected apps:withAgentReactDevTools wraps the final config, outside other Metro wrappers.--reset-cache (bare) or npx expo start -c.adb reverse for Android devices.Manual fallback
.mjs),
TypeScript, JSON or a package-field configuration; when your app starts Metro
with a custom --config; or when the CLI reports an ambiguous config or entry.
Keep withAgentReactDevTools as the final outermost wrapper.Using with agent-browser
agent-browser to drive the app (e.g. for profiling interactions), you must use headed mode. Headless Chromium does not properly execute the devtools connect script:agent-browser --session devtools --headed open http://localhost:5173/
agent-react-devtools status # Should show "Apps: 1 connected"Using with AI Coding Assistants
npx skills add callstackincubator/agent-react-devtoolsClaude Code plugin
/plugin marketplace add callstackincubator/agent-react-devtools
/plugin install agent-react-devtools@piotrskiCodex
AGENTS.md. This repo includes one at the root that registers:packages/agent-react-devtools/skills/react-devtools/SKILL.mdManual setup
AGENTS.md, CLAUDE.md, or equivalent agent instructions:## React Debugging
agent-react-devtools start — start the daemonagent-react-devtools status — check if the app is connectedagent-react-devtools get tree — see the component hierarchyagent-react-devtools get tree @c5 — see subtree from a specific componentagent-react-devtools get component @c1 — inspect a specific componentagent-react-devtools find <Name> — search for componentsagent-react-devtools errors — list components with errors or warningsagent-react-devtools profile start / profile stop / profile slow — diagnose render performanceDevelopment
bun install # Install dependencies
bun run build # Build
bun run test # Run tests
bun run typecheck # Type checkLicense