Skip to content

Support Claude preview autoPort in storybook dev #35257

Description

@kasperpeulen

Problem

Claude preview owns the browser surface and uses .claude/launch.json autoPort to choose the port for a launcher-managed dev server. Claude passes that selected port to the child process through the PORT environment variable.

storybook dev does not currently read PORT. It only receives an explicit CLI --port value or the existing SBCONFIG_PORT env mapping. The current Claude launch skill guidance also tells agents to pass --port $PORT, but Claude launches runtimeArgs without shell expansion, so Storybook receives the literal string $PORT instead of a number.

The result is a broken Claude preview flow: Claude can report one port while Storybook binds another, and Storybook may also open an extra browser window even though Claude preview already provides the browser surface.

Related tracker: #34826

Delivery shape

This requires two coordinated PRs:

  1. A storybookjs/storybook PR for the core storybook dev behavior and CLI docs.
  2. A storybookjs/mcp PR for the Claude launch skill guidance that writes .claude/launch.json.

The Storybook core PR should land first or be available as a canary before the mcp/plugin skill PR is considered complete, because the new launch guidance depends on Storybook reading PORT and suppressing the extra browser in Claude preview.

Intended behavior

  • When storybook dev is launched by Claude preview, Storybook should not open an additional browser window.
  • This should be scoped to Claude preview, not all detected agents and not generic CI.
  • Claude preview detection should reuse the existing runtime provenance signal: CLAUDE_AGENT_SDK_VERSION is present and AI_AGENT is absent.
  • The existing claude-preview runtime record behavior should keep working.
  • Existing env-backed dev options should keep the same behavior as getEnvConfig: truthy env values override the corresponding Commander option for SBCONFIG_HOSTNAME, SBCONFIG_STATIC_DIR, SBCONFIG_CONFIG_DIR, and CI.
  • storybook dev should resolve and validate the dev options object with Valibot before starting the dev server.
  • Port resolution should use strict valid-port parsing for the selected value.
  • Outside Claude preview, port precedence should be: explicit CLI --port > SBCONFIG_PORT > PORT.
  • In Claude preview, port precedence should be: launcher-provided PORT > explicit CLI --port > SBCONFIG_PORT.
  • A hardcoded numeric project script port should therefore keep winning outside Claude preview, but a valid Claude preview PORT should override it.
  • Literal shell placeholders such as --port '$PORT' are not supported interpolation. If such a value is the selected port, Valibot should reject it.
  • Invalid selected port values should fail before dev server startup using Valibot's validation error.
  • Claude launch config guidance should stop generating --port $PORT and should not need --ci just to avoid a browser window.

Storybook core PR

Implementation notes:

  • Extract the existing Claude preview launcher detection into a reusable helper.
  • Reuse that helper from the runtime instance registry so records still write agent: "claude-preview" for Claude preview-launched Storybooks.
  • In the storybook dev CLI path, make options.open default to false for Claude preview-launched processes.
  • Do not set process.env.CI and do not treat Claude preview as CI.
  • Replace the dev command's existing getEnvConfig mutation with an inline resolved options object that preserves the same truthy env override behavior for existing env-backed options.
  • Add Valibot parsing for the resolved dev options object, including strict port parsing.
  • Implement port precedence as:
    • Claude preview: PORT ?? options.port ?? SBCONFIG_PORT
    • non-Claude preview: options.port ?? SBCONFIG_PORT ?? PORT
  • Update docs/api/cli-options.mdx with a concise note that storybook dev also reads PORT for launcher/platform integrations, and that Claude preview PORT overrides hardcoded script ports.

