Skip to content

Pass a valid empty MCP configuration to the auto-naming summarizer - #9473

Merged
austinywang merged 2 commits into
mainfrom
issue-9457-workspace-auto-naming-always-fails-cmux
Aug 3, 2026
Merged

austinywang merged 2 commits into
mainfrom
issue-9457-workspace-auto-naming-always-fails-cmux

Conversation

@austinywang

@austinywang austinywang commented Aug 3, 2026 •

Copy link
Copy Markdown
Contributor

Workspace auto-naming failed on every attempt with a Claude Code session. cmux spawned the summarizer with --strict-mcp-config --mcp-config {}, and Claude Code 2.1.220 validates that JSON against a schema requiring an mcpServers record. The subprocess exited on argument validation in under a second (mcpServers: Invalid input: expected record, received undefined), so no title was ever produced and every attempt recorded autoNamingLastStatus.category: "failed".

The fix emits {"mcpServers":{}} instead, which is the same semantics (no MCP servers) in a form the current schema accepts. The argv is now built by AutoNamingEnvironmentPolicy.claudeSummarizerArguments(from:) so it is covered by a test rather than living inline in the dispatch path.

Fixes #9457

Not addressed here: the reporter's secondary observations (the summarizer still loads the user's global CLAUDE.md, and the failure is invisible from outside because the subprocess stderr and exit code are discarded). Both are real but separate from the argument bug; leaving them out keeps this change minimal.

Testing

Regression test: cmuxTests/AutoNamingClaudeArgumentsTests.swift asserts the --mcp-config value is not {} and parses to an object whose only key is an mcpServers record, plus the tool/session-isolation flags and the ANTHROPIC_SMALL_FAST_MODEL override. Two commits, ad2dc5c adds the test against the current {} argument and 5d7d7ea applies the fix.

CI could not run that test on either commit. ci.yml is dispatch-only right now, and both dispatched runs (30855956954 on the test-only commit, 30855966921 on the fix) failed before the macOS tests job at a preexisting gate on main: workflow-guard-tests reports scripts/ghosttykit-checksums.txt is missing an entry for ghostty f0f8273b700e754b3f0052cea033789aab902fd1, which is the SHA main pins. linux-preflight gates tests on that guard, so the same failure is hitting other branches. That pin is a separate fix.

Verified at runtime instead, on macOS 26 with Claude Code 2.1.220 installed locally:

  1. Reproduced the bug against the real binary. claude -p --model haiku --tools "" --disable-slash-commands --no-session-persistence --strict-mcp-config --mcp-config '{}' prints Error: Invalid MCP configuration: mcpServers: Invalid input: expected record, received undefined. The same command with '{"mcpServers":{}}' returns a title.
  2. Built a tagged dev app with ./scripts/reload.sh --tag sym9457 and confirmed the bundled CLI carries the new literal.
  3. Drove the real path end to end in that app: enabled workspaceAutoNamingEnabled with autoNamingAgent: claude, ran an interactive Claude Code session in a workspace over /tmp/cmux-debug-sym9457.sock, and completed a turn so the Stop hook fired. The workspace was renamed to custom_title: "OAuth Refresh Tokens" with has_custom_title: true, and autoNamingLastStatus did not exist afterward, which is the success signature the reporter described. Before this change the same flow left custom_title: null and recorded category: "failed".

The tagged app was quit and its temporary defaults were removed after verification.

🤖 Generated with Claude Code

austinywang and others added 2 commits August 3, 2026 14:10
Extracts the claude summarizer argv into
AutoNamingEnvironmentPolicy.claudeSummarizerArguments and asserts the
--mcp-config value is a valid MCP configuration object. It currently
emits a bare {}, which Claude Code rejects.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude Code 2.1.220 validates --mcp-config against a schema requiring an
mcpServers record, so the bare {} cmux passed made the summarizer exit
on argument validation and every workspace auto-naming attempt recorded
category: failed. Emit {"mcpServers":{}} instead.

Fixes #9457

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Claude auto-naming now builds arguments through a centralized environment policy. The invocation uses a valid empty MCP configuration and disables tools, slash commands, and session persistence. New tests verify these arguments and model selection.

