Skip to content

CLI: Prefer agent-matched Storybook instances - #35235

Merged
kasperpeulen merged 7 commits into
nextfrom
kasper/ai-agent-instance-selection
Jun 19, 2026
Merged

kasperpeulen merged 7 commits into
nextfrom
kasper/ai-agent-instance-selection

Conversation

@kasperpeulen

@kasperpeulen kasperpeulen commented Jun 19, 2026 •

Copy link
Copy Markdown
Member

Closes #35234

What I did

Adds optional agent provenance to Storybook runtime instance records and uses it when storybook ai resolves a running Storybook instance without an explicit --port.

  • Records Claude preview-launched Storybooks as agent: 'claude-preview' when CLAUDE_AGENT_SDK_VERSION is set and AI_AGENT is not set.
  • Records other detected agent launches with detectAgent()?.name.
  • Prefers claude-preview records for Claude CLI calls, then generic claude records; other agents prefer their matching records.
  • Falls back to the existing latest-started behavior when no agent bucket matches.
  • Limits multi-instance warnings to the selected competing bucket instead of every same-cwd instance.

Checklist for Contributors

Testing

The changes in this PR are covered in the following automated tests:

  • stories
  • unit tests
  • integration tests
  • end-to-end tests

Manual testing

Caution

This section is mandatory for all contributions. If you believe no manual test is necessary, please state so explicitly. Thanks!

No browser story QA is necessary for this PR; the behavior is CLI runtime instance selection. To manually verify the intended surface, run:

  1. yarn vitest run code/core/src/cli/ai/mcp/resolve-instance.test.ts code/core/src/cli/ai/mcp/run-tool.test.ts code/core/src/cli/ai/mcp/registry.test.ts code/core/src/core-server/utils/runtime-instance-registry.test.ts
  2. Confirm the test named only warns about instances in the selected agent bucket passes. That test simulates a Claude CLI call with two claude-preview records and a newer codex record at the same cwd; the expected behavior is that the command routes to the latest Claude preview record and the warning excludes the Codex record.

Documentation

  • Add or update documentation reflecting your changes
  • If you are deprecating/removing a feature, make sure to update
    MIGRATION.MD

Checklist for Maintainers

  • When this PR is ready for testing, make sure to add ci:normal, ci:merged or ci:daily GH label to it to run a specific set of sandboxes. The particular set of sandboxes can be found in code/lib/cli-storybook/src/sandbox-templates.ts

  • Declare whether manual QA will be needed for this PR during the next release, through qa:needed or qa:skip

  • Make sure this PR contains one of the labels below:

    Available labels
    • bug: Internal changes that fixes incorrect behavior.
    • maintenance: User-facing maintenance tasks.
    • dependencies: Upgrading (sometimes downgrading) dependencies.
    • build: Internal-facing build tooling & test updates. Will not show up in release changelog.
    • cleanup: Minor cleanup style change. Will not show up in release changelog.
    • documentation: Documentation only changes. Will not show up in release changelog.
    • feature request: Introducing a new feature.
    • BREAKING CHANGE: Changes that break compatibility in some way with current major version.
    • other: Changes that don't fit in the above categories.

🦋 Canary release

This pull request has been released as version 0.0.0-pr-35235-sha-7c9fa4b5. Try it out in a new sandbox by running npx storybook@0.0.0-pr-35235-sha-7c9fa4b5 sandbox or in an existing project with npx storybook@0.0.0-pr-35235-sha-7c9fa4b5 upgrade.

More information
Published version 0.0.0-pr-35235-sha-7c9fa4b5
Triggered by @huang-julien
Repository storybookjs/storybook
Branch kasper/ai-agent-instance-selection
Commit 7c9fa4b5
Datetime Fri Jun 19 14:37:29 UTC 2026 (1781879849)
Workflow run 27832032547

To request a new release of this pull request, mention the @storybookjs/core team.

core team members can create a new canary release here or locally with gh workflow run --repo storybookjs/storybook publish.yml --field pr=35235

