Skip to content

Commit 730ffa7

Browse files
Lykhoydaclaude
andauthored
docs(site): dedicated React Native DevTools coexistence guide (#269)
New guides/devtools-coexistence page written for the reported symptoms ("second DevTools window" eviction + __RN_NET__ console spam), linked from a new Guides sidebar group and a troubleshooting tip; the maestro-interop section becomes a pointer. Tool docs regenerated (catches up cdp_status/cdp_wait_for_network/cdp_network_body from PR #267 plus stale device_fill/maestro_run descriptions). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent b54df6f commit 730ffa7

9 files changed

Lines changed: 78 additions & 24 deletions

File tree

docs-site/astro.config.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ export default defineConfig({
132132
},
133133
],
134134
},
135+
{
136+
label: 'Guides',
137+
items: [
138+
{ label: 'React Native DevTools coexistence', slug: 'guides/devtools-coexistence' },
139+
{ label: 'maestro-mcp interop', slug: 'guides/maestro-interop' },
140+
],
141+
},
135142
{ label: 'Benchmarks', slug: 'benchmarks' },
136143
{ label: 'Troubleshooting', slug: 'troubleshooting' },
137144
{ label: 'Changelog', slug: 'changelog' },
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
title: Using rn-dev-agent with React Native DevTools
3+
description: Stop the CDP bridge from kicking React Native DevTools off the debugger seat, and what happened to the __RN_NET__ console spam.
4+
---
5+
6+
import { Aside } from '@astrojs/starlight/components';
7+
8+
You open React Native DevTools and it immediately disconnects with **"Disconnected due to opening a second DevTools window"**. Or your Metro logs are full of `__RN_NET__:request:{...}` lines. Both come from the rn-dev-agent CDP bridge — and both are fixed. This page explains what's happening and how to configure it.
9+
10+
## Why DevTools gets kicked
11+
12+
React Native allows **exactly one debugger frontend** per app (on RN versions before dev-middleware learned to multiplex frontends). The rn-dev-agent bridge and the visual React Native DevTools window connect to the *same* `/inspector/debug` slot, so they evict each other — whoever connects last wins.
13+
14+
By default the bridge is **agent-first**: after any disconnect it auto-reconnects in the background (instant first retry, then a 5-second poll). So the moment you open DevTools, the bridge re-grabs the seat and your DevTools window gets kicked. You never had a chance.
15+
16+
## The fix: turn off background auto-reconnect
17+
18+
Two equivalent opt-out surfaces — the environment variable wins if both are set:
19+
20+
**Environment variable** (set where the MCP server starts, e.g. in your shell profile or the Claude Code MCP env):
21+
22+
```bash
23+
RN_CDP_AUTOCONNECT=0 # also accepts 'false'; '1'/'true' force the default back on
24+
```
25+
26+
**Project config file**`.rn-agent/config.json` in your React Native project root:
27+
28+
```json
29+
{ "cdp": { "autoConnect": false } }
30+
```
31+
32+
With either set, the bridge runs in **passive mode**: after a disconnect it stays down instead of re-grabbing the seat. Open React Native DevTools and it keeps the connection — Console, Network, Components, Profiler all work.
33+
34+
## What passive mode does and doesn't change
35+
36+
- **Disabled:** all *background* reconnection — the close-triggered reconnect loop and the 5-second background poll. The bridge never takes the seat behind your back.
37+
- **Unchanged:** on-demand connection. When the agent actually runs a CDP tool (`cdp_status`, `cdp_component_tree`, …), the bridge connects for that work — which **does** evict your DevTools window at that moment. That's deliberate: a tool call is a visible, foreground action. Once you reopen DevTools afterwards, the bridge yields again.
38+
- **Unchanged:** `device_*` tools (taps, screenshots, fills). They don't touch the debugger connection at all — use them freely while DevTools is open.
39+
40+
<Aside type="tip" title="Rule of thumb">
41+
Passive mode means: *the bridge holds the debugger seat only while the agent is actively working.* If you want uninterrupted DevTools time, just don't run `cdp_*` tools meanwhile.
42+
</Aside>
43+
44+
You can always see the resolved mode in `cdp_status` → top-level `autoConnect` field (`{ enabled, source: 'env' | 'config' | 'default' }`), and `/rn-dev-agent:doctor` reports it as the **CDP auto-reconnect** row (YELLOW when off — informational, not an error).
45+
46+
**Known limitation:** a DevTools-sharing proxy started with `cdp_open_devtools` is not auto-resumed after a disconnect in passive mode — re-run `cdp_open_devtools` if you use that flow.
47+
48+
## The `__RN_NET__` console spam is gone
49+
50+
Unrelated knob, same release: on React Native < 0.83 the bridge falls back to in-app `fetch`/XHR wrappers for network capture, and these used to transport every request/response as a `console.log('__RN_NET__:…')` line — invisible to the bridge (it filters them) but spamming Metro logs and your DevTools console.
51+
52+
That transport is replaced: entries now go to an in-app ring buffer (`globalThis.__RN_AGENT_NET_BUF__`, capped at 100) that the network tools drain on demand. **No configuration needed** — update the plugin and the console noise disappears while `cdp_network_log` keeps working.
53+
54+
## Quick reference
55+
56+
| I want… | Do this |
57+
|---|---|
58+
| DevTools to stay connected while the agent is idle | `RN_CDP_AUTOCONNECT=0` or `.rn-agent/config.json``{ "cdp": { "autoConnect": false } }` |
59+
| The agent-first default back | Remove the override, or `RN_CDP_AUTOCONNECT=1` |
60+
| To check which mode is active | `cdp_status``autoConnect`, or `/rn-dev-agent:doctor` |
61+
| No `__RN_NET__` lines in my console | Nothing — fixed automatically as of this release |

docs-site/src/content/docs/guides/maestro-interop.mdx

Lines changed: 1 addition & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,4 @@ A natural question: since maestro drives the device fine via WebDriverAgent, can
3232

3333
## Using rn-dev-agent with React Native DevTools
3434

35-
React Native (Hermes) allows **exactly one debugger frontend** per app at a time. By default, rn-dev-agent is agent-first: its CDP bridge auto-reconnects in the background after each disconnect, which means opening the visual React Native DevTools window will kick the bridge out — and the bridge will immediately reclaim the seat.
36-
37-
**To let React Native DevTools hold the debugger seat**, disable background auto-reconnect with one of two opt-out surfaces:
38-
39-
- **Environment variable** (takes precedence over everything):
40-
```bash
41-
RN_CDP_AUTOCONNECT=0 # also accepts 'false'; '1'/'true' force it back on
42-
```
43-
- **Project config file** (`.rn-agent/config.json` in your project root, env wins):
44-
```json
45-
{ "cdp": { "autoConnect": false } }
46-
```
47-
48-
In passive mode the bridge **yields the seat** and reconnects only when a CDP tool actually runs (e.g. `cdp_status`, `cdp_component_tree`). Once you reopen React Native DevTools after a tool call, the bridge yields again automatically.
49-
50-
**Known limitation:** in passive mode, a previously-opened DevTools-sharing proxy (`cdp_open_devtools`) is not auto-resumed after a disconnect — re-run `cdp_open_devtools` if you use it.
51-
52-
**Important caveat:** *any* CDP tool call — including `cdp_status` — reclaims the seat while it runs. Passive mode stops only *background* re-grabs (the close-triggered reconnect loop and the background poll). If you need uninterrupted DevTools access, avoid running CDP tools while the window is open.
53-
54-
The resolved auto-connect mode is always visible in `cdp_status` → top-level `autoConnect` field: `{ enabled: true|false, source: 'default'|'env'|'config' }`. The `/rn-dev-agent:doctor` command also reports it as the **CDP auto-reconnect** row (YELLOW when OFF — informational, not an error).
55-
56-
**Hook-mode network capture note:** on React Native < 0.83 (or when `RN_FORCE_NETWORK_HOOK=1` is set), network entries are captured by in-app `fetch`/XHR wrappers. As of this release that capture **no longer writes `__RN_NET__:…` lines to the console** — entries go directly to an in-app ring buffer (`globalThis.__RN_AGENT_NET_BUF__`, capped at 100) that the network tools drain on demand. Metro logs and your React Native DevTools console will no longer contain hook-mode network noise. No user action is required; the change is transparent.
35+
The same coexistence question exists for the **visual React Native DevTools window**, which competes with the bridge for the single debugger seat. That has its own opt-out (`RN_CDP_AUTOCONNECT=0` / `.rn-agent/config.json`) and is covered in a dedicated guide: [Using rn-dev-agent with React Native DevTools](/rn-dev-agent/guides/devtools-coexistence/).

docs-site/src/content/docs/tools/cdp/cdp_network_body.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: "cdp_network_body"
33
description: "Get the actual response body for a network request by its requestId"
44
---
55

6-
Get the actual response body for a network request by its requestId. Use cdp_network_log first to find request IDs. Only works in CDP network mode (RN 0.83+). Bodies are fetched on-demand, not cached. Pass `device` to look up requestId in a specific device buffer; defaults to the active device.
6+
Get the actual response body for a network request by its requestId. Use cdp_network_log first to find request IDs. In CDP mode (RN 0.83+) bodies are fetched on-demand; on RN &lt; 0.83 hook mode a small recent-response cache is used. Pass `device` to look up requestId in a specific device buffer; defaults to the active device.
77

88
## Parameters
99

docs-site/src/content/docs/tools/cdp/cdp_status.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Get full environment status. Auto-connects if not connected. Returns Metro statu
1313
|------|------|----------|---------|-------------|-------------|
1414
| `metroPort` | `number` | No | | | Override Metro port (default: auto-detect 8081/8082/19000/19006) |
1515
| `platform` | `string` | No | | | Filter target by platform (e.g. "ios", "android") to avoid connecting to the wrong device in multi-simulator setups |
16+
| `resetArbiter` | `boolean` | No | | | Clear a wedged in-memory device arbiter (a leaked plane lease refusing all flows). Escape hatch — cdp_status is unarbitrated so it always runs. |
1617

1718
## Usage
1819

docs-site/src/content/docs/tools/cdp/cdp_wait_for_network.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: "cdp_wait_for_network"
33
description: "Block until a network request matching url_pattern (URL substring) and optional method completes (response received), or timeout_ms elapses"
44
---
55

6-
Block until a network request matching url_pattern (URL substring) and optional method completes (response received), or timeout_ms elapses. Two-phase: scans the existing buffer first (retroactive match), then polls every poll_interval_ms until deadline. Returns \{matched:true, mutation, network_log_since\} on success or \{matched:false, timeout_ms, candidates_seen\} (capped at 10) on timeout — never errors on timeout; agents should check `data.matched`. Use after triggering an action that fires a request to deterministically confirm it landed without buffer-churn races. Pin `since` to a timestamp captured BEFORE the trigger (Date.now() ISO) to also catch mutations that land in the MCP transport window.
6+
Block until a network request matching url_pattern (URL substring) and optional method completes (response received), or timeout_ms elapses. Two-phase: scans the existing buffer first (retroactive match), then polls every poll_interval_ms until deadline. Returns \{matched:true, mutation, network_log_since\} on success or \{matched:false, timeout_ms, candidates_seen\} (capped at 10) on timeout — never errors on timeout; agents should check `data.matched`. Use after triggering an action that fires a request to deterministically confirm it landed without buffer-churn races. Pin `since` to a timestamp captured BEFORE the trigger (Date.now() ISO) to also catch mutations that land in the MCP transport window. On RN &lt; 0.83 (hook network mode) new-entry detection granularity is ~500ms — sub-500ms poll_interval_ms buys nothing there.
77

88
## Parameters
99

docs-site/src/content/docs/tools/device/device_fill.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ Type text into an input field by its @ref from device_snapshot. Always re-taps t
1414
| `ref` | `string` | Yes | | | Input field ref from device_snapshot (e.g. "e5" or "@e5") |
1515
| `text` | `string` | Yes | | | Text to type into the field |
1616
| `waitForKeyboardMs` | `number` | No | | min: 0, max: 5000, integer | Wait between pre-tap and fill probe in ms (default 150). Bump to 500-1000ms when filling Pressable-wrapped TextInputs on slow keyboard animations to give RN native focus dispatch time to land. |
17+
| `testID` | `string` | No | | | Explicit testID for the JS-first fill path; resolved from the ref\\'s cached snapshot identifier when omitted. Pass this when the ref is not a snapshot token. |
1718

1819
## Usage
1920

docs-site/src/content/docs/tools/testing/maestro_run.mdx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ Execute a Maestro flow via maestro-runner. Pass flowPath for an existing .yaml f
1515
| `inlineYaml` | `string` | No | | | Inline YAML flow content (written to /tmp and executed) |
1616
| `platform` | `enum: ios | android` | No | | | Target platform (auto-detected from session) |
1717
| `appId` | `string` | No | | | App bundle ID (auto-detected from app.json) |
18+
| `appFile` | `string` | No | | | iOS only — path to a built .app/.ipa for maestro-runner to reinstall on clearState. Auto-resolved from the flow appId when omitted (GH#201). |
1819
| `timeoutMs` | `number` | No | `120000` | min: 5000, max: 300000, integer | Execution timeout in ms |
1920

2021
## Usage

docs-site/src/content/docs/troubleshooting.mdx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ Open the app on the simulator and ensure Hermes is enabled. Check your `app.json
1919
Close React Native DevTools, Flipper, or Chrome DevTools — only one debugger can connect at a time. The 1006 close code means session conflict.
2020
</Aside>
2121

22+
<Aside type="tip" title='DevTools shows "Disconnected due to opening a second DevTools window"'>
23+
The bridge auto-reconnects by default and evicts the visual React Native DevTools from the single debugger seat. Set `RN_CDP_AUTOCONNECT=0` (or `.rn-agent/config.json``{ "cdp": { "autoConnect": false } }`) to let DevTools hold the seat — the bridge then connects only when a CDP tool runs. Full guide: [React Native DevTools coexistence](/rn-dev-agent/guides/devtools-coexistence/).
24+
</Aside>
25+
2226
<Aside type="tip" title="CDP connection lost after reload">
2327
This is normal. `cdp_reload` automatically reconnects within 15 seconds. If it fails, call `cdp_status` to re-establish the connection.
2428
</Aside>

0 commit comments

Comments
 (0)