rn-devtools-hub

Benchmark

This document contains two different measurements. The live-read benchmark was executed against a running app. The bug-fix pilot is a reproducible runner and manifest, but its comparative agent runs have not been executed yet, so it does not support a claim about bug-fix success. Prompt-token figures below are client-reported deltas: they measure what those client versions reported, not the full serialized size or guaranteed context occupancy of tools/list.

Two questions get asked about a hub that hands an agent 58 tools. What does that cost the agent in context, and does the agent actually come back with the right answer about the running app. Both are measurable, so neither is argued here.

Everything below was measured against a real Expo app on a booted iOS simulator, with a device connected to the hub, across the three CLIs the hub targets. The numbers come from each client's own usage reporting, not from an estimate.

What the hub costs an agent in context

Prompt tokens added by attaching the hub (58 tools) Prompt tokens added by attaching the hub (58 tools) median of 3 runs per arm, identical trivial prompt, same session shape Claude Code 24406 without, 25206 with +800 (13.8/tool) Codex CLI 23773 without, 23923 with +150 (2.6/tool) Cursor CLI 17221 without, 17428 with +207 (3.6/tool)

Attaching the hub added between 150 and 800 tokens to the prompt usage reported by these client versions. On a 1M context window that is under a tenth of a percent if the reported delta represents context occupancy. The tool list also sits at the very front of the request, where it is the most cacheable part of the prompt, and tools/list is byte-stable across calls, so the cache prefix holds.

The cost scales with the number of tools, and it is close to linear.

Claude Code: injected tokens against tool count Claude Code: injected tokens against tool count controlled MCP server serving a fixed slice of the hub's real tool definitions 0 225 450 675 900 +0 0 +133 10 +432 33 +836 65 tools exposed tokens

13.3, 13.1 and 12.9 tokens per tool at 10, 33 and 65 tools. The remaining question is what those tokens are: the names, or the schemas.

Same tool count, different schema size Same tool count, different schema size the payload grows 4.2x and the injected cost does not move 40 KB of schema +836 170 KB of schema +836 40 KB, short names +650

Inflating every description until the payload is 4.2 times larger changes the client-reported injected cost by zero tokens. Shortening the tool names does move it. This is consistent with that client loading schemas on demand and injecting names, but usage reporting alone cannot prove the internal mechanism: the client may account for schemas outside the reported prompt-token field.

In this client version, trimming descriptions did not change the reported prompt-token field. The experiment cannot establish that schemas are free: a client may load, cache or account for them outside that field. Tool count and serialized schema bytes must therefore be reported separately.

Whether an agent reads the app correctly through the hub

Nine questions about the running app, each answerable by one read-only hub tool: the slowest endpoint by p95, how many endpoints are tracked, total calls, how many endpoints have errors, the crash count, the connected device name, the declared expo and react-native versions, the registered debug actions.

Correct answers about the live app, by client Correct answers about the live app, by client 95% Wilson interval, one tool call per question, ground truth captured around every round 0 25 50 75 100 100% Claude Code 17/17 100% Codex CLI 17/17 100% Cursor CLI 16/16

Every client answered every retained, completed round correctly.

The interesting part is what it took to measure this honestly. A first run scored 50 to 65 percent, and the failures were identical across all three clients, which is not how three different models fail. They were not failures: the app kept running, and the reference values captured at the start had gone stale. The slowest endpoint had moved, the crash history had rolled over on an app restart, the endpoint count had changed. The agents were reporting the truth at the moment they were asked, and the benchmark was grading them against the truth from forty minutes earlier.

So ground truth is now captured directly from the hub immediately before and immediately after each round. When it moves during the round, that round is discarded for all three clients at once, because the fact changed rather than the agent being wrong. One round out of 18 was discarded that way.

That volatility is visible in the retained data and is the point: between the two repetitions the slowest endpoint went from GET /v1/express/config to POST /v1/auth/login and the tracked endpoint count went from 11 to 14. Every client tracked the change both times. A hub that returned a cached or stale view would have scored well against a fixed reference and badly here.

Two devices at once

The questions above were asked of a single connected device. Adding a second one changes the problem: a hub that holds two apps has to be asked which app, and an agent has to work that out.

So a physical Samsung Galaxy A16 5G (SM-A165M), Android 16 was added next to the iPhone 16 Pro Max, iOS 18.4, both running the same app, both connected to the same hub. The Android side is a development build (the app depends on expo-dev-client and native modules Expo Go does not carry), installed over USB with Metro and the hub reached through reversed ports.

With two devices attached, every device-scoped tool stops answering and says so, naming both candidates:

2 devices are connected, so the target is ambiguous: pass deviceId.
Connected: s-SimulatoriOS-...-ios (@example/mobile on iPhone 16 Pro Max),
           s-SM-A165M-...-andr (@example/mobile on Galaxy A16)

That refusal is the feature under test. Ten questions were asked, each naming its target device, with no hint in the prompt that disambiguation would be needed. The agents had to hit the refusal, resolve the device themselves and retry scoped.

Correct answers with two devices connected, by client Correct answers with two devices connected, by client an Android phone and an iOS simulator on one hub; every device-scoped question names its target 0 25 50 75 100 100% Claude Code 20/20 100% Codex CLI 20/20 95% Cursor CLI 19/20

The two devices held different data, which is what makes a wrong answer visible: the hub had statistics for 13 endpoints on the simulator and 1 on the phone. An agent that scoped to the wrong device answers 13 where 1 is correct, and none did.

The single miss is real rather than a scoring artifact: on one round Cursor answered that one device was connected when two were. It is the only genuine wrong answer across both accuracy experiments, and it is left in the count.

Nothing drifted during these 20 rounds, so none were discarded.

Method

The exact model identifiers and the raw transcripts were not retained with the published document. The CLI versions and aggregate results are therefore auditable only as reported here, not independently reproducible. Future runs must store the prompt, model identifier, raw client output, ground truth before and after the round, scoring output and any discarded attempt together.

Limits

These are single-tool lookups, not multi-step debugging. They measure whether the hub delivers correct live facts to an agent and whether the agent reads them, which is the hub's contract. They do not measure whether an agent can diagnose a bug.

With 17 retained rounds per client, a 100% score carries a 95% interval reaching down to about 82%. The result rules out a broken path, not a rare failure mode. One Cursor run out of 18 exceeded a 260 second deadline and was counted as missing rather than wrong. Cursor's conditional answer accuracy was therefore 16/16, while its end-to-end completion rate on retained rounds was 16/17 (94.1%). Both numbers are required: excluding the timeout from the accuracy denominator must not make the operational result look like 100%.

The Wilson intervals treat answers as Bernoulli observations, although answers are clustered by app, machine, round and underlying hub state. They are descriptive intervals, not evidence that 17 independent app or environment samples were tested.

All of it is one app on one machine. Another app with different traffic would be a different sample, and the injection numbers belong to the client versions listed above, which change often.

The scoring code is itself a source of error, and was twice: an early version graded three questions against a pattern built from a non-numeric value, which turned three correct answers into failures across every client at once. It now refuses to build a matcher it has no rule for instead of quietly producing one that can never match. Both accuracy sections were scored again from the same recorded answers after that fix; no agent was re-run to improve a number.