Agent-first CLI for inspecting React applications through a Playwright-managed browser session.
It gives agents and engineers a structured command surface for React tree snapshots, node inspection, source reveal, deterministic browser interaction, and commit-oriented profiler analysis without opening the DevTools UI. The public CLI is engine-based: auto chooses between the current custom engine and a DevTools-aligned engine when capability checks allow it.
rdttalks to Playwright directly through the Node APIrdt session openis the default local pathrdt session connectis the remote Playwright protocol pathrdt session attachis the Chromium CDP compatibility path
This follows the same overall shape as Playwright's own CLI surface: one command layer, multiple transport modes underneath.
npm install -g react-devtool-cliIf you want an AI coding agent to know how to operate the published rdt CLI, install the bundled react-devtool-cli skill with the method that matches your toolchain.
Copy skills/react-devtool-cli into $CODEX_HOME/skills (~/.codex/skills by default), then restart Codex.
macOS/Linux:
git clone https://github.com/Ring-wdr/react-devtool-cli.git
mkdir -p ~/.codex/skills
cp -R react-devtool-cli/skills/react-devtool-cli ~/.codex/skills/react-devtool-cliWindows PowerShell:
git clone https://github.com/Ring-wdr/react-devtool-cli.git
New-Item -ItemType Directory -Force "$env:USERPROFILE/.codex/skills" | Out-Null
Copy-Item -Recurse -Force ".\\react-devtool-cli\\skills\\react-devtool-cli" "$env:USERPROFILE/.codex/skills/react-devtool-cli"Claude Code discovers skills from ~/.claude/skills/<skill-name>/SKILL.md for personal skills and .claude/skills/<skill-name>/SKILL.md for project-scoped skills. Copy this repository's bundled skill directory into one of those locations:
git clone https://github.com/Ring-wdr/react-devtool-cli.git
mkdir -p ~/.claude/skills
cp -R react-devtool-cli/skills/react-devtool-cli ~/.claude/skills/react-devtool-cliFor project-only usage, copy it to .claude/skills/react-devtool-cli inside your repo instead.
Gemini CLI has built-in skill management. Install directly from this repo:
gemini skills install https://github.com/Ring-wdr/react-devtool-cli.git --path skills/react-devtool-cliIf you already cloned this repository locally, you can also link the whole skills folder and let Gemini discover it:
gemini skills link /path/to/react-devtool-cli/skills --scope workspaceReload discovered skills with /skills reload if the current session is already open.
If you want one installer path that configures the skill for a supported agent automatically, use skills.sh:
npx skills add https://github.com/Ring-wdr/react-devtool-cli --skill react-devtool-cliThis is the easiest cross-tool path when you are using ecosystems such as Claude Code, Gemini CLI, Codex, or Antigravity.
If you are working on the repository itself rather than using the published CLI, install skills/react-devtool-cli-repo with the same tool-specific pattern.
Published package notes:
- npm consumers receive built files from
dist/, not the repository source tree. - repository-only validation artifacts, handoff docs, and local test fixtures are intentionally excluded from the published package.
- This project is maintained by a single maintainer.
- Issues, PRs, and releases are handled on a best-effort basis with no response SLA.
- Reproducible bug reports and narrowly scoped feature proposals are much more likely to be actioned than open-ended support requests.
- Before opening a PR or issue, read CONTRIBUTING.md and SECURITY.md.
- Maintainer operating principles for the public repo are documented in docs/public-repo-strategy.md.
rdt resolves Playwright in this order:
- local
playwright - local
playwright-core RDT_PLAYWRIGHT_PATH- global
playwright - global
playwright-core
rdt session open --url http://localhost:3000 --browser chromium --engine auto --session demo
rdt session connect --ws-endpoint ws://127.0.0.1:3000/ --target-url localhost:3000 --session remote
rdt session attach --cdp-url http://127.0.0.1:9222 --target-url localhost:3000 --session cdp
rdt session doctor --session demo
rdt tree get --session demo
rdt interact type --session demo --selector 'input[name="query"]' --text hello
rdt node search App --session demo --snapshot <snapshotId>
rdt node inspect <nodeId> --session demo --snapshot <snapshotId>
rdt profiler start --session demo
rdt profiler stop --session demo
rdt profiler compare --session demo --left baseline --right candidate
rdt profiler export --session demo --compresstree getreturns asnapshotId.- Node IDs are only meaningful within that snapshot.
- The runtime currently keeps up to
5snapshots in memory per session. - Agent-friendly recommended flow:
- call
tree get - store the returned
snapshotId - pass that
snapshotIdto laternode search,node inspect,node highlight, andsource revealcalls
- call
- If
--snapshotis omitted, commands fall back to the latest collected snapshot. - If an explicitly requested snapshot has been evicted from the runtime cache, commands fail with
snapshot-expired. - Responses from snapshot-aware commands include the
snapshotIdthat was actually used, so agents can pin follow-up calls to it.
rdt session doctor --session <name>reports runtime readiness and trust boundaries before a deeper investigation.- It also reports
enginePreference,selectedEngine,recommendedEngine,availableEngines, and DevTools capability hints so agents know whether they are on a custom fallback or a DevTools-aligned path. sourceCapabilityis reported separately from engine selection._debugSourceis treated as an optional legacy source-mapping capability, not an engine-selection gate.- In React 19+ builds,
_debugSourceis commonly unavailable, sosource revealmay remain partial even whenselectedEngineisdevtools. - It checks React detection, snapshot/inspect readiness, profiler capability,
_debugSourceavailability, and Playwright resolution. - It also reports whether built-in
interactcommands are available on the current session target and whether duration metrics are exposed by the current React runtime. - It also warns when
rdtitself can resolve Playwright but standalone helper scripts may still fail toimport('playwright'). - When that mismatch happens,
doctorreturnshelperImportTargetandhelperImportExampleso agents can import the same Playwright entry thatrdtresolved without reading internal package files. - It returns
recommendedWorkflow,unsafeConclusions, andhelperStrategyso agents can decide whether to trustinteract,profiler, or helper-based fallbacks. - Use it before profiling if browser interaction helpers or ad hoc Node scripts are involved.
- Use built-in
interactcommands before reaching for external Playwright helper scripts. - Current supported actions:
rdt interact click --session <name> --selector <css>rdt interact type --session <name> --selector <css> --text <value>rdt interact press --session <name> --key <name> [--selector <css>]rdt interact wait --session <name> --ms <n>
- These commands execute through the same Playwright session that owns the current
rdtbrowser page. - They target the first matching selector only and return structured action metadata plus trust-boundary fields.
click,type, andpressconfirm that the action was dispatched. They do not guarantee that the page or React tree has fully settled afterward.- When profiling or triggering large rerenders, follow
interactwith an explicit verification step such asinteract wait,tree get,node inspect, or a profiler read command.
Example deterministic flow:
rdt tree get --session demo
# => save snapshotId from output
rdt node search App --session demo --snapshot <snapshotId>
rdt node inspect <nodeId> --session demo --snapshot <snapshotId>
rdt node highlight <nodeId> --session demo --snapshot <snapshotId>
rdt source reveal <nodeId> --session demo --snapshot <snapshotId>Snapshot recovery:
- If you get
snapshot-expired, do not reuse old node IDs. - Run
rdt tree get --session <name>again. - Read the new
snapshotId. - Re-run
node searchagainst the new snapshot before further inspection.
node pick behavior:
node pickcaptures a snapshot-scoped result and returns the same shape asnode inspect.- Agents should persist the returned
snapshotIdand use it for any follow-up commands.
Engine selection:
--engine autois the default and should be preferred for agent workflows.--engine customforces the snapshot-diff engine.--engine devtoolsrequests the DevTools-aligned engine and falls back tocustomwhen capability checks fail.- Inspect
selectedEngine,engineFallback, anddevtoolsCapabilitiesfromsession doctorbefore trusting profiler fidelity. - Do not use
_debugSourceavailability as a reason to overrideselectedEngine; source mapping is tracked independently viasourceCapability. - Snapshot and profiler buffers are now isolated per selected engine, so
auto,custom, anddevtoolsno longer share the same in-memory lookup state.
Performance triage flow:
rdt session open --url http://localhost:3000 --session app
rdt tree get --session app
# => save snapshotId from output as SNAPSHOT_A
rdt node search SlowSearchDemo --session app --snapshot SNAPSHOT_A
rdt node search ResultList --session app --snapshot SNAPSHOT_A
rdt node inspect <nodeId> --session app --snapshot SNAPSHOT_A
rdt profiler start --session app
# in test-app, type one character into "Type to filter products"
rdt profiler stop --session app
rdt profiler summary --session app
rdt profiler commits --session app
rdt profiler ranked <commitId> --session app --limit 10
rdt profiler export --session app --compress
rdt tree get --session app
# => save new snapshotId as SNAPSHOT_B
rdt node search SlowSearchDemo --session app --snapshot SNAPSHOT_B
rdt node inspect <nodeId> --session app --snapshot SNAPSHOT_BUse this flow when an agent needs to answer:
- whether a user action produced more commits than expected
- whether a suspected component changed
props,state,hooks, orcontext - whether the update appears localized or broad across the tree
test-app includes an intentional bottleneck for this flow:
SlowSearchDemoowns the filter stateResultListrenders a large listResultRowrecomputes per-row derived data and receives fresh props on each input change- typing into the filter causes broad re-rendering across the visible list
Profiler interpretation:
- current profiler output is commit-oriented, not component-duration-oriented
- use
commitCount, commit timestamps, andnodeCountto detect suspicious update patterns - prefer
primaryUpdateCommitIdandrecommendedCommitIdsover blindly drilling intocommit-1 - read
commitKind,isLikelyInitialMount, andisInteractionCandidateliterally when deciding whether a commit represents setup noise or a user-triggered update - use follow-up
tree getandnode inspectcalls to infer likely causes from changed state, props, hooks, and context
node pick flow:
rdt node pick --session app
# click the element in Chromium
# => save returned snapshotId and id
rdt node inspect <nodeId> --session app --snapshot <snapshotId>
rdt node highlight <nodeId> --session app --snapshot <snapshotId>
rdt source reveal <nodeId> --session app --snapshot <snapshotId>Use node pick when the agent knows the visible element but not the component name to search for.
- Most structured responses now include:
observationLevellimitationsruntimeWarnings
- Read them literally:
observationLevel: "observed"means the payload is directly observed byrdtlimitationsdescribes what the payload does not proveruntimeWarningshighlights environment or runtime conditions that can mislead follow-up analysis
tagis the numeric React fiber tag.tagNameis the human-readable label derived from that fiber tag.ownerStackis a lightweight owner chain for CLI output, not a full stack frame model.hooksis a simplified serialized view of hook state from the inspected fiber.contextis a serialized view of current context dependencies for the inspected node.sourceprojects_debugSourcewhen available;nullis expected in many dev builds.domis the first host element summary used for CLI highlight and DOM-oriented inspection.- Profiler summary fields are commit-oriented CLI metrics, not the full DevTools profiler session schema.
profiler summaryand exported summaries explicitly report:measurementMode: "actual-duration" | "structural-only" | "mixed"measuresComponentDurationtracksChangedFibers: falsenodeCountMeaning: "live-tree-size-at-commit"
- New profiler drill-down commands:
rdt profiler commits --session <name>rdt profiler commit <commitId> --session <name>rdt profiler ranked <commitId> --session <name> [--limit <n>]rdt profiler flamegraph <commitId> --session <name>rdt profiler compare --session <name> --left <profileId|file> --right <profileId|file>
node inspect --commit <commitId>expects a node id from that commit's profiler views, not from a separatetree getsnapshot.profiler comparecan compare in-memory profile ids from the current session or exported.jsonl/.jsonl.gzprofiler files.- Commit-oriented profiler payloads now expose:
commitKindisLikelyInitialMountisInteractionCandidateprimaryUpdateCommitIdrecommendedCommitIdsobservedReasonsinferredReasonsreasonConfidence
- Read them literally:
commitKind: "initial-mount"usually means setup noise, not the user interaction you just reproducedprimaryUpdateCommitIdis the best follow-up commit candidate when one existsobservedReasonsare direct diffs from adjacent commit snapshotsinferredReasonsare propagation-based explanations such asparent-renderreasonConfidenceis a CLI confidence estimate, not React-internal truth
profiler rankednow includesreasonSummary,hotspotLabel, and compact hotspot summaries.profiler flamegraphnow includeshottestSubtrees,widestChangedSubtrees, andmostCommonReasonsat the root level.
- Current runtime design note: docs/devtools-concept-mapping.md
react-devtools-coreis the primary reference package for concept comparison.react-debug-toolsis installed as a dev-only reference but is currently a low-value implementation reference in this repo state.
- Default command output is
JSON - Compact human-readable output supports
--format yamland--format pretty - Raw profiler export is
NDJSON(.jsonl) orjsonl.gzwith--compress - Exported profiler files now include profile summary metadata so file-based
profiler comparepreserves engine and measurement information.
Bundled skill directories in this repository:
- CLI user skill: skills/react-devtool-cli/SKILL.md
- Repository maintenance skill: skills/react-devtool-cli-repo/SKILL.md
Use the installation routes above to place either skill into your agent's skill directory or installer flow.
- Initial browser support is Chromium-only
session openis the recommended defaultsession connectexpects a PlaywrightwsEndpointsession attachrequires a Chromium instance with CDP enabled and has lower fidelity than Playwright protocol transport- Session status reports
transport,browserName,endpoint,persistent, andcapabilities - Snapshot-aware node workflows are preferred for agents; use the
snapshotIdreturned bytree getfor deterministic follow-up calls - Runtime semantics are documented to align with DevTools concepts where practical, while keeping the CLI snapshot model custom
profiler exportintentionally rejectsYAML; useprofiler summaryfor compact summaries- Global CLI distribution is preferred; Playwright does not need to be pinned as a repo dependency
MIT. See LICENSE.