Skip to content

feat: sb-rn CLI to look up component docs and drive Storybook on the device - #933

Draft
dannyhw wants to merge 3 commits into
nextfrom
dannyhw/feat/sb-rn-cli
Draft

dannyhw wants to merge 3 commits into
nextfrom
dannyhw/feat/sb-rn-cli

Conversation

@dannyhw

@dannyhw dannyhw commented Oct 17, 2026

Copy link
Copy Markdown
Member

Issue: N/A. Follows upstream Storybook 11's agent tooling (storybook tools / storybook skills), which explicitly excludes React Native.

What I did

Upstream Storybook moved its agent skills from MCP to a CLI (npx storybook tools …). Their evals showed that coding agents that can run shell commands use the tools more reliably that way, and it needs no MCP client config. Upstream's CLI can't attach to us: it needs a storybook dev instance and a web builder. This PR adds an RN equivalent that uses the same vocabulary and is built on our channel server.

New sb-rn CLI (bin in @storybook/react-native)

  • sb-rn docs list | show --id | show-story --storyId runs the @storybook/mcp docs tools in-process against the story files. The output is identical to the MCP docs-* tools, with tool references rewritten to the CLI commands. It needs no device or bundler.
  • sb-rn stories list lists the story ids from the node-side index.
  • sb-rn stories select, args update, args reset, globals update and status drive the device through the channel server. Each waits for the device to confirm and prints the result: the rendered story, or the resulting args or globals.
  • sb-rn skills ui-workflow | component-docs | write-story prints agent instructions that ship with the installed version.
  • Results go to stdout; library logs (CSF warnings, docgen) go to stderr. --json is available, and the exit code is 1 on failure.
  • Finding the channel server, in order: --url/--host/--port, then STORYBOOK_WS_HOST/PORT, then a record the running server writes to node_modules/.cache/storybook-react-native/channel-server.json, then localhost:7007.

Channel server: shared device-control layer (deviceControl.ts)

  • The HTTP endpoints and the MCP tools both use it, so the two behave the same.
  • It tracks each connected device's story, args, globals and last render error. It decodes the telejson markers the device sends (_duplicate_, _undefined_, _date_); before this, globals showed up as _duplicate_[…] strings.
  • Only clients that report preview events count as devices, so a devtools socket doesn't. connectedClients reports all clients.
  • New endpoints: GET /state, POST /update-args-sync, /reset-args-sync and /update-globals-sync. Errors return { success: false, code, error }.
  • POST /select-story-sync/:id keeps its 1000ms default and response shape for existing Maestro flows. It now also accepts ?timeout=, fails right away with 422 when the story throws or is missing, and returns 404 with same-component suggestions when the id isn't in the index.
  • Each server now removes its beforeExit listener when it closes. Tests that create many servers previously triggered MaxListenersExceededWarning.

MCP

  • New device tools: get-device-state, update-story-args, reset-story-args and update-globals.
  • select-story now waits for the render instead of firing and forgetting.
  • The manifest provider is shared with the CLI (manifestProvider.ts).

Other

  • buildIndex reads process.cwd() per call instead of at import, so --cwd works.
  • Docs: a new "Agent CLI (sb-rn)" page, and the MCP page lists the device tools.
  • Skills: new thin react-native-storybook-ui-workflow and react-native-storybook-component-docs skills that defer to npx sb-rn skills <id>. Both READMEs and AGENTS.md/CLAUDE.md are updated.
  • Changeset: minor for @storybook/react-native.

Not in this PR (follow-ups):

  • Token auth on the HTTP control endpoints. Upstream puts a token in its instance record. Adding it here would break the existing /send-event curl and Maestro usage, so it needs its own discussion.
  • componentPath and real tags in buildIndex, which would enable find-by-component and !manifest filtering.
  • Screenshots. These stay with agent-device, simctl or adb; the skill says so.

How to test