Acceptance criteria:

  • CLAUDE_AGENT_SDK_VERSION=1 with no AI_AGENT causes storybook dev to skip automatic browser opening by default.
  • The same Claude preview detection still records runtime provenance as agent: "claude-preview".
  • Truthy SBCONFIG_HOSTNAME, SBCONFIG_STATIC_DIR, SBCONFIG_CONFIG_DIR, and CI values keep overriding their corresponding dev command options as they did through getEnvConfig.
  • PORT=6123 storybook dev starts Storybook on port 6123 when no --port or SBCONFIG_PORT is provided.
  • Outside Claude preview, PORT=6123 storybook dev --port 7007 starts Storybook on port 7007.
  • Outside Claude preview, PORT=6123 SBCONFIG_PORT=7008 storybook dev starts Storybook on port 7008.
  • Outside Claude preview, SBCONFIG_PORT=7008 storybook dev --port 7007 starts Storybook on port 7007.
  • In Claude preview, CLAUDE_AGENT_SDK_VERSION=1 PORT=6123 storybook dev --port 7007 starts Storybook on port 6123.
  • In Claude preview without PORT, CLAUDE_AGENT_SDK_VERSION=1 SBCONFIG_PORT=7008 storybook dev --port 7007 starts Storybook on port 7007.
  • In Claude preview without PORT or --port, CLAUDE_AGENT_SDK_VERSION=1 SBCONFIG_PORT=7008 storybook dev starts Storybook on port 7008.
  • PORT=not-a-port storybook dev fails before startup with a Valibot validation error for the selected port value.
  • SBCONFIG_PORT=7007abc storybook dev fails before startup with a Valibot validation error for the selected port value.
  • storybook dev --port '$PORT' is not treated as a supported interpolation mechanism and fails when that value is selected as the port.
  • Non-Claude-preview launches keep the existing browser-open default.
  • Docs mention the PORT fallback behavior near the --port CLI option.

Verification:

  • Add focused unit coverage for the extracted Claude preview detection helper.
  • Add or update runtime registry coverage proving agent: "claude-preview" still uses the helper.
  • Verify the resolved dev option behavior with targeted local checks or focused tests for normal port precedence, Claude-preview port precedence, SBCONFIG_PORT, invalid selected port values, and Claude-preview open: false.
  • Run formatting from code/ with yarn fmt:write after code changes.
  • Run targeted lint/check commands for changed files.

MCP plugin PR

Implementation notes:

  • Update the Claude launch skill in storybookjs/mcp so it preserves the existing behavior of discovering the project's Storybook script, preferred package manager, and invocation directory, but no longer requires --port $PORT / %PORT% or --ci.
  • Do not replace the working script-discovery behavior with a universal storybook dev command.
  • Update any related Claude plugin README, QA guide, tests, or snapshots in storybookjs/mcp that still describe --port $PORT or --ci as required for Claude preview.
  • Keep the skill focused on launching Storybook through Claude preview, not on ad hoc background shell commands.

Acceptance criteria:

  • The Claude launch skill no longer instructs agents to generate --port $PORT / %PORT% or add --ci for Claude preview.
  • The skill still instructs agents to inspect and use the project's existing Storybook script, preferred package manager, and Storybook invocation directory.
  • The launch guidance still requires autoPort: true and relies on Claude providing PORT while Storybook core consumes it.
  • Related tests/snapshots/docs in storybookjs/mcp match the new launch guidance.

Verification:

  • Run formatting and targeted tests/checks for the changed storybookjs/mcp package files.
  • Manually inspect the generated or documented Claude launch guidance to confirm it:
    • uses autoPort: true
    • keeps the existing project-script/package-manager launch shape and cwd behavior
    • does not include --port $PORT, %PORT%, or --ci
    • does not require a universal runtimeArgs shape such as ["storybook", "dev"]

Out of scope

  • Do not remove, merge, or broadly rewrite the Claude plugin skills as part of this work.
  • Do not slim down the stories skill beyond removing or updating wording that directly conflicts with this issue.
  • Keep the MCP plugin PR to the minimal launch guidance changes required by the Storybook core behavior.

End-to-end verification

After both PRs are available, manually smoke-test the intended Claude preview flow where feasible:

  • Use a Claude launch entry with the project's existing Storybook script, autoPort: true, and no --port $PORT / %PORT% / --ci runtime args.
  • Confirm Claude preview and Storybook agree on the selected port, including when the project script hardcodes a numeric Storybook port.
  • Confirm Storybook does not open an additional external browser window.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions