{"id":"ebbc48ae-9fe6-4043-ae7c-dfcea92635e0","slug":"react-devtool-cli","kind":"skill","name":"react-devtool-cli","summary":"Playwright-native CLI for inspecting live React apps without opening the DevTools UI.","owner":"Ring-wdr","repoUrl":"https://github.com/Ring-wdr/react-devtool-cli","license":"MIT","licenseTier":"permissive","trust":"community","stars":3,"match":null,"fewStars":true,"format":"skill","createdAt":"2026-03-16T07:52:43.000Z","addedAt":"2026-10-21T22:47:56.819Z","logoUrl":"https://avatars.githubusercontent.com/u/70439662?u=ee72d90750d0e195e0f75c3e5f9881f4ebcff3ff&v=4","linkOnly":false,"collection":null,"skillPath":null,"categories":["browser-web","design-media"],"tags":["agent-tooling","cli","debugging","playwright","react","react-devtools","react-profiler"],"runtime":"node","local":true,"cloudCapable":false,"cloudCapability":"unknown","cloudReadyOnPlatform":false,"needsApiKey":false,"reviewed":false,"syncedAt":"2026-10-25T19:38:20.782Z","sample":false,"url":"https://conduits.dev/tools/react-devtool-cli","language":"JavaScript","transports":["stdio"],"install":{"npm":"react-devtool-cli"},"requirements":{"env":[],"upstreamMayCharge":false},"tools":null,"readme":"# react-devtool-cli\n\nAgent-first CLI for inspecting React applications through a Playwright-managed browser session.\n\nIt 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.\n\nProject site: https://ring-wdr.github.io/react-devtool-cli/\n\n## Recommended architecture\n\n- `rdt` talks to Playwright directly through the Node API\n- `rdt session open` is the default local path\n- `rdt session connect` is the remote Playwright protocol path\n- `rdt session attach` is the Chromium CDP compatibility path\n\nThis follows the same overall shape as Playwright's own CLI surface: one command layer, multiple transport modes underneath.\n\n## Install\n\n```bash\nnpm install -g react-devtool-cli\n```\n\n## Install the bundled agent skill\n\nIf 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.\n\n### Codex\n\nCopy `skills/react-devtool-cli` into `$CODEX_HOME/skills` (`~/.codex/skills` by default), then restart Codex.\n\nmacOS/Linux:\n\n```bash\ngit clone https://github.com/Ring-wdr/react-devtool-cli.git\nmkdir -p ~/.codex/skills\ncp -R react-devtool-cli/skills/react-devtool-cli ~/.codex/skills/react-devtool-cli\n```\n\nWindows PowerShell:\n\n```powershell\ngit clone https://github.com/Ring-wdr/react-devtool-cli.git\nNew-Item -ItemType Directory -Force \"$env:USERPROFILE/.codex/skills\" | Out-Null\nCopy-Item -Recurse -Force \".\\\\react-devtool-cli\\\\skills\\\\react-devtool-cli\" \"$env:USERPROFILE/.codex/skills/react-devtool-cli\"\n```\n\n### Claude Code\n\nClaude 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:\n\n```bash\ngit clone https://github.com/Ring-wdr/react-devtool-cli.git\nmkdir -p ~/.claude/skills\ncp -R react-devtool-cli/skills/react-devtool-cli ~/.claude/skills/react-devtool-cli\n```\n\nFor project-only usage, copy it to `.claude/skills/react-devtool-cli` inside your repo instead.\n\n### Gemini CLI\n\nGemini CLI has built-in skill management. Install directly from this repo:\n\n```bash\ngemini skills install https://github.com/Ring-wdr/react-devtool-cli.git --path skills/react-devtool-cli\n```\n\nIf you already cloned this repository locally, you can also link the whole skills folder and let Gemini discover it:\n\n```bash\ngemini skills link /path/to/react-devtool-cli/skills --scope workspace\n```\n\nReload discovered skills with `/skills reload` if the current session is already open.\n\n### skills.sh\n\nIf you want one installer path that configures the skill for a supported agent automatically, use `skills.sh`:\n\n```bash\nnpx skills add https://github.com/Ring-wdr/react-devtool-cli --skill react-devtool-cli\n```\n\nThis is the easiest cross-tool path when you are using ecosystems such as Claude Code, Gemini CLI, Codex, or Antigravity.\n\nIf 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.\n\nPublished package notes:\n\n- npm consumers receive built files from `dist/`, not the repository source tree.\n- repository-only validation artifacts, handoff docs, and local test fixtures are intentionally excluded from the published package.\n\n## Public Repository Expectations\n\n- This project is maintained by a single maintainer.\n- Issues, PRs, and releases are handled on a best-effort basis with no response SLA.\n- Reproducible bug reports and narrowly scoped feature proposals are much more likely to be actioned than open-ended support requests.\n- Before opening a PR or issue, read [CONTRIBUTING.md](./CONTRIBUTING.md) and [SECURITY.md](./SECURITY.md).\n- Maintainer operating principles for the public repo are documented in [docs/public-repo-strategy.md](./docs/public-repo-strategy.md).\n\n`rdt` resolves Playwright in this order:\n\n- local `playwright`\n- local `playwright-core`\n- `RDT_PLAYWRIGHT_PATH`\n- global `playwright`\n- global `playwright-core`\n\n## Commands\n\n```bash\nrdt doctor --session demo\nrdt session open --url http://localhost:3000 --browser chromium --engine auto --session demo\nrdt session connect --ws-endpoint ws://127.0.0.1:3000/ --target-url localhost:3000 --session remote\nrdt session attach --cdp-url http://127.0.0.1:9222 --target-url localhost:3000 --session cdp\nrdt session doctor --session demo\nrdt tree get --session demo\nrdt tree stats --session demo --top 5\nrdt interact type --session demo --selector 'input[name=\"query\"]' --text hello\nrdt node search App --session demo --snapshot <snapshotId> --structured\nrdt node inspect <nodeId> --session demo --snapshot <snapshotId>\nrdt profiler start --session demo\nrdt profiler stop --session demo\nrdt profiler compare --session demo --left baseline --right candidate\nrdt profiler export --session demo --compress\n```\n\n## Snapshot Semantics\n\n- `tree get` returns a `snapshotId`.\n- `tree stats` returns the same `snapshotId` plus summary fields such as `rootCount`, `nodeCount`, `rootSummaries`, and `topLevelComponents`.\n- Node IDs are only meaningful within that snapshot.\n- The runtime currently keeps up to `5` snapshots in memory per session.\n- Agent-friendly recommended flow:\n  1. call `tree get`\n  2. store the returned `snapshotId`\n  3. pass that `snapshotId` to later `node search`, `node inspect`, `node highlight`, and `source reveal` calls\n- If `--snapshot` is omitted, commands fall back to the latest collected snapshot.\n- If an explicitly requested snapshot has been evicted from the runtime cache, commands fail with `snapshot-expired`.\n- Responses from snapshot-aware commands include the `snapshotId` that was actually used, so agents can pin follow-up calls to it.\n\n## Doctor\n\n- `rdt session doctor --session <name>` reports runtime readiness and trust boundaries before a deeper investigation.\n- `rdt doctor --session <name>` is a first-class alias for the same command.\n- 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.\n- `sourceCapability` is reported separately from engine selection.\n- `_debugSource` is treated as an optional legacy source-mapping capability, not an engine-selection gate.\n- In React 19+ builds, `_debugSource` is commonly unavailable, so `source reveal` may remain partial even when `selectedEngine` is `devtools`.\n- It checks React detection, snapshot/inspect readiness, profiler capability, `_debugSource` availability, and Playwright resolution.\n- It also reports whether built-in `interact` commands are available on the current session target and whether duration metrics are exposed by the current React runtime.\n- It also warns when `rdt` itself can resolve Playwright but standalone helper scripts may still fail to `import('playwright')`.\n- When that mismatch happens, `doctor` returns `helperImportTarget` and `helperImportExample` so agents can import the same Playwright entry that `rdt` resolved without reading internal package files.\n- It returns `recommendedWorkflow`, `unsafeConclusions`, and `helperStrategy` so agents can decide whether to trust `interact`, `profiler`, or helper-based fallbacks.\n- Use it before profiling if browser interaction helpers or ad hoc Node scripts are involved.\n\n## Interact\n\n- Use built-in `interact` commands before reaching for external Playwright helper scripts.\n- Current supported actions:\n  - `rdt interact click --session <name> (--selector <css> | --text <value> | --role <role>) [--nth <index>] [--strict] [--delivery auto|playwright|dom]`\n  - `rdt interact type --session <name> (--selector <css> | --target-text <label> | --role <role>) [--nth <index>] [--strict] --text <value>`\n  - `rdt interact press --session <name> --key <name> [--selector <css> | --target-text <label> | --role <role>] [--nth <index>] [--strict]`\n  - `rdt interact wait --session <name> --ms <n>`\n- These commands execute through the same Playwright session that owns the current `rdt` browser page.\n- `interact click` can resolve targets by CSS selector, visible text, or ARIA role.\n- `interact type` and targeted `interact press` can resolve controls by CSS selector, label text, or ARIA role.\n- `interact press` without a target remains a page-level keyboard action for compatibility; use a target when focus ambiguity would make the result nondeterministic.\n- `--nth` selects one match from a broader result set, and `--strict` requires exactly one match.\n- For `interact type` and targeted `interact press`, `--strict` and `--nth` only make sense when one of `--selector`, `--target-text`, or `--role` is present.\n- Responses now include `targetingStrategy`, `targetingResolution`, `matchCount`, and `resolvedNth` alongside the delivery metadata.\n- `interact click` defaults to `--delivery auto`.\n- In `auto`, profiler-active clicks fall back to DOM dispatch and report `requestedDelivery`, `effectiveDelivery`, `profilerActive`, and `fallbackApplied`.\n- Use `--delivery playwright` to force Playwright pointer input, or `--delivery dom` to force DOM dispatch.\n- `click`, `type`, and `press` confirm that the action was dispatched. They do not guarantee that the page or React tree has fully settled afterward.\n- When profiling or triggering large rerenders, follow `interact` with an explicit verification step such as `interact wait`, `tree get`, `node inspect`, or a profiler read command.\n\nExample deterministic flow:\n\n```bash\nrdt tree get --session demo\n# => save snapshotId from output\nrdt node search App --session demo --snapshot <snapshotId> --structured\nrdt node inspect <nodeId> --session demo --snapshot <snapshotId>\nrdt node highlight <nodeId> --session demo --snapshot <snapshotId>\nrdt source reveal <nodeId> --session demo --snapshot <snapshotId> --structured\n```\n\nSnapshot recovery:\n\n- If you get `snapshot-expired`, do not reuse old node IDs.\n- Run `rdt tree get --session <name>` again.\n- Read the new `snapshotId`.\n- Re-run `node search` against the new snapshot before further inspection.\n\n`node pick` behavior:\n\n- `node pick` captures a snapshot-scoped result and returns the same shape as `node inspect`.\n- Agents should persist the returned `snapshotId` and use it for any follow-up commands.\n\n## Practical Workflows\n\nEngine selection:\n\n- `--engine auto` is the default and should be preferred for agent workflows.\n- `--engine custom` forces the snapshot-diff engine.\n- `--engine devtools` requests the DevTools-aligned engine and falls back to `custom` when capability checks fail.\n- Inspect `selectedEngine`, `engineFallback`, and `devtoolsCapabilities` from `session doctor` before trusting profiler fidelity.\n- Do not use `_debugSource` availability as a reason to override `selectedEngine`; source mapping is tracked independently via `sourceCapability`.\n- Snapshot and profiler buffers are now isolated per selected engine, so `auto`, `custom`, and `devtools` no longer share the same in-memory lookup state.\n\nPerformance triage flow:\n\n```bash\nrdt session open --url http://localhost:3000 --session app\nrdt tree get --session app\n# => save snapshotId from output as SNAPSHOT_A\nrdt node search SlowSearchDemo --session app --snapshot SNAPSHOT_A\nrdt node search ResultList --session app --snapshot SNAPSHOT_A\nrdt node inspect <nodeId> --session app --snapshot SNAPSHOT_A\nrdt profiler start --session app\n# in test-app, type one character into \"Type to filter products\"\nrdt profiler stop --session app\nrdt profiler summary --session app\nrdt profiler commits --session app\nrdt profiler ranked <commitId> --session app --limit 10\nrdt profiler export --session app --compress\nrdt tree get --session app\n# => save new snapshotId as SNAPSHOT_B\nrdt node search SlowSearchDemo --session app --snapshot SNAPSHOT_B\nrdt node inspect <nodeId> --session app --snapshot SNAPSHOT_B\n```\n\nUse this flow when an agent needs to answer:\n\n- whether a user action produced more commits than expected\n- whether a suspected component changed `props`, `state`, `hooks`, or `context`\n- whether the update appears localized or broad across the tree\n\n`test-app` includes an intentional bottleneck for this flow:\n\n- `SlowSearchDemo` owns the filter state\n- `ResultList` renders a large list\n- `ResultRow` recomputes per-row derived data and receives fresh props on each input change\n- typing into the filter causes broad re-rendering across the visible list\n\nProfiler interpretation:\n\n- current profiler output is commit-oriented, not component-duration-oriented\n- use `commitCount`, commit timestamps, and `nodeCount` to detect suspicious update patterns\n- prefer `primaryUpdateCommitId` and `recommendedCommitIds` over blindly drilling into `commit-1`\n- read `commitKind`, `isLikelyInitialMount`, and `isInteractionCandidate` literally when deciding whether a commit represents setup noise or a user-triggered update\n- use follow-up `tree get` and `node inspect` calls to infer likely causes from changed state, props, hooks, and context\n\n`node pick` flow:\n\n```bash\nrdt node pick --session app\n# click the element in Chromium\n# => save returned snapshotId and id\nrdt node inspect <nodeId> --session app --snapshot <snapshotId>\nrdt node highlight <nodeId> --session app --snapshot <snapshotId>\nrdt source reveal <nodeId> --session app --snapshot <snapshotId>\n```\n\nUse `node pick` when the agent knows the visible element but not the component name to search for.\n\n## Response Semantics\n\n- Most structured responses now include:\n  - `observationLevel`\n  - `limitations`\n  - `runtimeWarnings`\n- Read them literally:\n  - `observationLevel: \"observed\"` means the payload is directly observed by `rdt`\n  - `limitations` describes what the payload does not prove\n  - `runtimeWarnings` highlights environment or runtime conditions that can mislead follow-up analysis\n- `tag` is the numeric React fiber tag.\n- `tagName` is the human-readable label derived from that fiber tag.\n- `ownerStack` is a lightweight owner chain for CLI output, not a full stack frame model.\n- `hooks` is a simplified serialized view of hook state from the inspected fiber.\n- `context` is a serialized view of current context dependencies for the inspected node.\n- `source` projects `_debugSource` when available; `null` is expected in many dev builds.\n- `source reveal --structured` returns `status`, `available`, `mode`, `reason`, and `source` so automation can distinguish unavailable source data from a successful source payload.\n- `source reveal` without `--structured` preserves the raw legacy behavior and may return literal `null`.\n- `dom` is the first host element summary used for CLI highlight and DOM-oriented inspection.\n- `node search --structured` wraps search results in `{ items, query, snapshotId, matchCount, returnedCount, truncated, runtimeWarnings }`.\n- `node search --limit <n>` trims the returned items to the requested count while preserving the full `matchCount`.\n- When `node search --structured` returns `matchCount: 0`, `runtimeWarnings` explains that the component may be absent from the current snapshot rather than absent from the codebase.\n- Profiler summary fields are commit-oriented CLI metrics, not the full DevTools profiler session schema.\n- `profiler summary` and exported summaries explicitly report:\n  - `measurementMode: \"actual-duration\" | \"structural-only\" | \"mixed\"`\n  - `measuresComponentDuration`\n  - `tracksChangedFibers: false`\n  - `nodeCountMeaning: \"live-tree-size-at-commit\"`\n- New profiler drill-down commands:\n  - `rdt profiler commits --session <name>`\n  - `rdt profiler commit <commitId> --session <name>`\n  - `rdt profiler ranked <commitId> --session <name> [--limit <n>]`\n  - `rdt profiler flamegraph <commitId> --session <name>`\n  - `rdt profiler compare --session <name> --left <profileId|file> --right <profileId|file>`\n- `node inspect --commit <commitId>` expects a node id from that commit's profiler views, not from a separate `tree get` snapshot.\n- `profiler compare` can compare in-memory profile ids from the current session or exported `.jsonl` / `.jsonl.gz` profiler files.\n- Commit-oriented profiler payloads now expose:\n  - `commitKind`\n  - `isLikelyInitialMount`\n  - `isInteractionCandidate`\n  - `primaryUpdateCommitId`\n  - `recommendedCommitIds`\n  - `observedReasons`\n  - `inferredReasons`\n  - `reasonConfidence`\n- Read them literally:\n  - `commitKind: \"initial-mount\"` usually means setup noise, not the user interaction you just reproduced\n  - `primaryUpdateCommitId` is the best follow-up commit candidate when one exists\n  - `observedReasons` are direct diffs from adjacent commit snapshots\n  - `inferredReasons` are propagation-based explanations such as `parent-render`\n  - `reasonConfidence` is a CLI confidence estimate, not React-internal truth\n- `profiler ranked` now includes `reasonSummary`, `hotspotLabel`, and compact hotspot summaries.\n- `profiler flamegraph` now includes `hottestSubtrees`, `widestChangedSubtrees`, and `mostCommonReasons` at the root level.\n\n## Concept Alignment\n\n- Current runtime design note: [docs/devtools-concept-mapping.md](./docs/devtools-concept-mapping.md)\n- `react-devtools-core` is the primary reference package for concept comparison.\n- `react-debug-tools` is installed as a dev-only reference but is currently a low-value implementation reference in this repo state.\n\n## Output formats\n\n- Default command output is `JSON`\n- Compact human-readable output supports `--format yaml` and `--format pretty`\n- Raw profiler export is `NDJSON` (`.jsonl`) or `jsonl.gz` with `--compress`\n- Exported profiler files now include profile summary metadata so file-based `profiler compare` preserves engine and measurement information.\n\n## Skills\n\nBundled skill directories in this repository:\n\n- CLI user skill: [skills/react-devtool-cli/SKILL.md](./skills/react-devtool-cli/SKILL.md)\n- Repository maintenance skill: [skills/react-devtool-cli-repo/SKILL.md](./skills/react-devtool-cli-repo/SKILL.md)\n\nUse the installation routes above to place either skill into your agent's skill directory or installer flow.\n\n## Notes\n\n- Initial browser support is Chromium-only\n- `session open` is the recommended default\n- `session connect` expects a Playwright `wsEndpoint`\n- `session attach` requires a Chromium instance with CDP enabled and has lower fidelity than Playwright protocol transport\n- Session status reports `transport`, `browserName`, `endpoint`, `persistent`, and `capabilities`\n- Snapshot-aware node workflows are preferred for agents; use the `snapshotId` returned by `tree get` for deterministic follow-up calls\n- Runtime semantics are documented to align with DevTools concepts where practical, while keeping the CLI snapshot model custom\n- `profiler export` intentionally rejects `YAML`; use `profiler summary` for compact summaries\n- Global CLI distribution is preferred; Playwright does not need to be pinned as a repo dependency\n\n## License\n\nMIT. See [LICENSE](./LICENSE).\n"}