Summary by CodeRabbit

  • New Features

    • Added agent-aware instance selection so Claude CLI runs prefer matching Claude preview instances over generic Claude instances when multiple Storybook instances are available.
    • Runtime instance records now optionally store agent provenance to improve disambiguation.
  • Bug Fixes

    • Improved warning output consistency when multiple instances match (including updated wording and preview-specific targeting).
  • Tests

    • Expanded coverage for agent-constrained selection, provenance precedence, and tie-breaking.
    • Improved test isolation by clearing environment overrides between runs.

@kasperpeulen kasperpeulen added feature request ci:normal Run our default set of CI jobs (choose this for most PRs). qa:needed Pull Requests that will need manual QA prior to release. labels Jun 19, 2026
@kasperpeulen
kasperpeulen marked this pull request as ready for review June 19, 2026 14:08
@coderabbitai

coderabbitai Bot commented Jun 19, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 07e2d102-9f12-4500-83f0-c2db8b7d69ea

📥 Commits

Reviewing files that changed from the base of the PR and between 2a96d35 and 7c9fa4b.

📒 Files selected for processing (1)
  • code/core/src/cli/ai/mcp/run-tool.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • code/core/src/cli/ai/mcp/run-tool.test.ts

📝 Walkthrough

Walkthrough

Adds agent provenance tracking to Storybook's MCP runtime instance records. A new agent-provenance.ts constants file defines Claude-related marker strings. The RuntimeInstanceRecord and StorybookInstanceRecordSchema gain an optional agent field. A detectRuntimeInstanceAgent() function derives agent identity from environment variables. resolveInstance gains a currentAgent parameter and delegates to a new selectCompetingBucket helper that narrows competing cwd-matched records to the current agent's bucket, with special claude→claude-preview preference logic. run-tool.ts passes detectAgent()?.name into resolveInstance.

Changes

Agent-aware MCP instance resolution

Layer / File(s) Summary
Agent provenance constants
code/core/src/shared/constants/agent-provenance.ts
Exports CLAUDE_AGENT_NAME ('claude') and CLAUDE_PREVIEW_AGENT_NAME ('claude-preview') as provenance marker strings.
Agent field in instance record types and writer
code/core/src/cli/ai/mcp/types.ts, code/core/src/core-server/utils/runtime-instance-registry.ts, code/core/src/core-server/utils/runtime-instance-registry.test.ts, code/core/src/cli/ai/mcp/registry.test.ts
Extends StorybookInstanceRecordSchema and RuntimeInstanceRecord with agent?: string; introduces detectRuntimeInstanceAgent() to select agent identity from CLAUDE_AGENT_SDK_VERSION, AI_AGENT, or detectAgent(); updates createRuntimeInstanceRecord and writeStorybookRuntimeInstanceRecord to accept and persist the field; tests cover field propagation and env-variable precedence.
selectCompetingBucket and resolveInstance agent awareness
code/core/src/cli/ai/mcp/resolve-instance.ts, code/core/src/cli/ai/mcp/resolve-instance.test.ts
Adds currentAgent?: string to resolveInstance; introduces selectCompetingBucket helper that narrows cwd-matching records to the agent's bucket (claude maps to claude-preview with generic claude as fallback, non-Claude agents use direct match, no agent uses all records); tests cover all bucket-selection and fallback scenarios.
run-tool wiring and warning text
code/core/src/cli/ai/mcp/run-tool.ts, code/core/src/cli/ai/mcp/run-tool.test.ts
Passes detectAgent()?.name into resolveInstance; renames warning section to "Matching instances at …"; adds env-stub cleanup and a new test verifying agent-bucket-limited MCP routing.

Sequence Diagram(s)

sequenceDiagram
  participant AI_Agent as AI Agent (e.g. Claude CLI)
  participant runAiTool
  participant resolveInstance
  participant selectCompetingBucket
  participant StorybookInstance

  AI_Agent->>runAiTool: invoke MCP tool
  runAiTool->>runAiTool: detectAgent() → {name: 'claude'}
  runAiTool->>resolveInstance: records, cwd, port?, currentAgent='claude'
  resolveInstance->>selectCompetingBucket: matches, targetPort, 'claude'
  selectCompetingBucket->>selectCompetingBucket: filter claude-preview bucket
  alt claude-preview records found
    selectCompetingBucket-->>resolveInstance: claude-preview bucket sorted
  else no claude-preview, fallback
    selectCompetingBucket-->>resolveInstance: claude bucket sorted
  end
  resolveInstance-->>runAiTool: {instance, matches, interceptReason?}
  runAiTool->>StorybookInstance: call MCP on resolved instance
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
code/core/src/cli/ai/mcp/run-tool.test.ts (1)

503-503: ⚡ Quick win

Move this scenario-specific mock behavior into a scoped beforeEach.

vi.mocked(readRegistry).mockResolvedValue(...) is configured inline inside the test. To keep this file aligned with the Vitest mocking rules, set this behavior in a nested describe beforeEach for this scenario.

As per coding guidelines, "Implement mock behaviors in beforeEach blocks in Vitest tests" and "Avoid inline mock implementations within test cases in Vitest tests".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/core/src/cli/ai/mcp/run-tool.test.ts` at line 503, The
vi.mocked(readRegistry).mockResolvedValue() call is currently configured inline
within the test case. Move this mock setup out of the test body and into a
scoped beforeEach block. Create or use an existing nested describe block for
this test scenario, then establish a beforeEach block within that describe where
you set up the vi.mocked(readRegistry).mockResolvedValue() with the test data
(olderPreview, selectedPreview, newerCodex), then remove the inline mock setup
from the test case itself.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@code/core/src/cli/ai/mcp/run-tool.test.ts`:
- Line 503: The vi.mocked(readRegistry).mockResolvedValue() call is currently
configured inline within the test case. Move this mock setup out of the test
body and into a scoped beforeEach block. Create or use an existing nested
describe block for this test scenario, then establish a beforeEach block within
that describe where you set up the vi.mocked(readRegistry).mockResolvedValue()
with the test data (olderPreview, selectedPreview, newerCodex), then remove the
inline mock setup from the test case itself.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: e2aa317a-2c59-4012-bb16-84e33216b673

📥 Commits

Reviewing files that changed from the base of the PR and between c89349e and 2a96d35.

📒 Files selected for processing (9)
  • code/core/src/cli/ai/mcp/registry.test.ts
  • code/core/src/cli/ai/mcp/resolve-instance.test.ts
  • code/core/src/cli/ai/mcp/resolve-instance.ts
  • code/core/src/cli/ai/mcp/run-tool.test.ts
  • code/core/src/cli/ai/mcp/run-tool.ts
  • code/core/src/cli/ai/mcp/types.ts
  • code/core/src/core-server/utils/runtime-instance-registry.test.ts
  • code/core/src/core-server/utils/runtime-instance-registry.ts
  • code/core/src/shared/constants/agent-provenance.ts

@kasperpeulen

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 19, 2026 •

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

This was referenced Jul 13, 2026
@JReinhold JReinhold added qa:success Pull Requests that were successfully QA'ed by the release team. and removed qa:needed Pull Requests that will need manual QA prior to release. labels Aug 28, 2026
@github-actions

Copy link
Copy Markdown
Contributor
Fails
🚫

node failed.

Log

Details
Error:  Error: Could not find the Dangerfile at scripts/dangerfile.ts - if it is local, perhaps you have a typo? If it's using a remote file, it doesn't have a repo reference.
    at /usr/src/danger/dist/platforms/GitHub.js:161:27
    at step (/usr/src/danger/dist/platforms/GitHub.js:44:23)
    at Object.next (/usr/src/danger/dist/platforms/GitHub.js:25:53)
    at /usr/src/danger/dist/platforms/GitHub.js:19:71
    at new Promise (<anonymous>)
    at __awaiter (/usr/src/danger/dist/platforms/GitHub.js:15:12)
    at Object.executeRuntimeEnvironment (/usr/src/danger/dist/platforms/GitHub.js:144:88)
    at /usr/src/danger/dist/commands/danger-runner.js:101:47
    at step (/usr/src/danger/dist/commands/danger-runner.js:34:23)
    at Object.next (/usr/src/danger/dist/commands/danger-runner.js:15:53)
danger-results://tmp/danger-results-a697376f.json

Generated by 🚫 dangerJS against 7c9fa4b

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

Labels

ci:normal Run our default set of CI jobs (choose this for most PRs). feature request qa:success Pull Requests that were successfully QA'ed by the release team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Improve storybook ai instance selection with agent-aware runtime records

3 participants