Changes

Claude auto-naming

Layer / File(s) Summary
Centralized Claude argument policy
CLI/CMUXCLI+AutoNaming.swift, CLI/CMUXCLI+AutoNamingDispatch.swift
Claude summarizer arguments now use a valid empty MCP configuration and centralized environment policy. Tools, slash commands, and session persistence are disabled.
Argument contract tests and target wiring
cmuxTests/AutoNamingClaudeArgumentsTests.swift, cmux.xcodeproj/project.pbxproj
Tests cover MCP configuration validity, required flags, and default or environment-overridden model selection. The test file is included in the Xcode test target.

Estimated code review effort: 3 (Moderate) | ~20 minutes


Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error)

Check name Status Explanation Resolution
Cmux Swift Package Boundaries ❌ Error Pure Claude provider-contract logic (claudeSummarizerArguments and MCP JSON) remains in CLI/CMUXCLI+AutoNaming.swift; new tests exercise it without UI, but no SwiftPM target contains it. Extract the Claude auto-naming argument policy into a CmuxAutoNaming target. Expose ClaudeSummarizerArgumentPolicy and keep CLI dispatch as composition.
✅ Passed checks (24 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR satisfies issue #9457 by changing the MCP configuration format and testing the resulting Claude summarizer arguments.
Out of Scope Changes check ✅ Passed The argument centralization and focused tests directly support issue #9457, with no unrelated code changes identified.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Cmux Swift Actor Isolation ✅ Passed Production diff adds pure argument construction to existing AutoNamingEnvironmentPolicy: Sendable; no MainActor annotations, mutable Sendable references, service protocols, or UI-bound access wer...
Cmux Swift Blocking Runtime ✅ Passed The PR only changes Claude argument construction and adds deterministic JSON/flag tests; no semaphore, sleep, delayed dispatch, polling, sync, or lock is introduced or expanded.
Cmux Browser Automation Off-Main ✅ Passed The PR changes only Claude auto-naming arguments and related tests; it adds no browser.* socket command or WebKit/AppKit worker-lane change covered by this rule.
Cmux Expensive Synchronous Load ✅ Passed The PR only changes Claude argv construction and adds argument tests; it adds no synchronous history/transcript loader or main-actor/interactive-path load.
Cmux Cache Substitution Correctness ✅ Passed The diff changes only Claude summarizer argv construction and test wiring; it does not replace an authoritative read with a cache or alter persistence, history, undo, or snapshot paths.
Cmux No Hacky Sleeps ✅ Passed The PR changes only Swift, Xcode project metadata, and Swift tests; it adds no covered TypeScript, JavaScript, shell, or build/runtime sleep or timer code.
Cmux Algorithmic Complexity ✅ Passed The production change builds a fixed small argv in CLI/CMUXCLI+AutoNaming.swift:153-163 and makes one dispatch call at line 126; it adds no scalable scans or sorting.
Cmux Swift Concurrency ✅ Passed The PR adds only synchronous argument construction, a call-site refactor, and synchronous tests; it introduces no Task, DispatchQueue, DispatchGroup, Combine, or completion-handler pattern.
Cmux Swift @Concurrent ✅ Passed The PR adds only synchronous argument construction and refactors a synchronous call; changed Swift files contain no async, actor-isolation, or @concurrent code.
Cmux Swiftpm Lockfiles ✅ Passed PR changes no Package.swift, Package.resolved, .gitignore, workflow, or SwiftPM package references; the pbx edits only register a test file, so no lockfile update is required.
Cmux Swift Logging ✅ Passed The PR adds no print, debugPrint, dump, NSLog, Logger, or ad hoc diagnostic logging; it only builds Claude arguments and adds tests.
Cmux User-Facing Error Privacy ✅ Passed The diff changes internal Claude subprocess arguments and adds developer comments/tests; it adds no user-facing error, alert, command output, or recovery text.
Cmux Full Internationalization ✅ Passed The diff adds CLI argument/config tokens, developer comments, and tests only; it adds no user-facing copy, localization catalogs, web messages, or locale changes.
Cmux Swiftui State Layout ✅ Passed HEAD~2..HEAD adds only CLI argument logic, dispatch wiring, project membership, and a Foundation/Testing unit test; no SwiftUI views, state wrappers, geometry, lazy rows, or render-time writes were...
Cmux Architecture Rethink ✅ Passed The PR is a small local correctness fix: the policy owns the validated MCP invariant, dispatch has one shared argument path, and added Swift lines contain no timing, polling, locking, observer, or...
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed The PR changes auto-naming argument construction and a test only; it adds no standalone window code. scripts/lint_auxiliary_window_close_shortcuts.py passes.
Cmux Source Artifacts ✅ Passed The aggregate diff contains only Swift source, a Swift test, and Xcode project configuration; no logs, caches, temp/build directories, screenshots, or copied artifacts appear.
Cmux No Test Or Debug Seam In Production Source ✅ Passed The PR changes Swift files only under CLI/ and cmuxTests/, not /Sources/; the production additions also contain no DEBUG guard or test/debug-only member seam.
Cmux No Ambient Global State ✅ Passed The production diff adds only a static let constant and an instance method on constructable AutoNamingEnvironmentPolicy; it adds no free API, mutable global, namespace type, or singleton.
Title check ✅ Passed The title clearly identifies the primary fix: passing a valid empty MCP configuration to the auto-naming summarizer.
Description check ✅ Passed The description explains the cause, fix, scope, and testing results in detail, although template checklist and demo-video sections are omitted.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-9457-workspace-auto-naming-always-fails-cmux

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@cmuxTests/AutoNamingClaudeArgumentsTests.swift`:
- Around line 31-33: Update the assertions for parsed in
AutoNamingClaudeArgumentsTests so the mcpServers value is unwrapped as a
dictionary and explicitly asserted to be empty, rather than only checking that
it exists. Preserve the existing object.count assertion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 96cacabb-47d1-4c78-84e3-0442c28ad658

📥 Commits

Reviewing files that changed from the base of the PR and between 8cc5dc4 and 5d7d7ea.

📒 Files selected for processing (4)
  • CLI/CMUXCLI+AutoNaming.swift
  • CLI/CMUXCLI+AutoNamingDispatch.swift
  • cmux.xcodeproj/project.pbxproj
  • cmuxTests/AutoNamingClaudeArgumentsTests.swift

Comment on lines +31 to +33
let object = try #require(parsed)
#expect(object["mcpServers"] as? [String: Any] != nil)
#expect(object.count == 1)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Assert that mcpServers is empty.

The current assertion accepts a non-empty mcpServers dictionary. That permits a future change to enable an MCP server while this isolation test still passes. Unwrap the dictionary and assert isEmpty.

Proposed fix
-        `#expect`(object["mcpServers"] as? [String: Any] != nil)
+        let mcpServers = try `#require`(object["mcpServers"] as? [String: Any])
+        `#expect`(mcpServers.isEmpty)
         `#expect`(object.count == 1)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
let object = try #require(parsed)
#expect(object["mcpServers"] as? [String: Any] != nil)
#expect(object.count == 1)
let object = try `#require`(parsed)
let mcpServers = try `#require`(object["mcpServers"] as? [String: Any])
`#expect`(mcpServers.isEmpty)
`#expect`(object.count == 1)
🧰 Tools
🪛 SwiftLint (0.65.0)

[Warning] 32-32: Prefer a is X to a as? X != nil

(prefer_type_checking)

🤖 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 `@cmuxTests/AutoNamingClaudeArgumentsTests.swift` around lines 31 - 33, Update
the assertions for parsed in AutoNamingClaudeArgumentsTests so the mcpServers
value is unwrapped as a dictionary and explicitly asserted to be empty, rather
than only checking that it exists. Preserve the existing object.count assertion.

@austinywang
austinywang merged commit e733aa4 into main Aug 3, 2026
19 of 23 checks passed
@austinywang
austinywang deleted the issue-9457-workspace-auto-naming-always-fails-cmux branch August 3, 2026 22:42
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.

Workspace auto-naming always fails: cmux passes --mcp-config {}, rejected by Claude Code 2.1.220

1 participant