Unit tests: pnpm -F @storybook/react-native test. There are 22 new tests: device-control endpoints against a fake device, telejson decoding, endpoint resolution order, the record file round trip, client error mapping, and a check that skill text only names real commands. All 87 tests pass, along with check:types, lint and format:check.

On a device (I ran this against expo-example on an iOS 26.4 simulator, with Metro on 8090 and STORYBOOK_WS_PORT=7017):

pnpm build
cd examples/expo-example
pnpm storybook        # then open the app

npx sb-rn docs show --id logindocsexample-button      # works without the app too
npx sb-rn status
npx sb-rn stories select --storyId logindocsexample-button--primary
npx sb-rn args update --args '{"title":"Saved by sb-rn","variant":"secondary"}'
npx sb-rn args reset --argNames variant
npx sb-rn globals update --globals '{"backgrounds":{"value":"dark"}}'
npx sb-rn stories select --storyId logindocsexample-button--primry   # typo: 404 with suggestions

Transcript from the device run:

$ npx sb-rn stories select --storyId controlexamples-controlexample--example
Story `controlexamples-controlexample--example` is rendered on the device.

$ npx sb-rn status
Channel server: http://localhost:7017 (found running in this project)
Connected devices: 1

## Device 1
- Story: controlexamples-controlexample--example
- Args: `{"name":"Storyteller","age":70,…,"birthday":"2017-01-20T00:00:00.000Z"}`
- Globals: `{"measureEnabled":false,"backgrounds":{"value":"plain"},"outline":false,"viewport":{"isRotated":false}}`

$ npx sb-rn args update --args '{"name":"Alice","age":25}'
Args of `controlexamples-controlexample--example`: `{"name":"Alice","age":25,…}`

$ npx sb-rn stories select --storyId controlexamples-controlexample--exmple
Story "controlexamples-controlexample--exmple" not found. Stories of the same component: controlexamples-controlexample--example
(exit 1)

Screenshots confirmed the device rendered the selected story, the updated title and variant, the args set over MCP update-story-args, and the background change from globals update. The MCP tools/list returned all 9 tools.

  • Does this need a new example in examples/expo-example? No. The existing stories cover it.
  • Does this need an update to the documentation? Yes, and it's included: docs/docs/intro/configuration/agent-cli.md and mcp-configuration.md.

…device

Add an `sb-rn` bin to @storybook/react-native, modelled on upstream
Storybook's `storybook tools` / `storybook skills`:

- `sb-rn docs list|show|show-story` runs the @storybook/mcp docs tools
  in-process against the story files, so it answers exactly like the MCP
  server and needs no device or bundler.
- `sb-rn stories list|select`, `args update|reset`, `globals update` and
  `status` drive the connected device through the channel server and wait
  for it to confirm.
- `sb-rn skills ui-workflow|component-docs|write-story` prints agent
  instructions that ship with the package; thin skills in skills/ point
  at them.

The channel server gets a device-control layer shared by its HTTP
endpoints and the MCP tools. It tracks each device's story, args, globals
and last render error, decoding the telejson markers the device sends.
New endpoints: GET /state, POST /update-args-sync, /reset-args-sync and
/update-globals-sync. /select-story-sync keeps its 1000ms default and
response shape, accepts ?timeout=, fails as soon as the story errors, and
suggests ids when the story is not in the index. MCP gains
get-device-state, update-story-args, reset-story-args and update-globals,
and select-story now waits for the render.

The running channel server writes its address to
node_modules/.cache/storybook-react-native/channel-server.json so sb-rn
finds it without guessing ports.
@changeset-bot

changeset-bot Bot commented Oct 17, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 059709e

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@storybook/react-native Minor
@storybook/addon-ondevice-actions Minor
@storybook/addon-ondevice-backgrounds Minor
@storybook/addon-ondevice-controls Minor
@storybook/addon-ondevice-notes Minor
@storybook/react-native-theming Minor
@storybook/react-native-ui-common Minor
@storybook/react-native-ui-lite Minor
@storybook/react-native-ui Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant