Skip to content

Stop exporting CLAUDE_CONFIG_DIR=$HOME/.claude in the Resume-in-new-tab launch command - #4401

Closed
mvanhorn wants to merge 1 commit into
manaflow-ai:mainfrom
mvanhorn:fix/4255-cmux-resume-launch-claude-config-dir-redundant-export
Closed

mvanhorn wants to merge 1 commit into
manaflow-ai:mainfrom
mvanhorn:fix/4255-cmux-resume-launch-claude-config-dir-redundant-export

Conversation

@mvanhorn

@mvanhorn mvanhorn commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

There are two independent fix sites; the primary one (1) is sufficient on its own, and (2) is a defense-in-depth wrapper-side patch that masks future regressions.

  1. Primary fix — stop emitting the redundant env prefix. Find where the Vault resume launch command is assembled and only include the env CLAUDE_CONFIG_DIR=... prefix when the value to be exported is not equal to $HOME/.claude (i.e. when the user really is on a non-default custom config dir). Candidate sites the reporter flagged via grep:

    Also drop the two CMUX_PRESERVE_CLAUDE_AUTH_SELECTION_ENV* variables from the emitted command — they are wrapper-internal and the wrapper unsets them anyway. Keep them inside the wrapper code path; just stop exporting them to the user's external shell.

  2. Defense-in-depth in the wrapper (Resources/bin/claude). At the end of normalize_claude_config_dir(), after the legacy-path rewrite block, add:

    if [[ "$CLAUDE_CONFIG_DIR" == "$HOME/.claude" ]]; then
        unset CLAUDE_CONFIG_DIR
    fi

    This means even if a future code path regresses and re-exports the default value, the wrapper unsets it before exec'ing claude. Tiny behavior change for the (probably empty) set of users who deliberately set CLAUDE_CONFIG_DIR=$HOME/.claude to force the custom-config-dir code path — documented in the PR.

  3. Do not change the non-default CLAUDE_CONFIG_DIR path. Users with a genuinely custom config dir (multi-account workflows, container setups) must continue to see it exported. The fix is conditional on equality with $HOME/.claude.

Why this matters

The GUI command emitted by cmux's "Vault by folder → Resume in new tab" feature always begins with:

env CLAUDE_CONFIG_DIR=$HOME/.claude \
    CMUX_PRESERVE_CLAUDE_AUTH_SELECTION_ENV=1 \
    CMUX_PRESERVE_CLAUDE_AUTH_SELECTION_ENV_KEYS=CLAUDE_CONFIG_DIR \
    claude --resume <id> ...

$HOME/.claude is the Claude CLI's default for CLAUDE_CONFIG_DIR. But because Claude CLI distinguishes "variable not set" from "variable set to the default value" (via something equivalent to !!process.env.CLAUDE_CONFIG_DIR rather than a value comparison), the act of exporting the var takes Claude down its "custom config dir" branch, which fails to read the existing keychain credential and forces the user to re-authenticate every Vault resume.

Reporter (treerobin06) bisected this with five command variants on cmux 0.64.6 / macOS 26.4.1 / Apple Silicon. Removing the env CLAUDE_CONFIG_DIR=... prefix is the only variable that flips behavior from "re-auth prompt" to "session resumes cleanly". The two CMUX_PRESERVE_* env vars are inert outside the cmux-bundled Resources/bin/claude wrapper (the wrapper already unsets them before exec'ing the real claude binary), so they are dead weight in the emitted command.

Testing

  1. Vault resume default OAuth: sign in normally, run a session, Cmd-Q, reopen cmux, Vault by folder → Resume in new tab. Generated command must not contain CLAUDE_CONFIG_DIR=$HOME/.claude and must not contain CMUX_PRESERVE_CLAUDE_AUTH_SELECTION_ENV*. Pasting the command into a fresh shell resumes the session without re-auth prompt.
  2. Vault resume with custom CLAUDE_CONFIG_DIR: launch cmux with CLAUDE_CONFIG_DIR=/tmp/alt-claude-config claude once; create a session; Cmd-Q; reopen and use Resume in new tab. The generated command MUST still export CLAUDE_CONFIG_DIR=/tmp/alt-claude-config because the value is non-default.
  3. Wrapper unit: Resources/bin/claude invoked with CLAUDE_CONFIG_DIR=$HOME/.claude env set must unset the variable before exec; with CLAUDE_CONFIG_DIR=/some/other/path must preserve it.
  4. Five-variant bisection regression: reproduce reporter's table A-E; only variant E (the original buggy emission) should be impossible to produce; A-D continue to work; the new "default-omitted" variant is a sixth row that also works.
  5. No regression on companion Resume launch command uses panel's current cwd, but session may have been created in a different cwd → session-not-found after restart #4256 cd-target path: the cd '/path' && ... portion of the same emitted command remains unchanged here; Resume launch command uses panel's current cwd, but session may have been created in a different cwd → session-not-found after restart #4256 is a separate plan.

Fixes #4255

AI was used for assistance.


View in Codesmith
Need help on this PR? Tag @codesmith with what you need.

  • Let Codesmith autofix CI failures and bot reviews

Summary by cubic

Prevents forced re-auth when using “Resume in new tab” by normalizing the environment: if CLAUDE_CONFIG_DIR equals $HOME/.claude, the wrapper unsets it so the CLI treats it as default. Fixes #4255.

  • Bug Fixes
    • In Resources/bin/claude, added and invoked normalize_claude_config_dir to unset CLAUDE_CONFIG_DIR only when it equals $HOME/.claude; non-default paths are preserved.

Written for commit cf098c2. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • Chores
    • Enhanced Claude configuration directory environment normalization in the cmux wrapper to improve consistency when default paths are used.

Review Change Stack

@vercel

vercel Bot commented May 19, 2026

Copy link
Copy Markdown

@mvanhorn is attempting to deploy a commit to the Manaflow Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented May 19, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a3f251f5-f5e7-4d03-968e-4edf6cdf78eb

📥 Commits

Reviewing files that changed from the base of the PR and between c6db818 and cf098c2.

📒 Files selected for processing (1)
  • Resources/bin/claude

📝 Walkthrough

Walkthrough

The Resources/bin/claude cmux wrapper adds environment normalization logic by introducing a normalize_claude_config_dir() helper function that unsets CLAUDE_CONFIG_DIR when explicitly set to the default $HOME/.claude. This helper is called before the wrapper determines whether to pass through unchanged to claude or inject cmux session/hook behavior.

Changes

Config directory normalization

Layer / File(s) Summary
Config directory normalization helper
Resources/bin/claude
Adds normalize_claude_config_dir() function that unsets CLAUDE_CONFIG_DIR when it equals $HOME/.claude, and invokes this helper in the control flow before hook injection logic.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related issues

  • manaflow-ai/cmux#4255: The new normalize_claude_config_dir() helper directly addresses the CLAUDE_CONFIG_DIR handling bug by unsetting the default ~/.claude value.
  • manaflow-ai/cmux#4087: The new normalization logic resolves the same CLAUDE_CONFIG_DIR environment variable handling issue described in this issue.

Possibly related PRs

Poem

🐰 A whisper of config, so tidy and clean,
Unsetting the defaults that might intervene,
Before hooks take flight on their merry quest,
The wrapper says "relax, I'll handle the rest!" ✨


Important

Pre-merge checks failed

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

❌ Failed checks (3 inconclusive)

Check name Status Explanation Resolution
Cmux Swift Blocking Runtime ❓ Inconclusive No result was produced after verification. Marking as INCONCLUSIVE. Re-run the check or adjust instructions to produce a final result.
Cmux Swift Logging ❓ Inconclusive The custom check references .github/review-bot-rules/swift-logging.md which does not exist in this repository, making the check unverifiable. The rules file .github/review-bot-rules/swift-logging.md must be present in the repository to assess Swift logging violations.
Cmux Swift Auxiliary Window Close Shortcuts ❓ Inconclusive Check references non-existent files: .github/review-bot-rules/swift-auxiliary-window-close-shortcuts.md and scripts/lint_auxiliary_window_close_shortcuts.py, making evaluation impossible. Provide the missing rule file and linting script, or clarify applicability.
✅ Passed checks (14 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the primary change: stopping the export of CLAUDE_CONFIG_DIR=$HOME/.claude in the Resume-in-new-tab launch command, which directly addresses the core issue.
Description check ✅ Passed The description provides comprehensive context with clear problem statement, three-part solution strategy, detailed testing plan, and explanation of why the change matters. It addresses all template sections despite some being incomplete (e.g., no demo video for non-UI change, checklist unchecked).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Cmux Swift Actor Isolation ✅ Passed Only shell script changes in Resources/bin/claude were made; no production Swift changes present. Check not applicable.
Cmux No Hacky Sleeps ✅ Passed Resources/bin/claude (new shell script) contains no sleep, wait, polling, or wall-clock delays. Timeouts are proper config/hook abstractions, not hacky waits.
Cmux Swift Concurrency ✅ Passed PR modifies only Resources/bin/claude (a bash script), not Swift code. The custom check requires assessing Swift code for legacy async patterns; no Swift files were modified.
Cmux Swift @Concurrent ✅ Passed PR only modifies Resources/bin/claude (bash script); no Swift files changed. The @concurrent annotation check applies only to Swift changes, making it not applicable here.
Cmux Swift File And Package Boundaries ✅ Passed PR modifies only Resources/bin/claude (bash script), not Swift files. The rule file referenced in the check does not exist in this repository.
Cmux User-Facing Error Privacy ✅ Passed The error message "Error: claude not found in PATH" safely references only the tool name and standard PATH, without exposing vendors, credentials, or sensitive information.
Cmux Full Internationalization ✅ Passed PR adds bash wrapper function to Resources/bin/claude with developer comments and environment logic only. No user-facing strings, Swift localization, string catalogs, or Info.plist changes.
Cmux Swiftui State Layout ✅ Passed PR changes bash script and removes legacy SwiftUI state files (SidebarState.swift, TerminalStartupEnvironment.swift). No new SwiftUI state layout violations introduced.
Cmux Architecture Rethink ✅ Passed PR contains only bash script changes, not Swift code. The custom check for Swift architecture violations is inapplicable here since no Swift files were modified.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch fix/4255-cmux-resume-launch-claude-config-dir-redundant-export

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 and usage tips.

@greptile-apps

greptile-apps Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a normalize_claude_config_dir() function to the Resources/bin/claude wrapper that unsets CLAUDE_CONFIG_DIR when its value equals $HOME/.claude, preventing Claude CLI from treating the default path as a custom-config-dir and forcing re-authentication on every "Resume in new tab" invocation.

  • The wrapper-side fix correctly intercepts env CLAUDE_CONFIG_DIR=$HOME/.claude ... claude --resume ... commands for users whose claude resolves to the cmux wrapper, eliminating the re-auth regression for the typical cmux user.
  • The normalization is called unconditionally before both the pass-through and cmux execution paths, which means it also fires for non-cmux users who have explicitly set CLAUDE_CONFIG_DIR=$HOME/.claude in their environment \u2014 a deliberate, documented tradeoff.
  • The PR description identifies three Swift files as the primary fix sites (stopping the env prefix from being emitted in the first place), but none of those files are changed in this PR; the emitted launch command still contains CLAUDE_CONFIG_DIR=$HOME/.claude and the wrapper normalization is the sole guard against the bug.

Confidence Score: 3/5

The wrapper change is internally correct but addresses only the secondary (defense-in-depth) fix site; the Swift code that generates the problematic launch command string is unchanged.

The wrapper normalization works for the primary user path where the wrapper is claude in PATH, but any execution path that bypasses the wrapper will still hit the re-auth bug. The PR description itself frames the Swift fix as the primary fix and this wrapper change as defense-in-depth, yet only the secondary fix is present.

The Swift files named in the PR description as the root-cause fix sites (AgentLaunchEnvironmentPolicy.swift, TerminalStartupEnvironment.swift, RestorableAgentSession.swift) are not present in this changeset and warrant follow-up.

Important Files Changed

Filename Overview
Resources/bin/claude Adds normalize_claude_config_dir() that unsets CLAUDE_CONFIG_DIR when it equals $HOME/.claude, called unconditionally before both the pass-through and cmux execution paths. Correctly handles the described re-auth regression for users going through the wrapper.

Sequence Diagram

sequenceDiagram
    participant GUI as cmux GUI (Swift)
    participant Shell as User Shell
    participant Wrapper as Resources/bin/claude (wrapper)
    participant Claude as Real claude binary

    GUI->>Shell: "emit command: env CLAUDE_CONFIG_DIR=$HOME/.claude claude --resume id"
    Note over GUI: Swift fix NOT in this PR, still emits prefix

    Shell->>Wrapper: "exec with CLAUDE_CONFIG_DIR=$HOME/.claude in env"
    Wrapper->>Wrapper: normalize_claude_config_dir() unsets CLAUDE_CONFIG_DIR
    Wrapper->>Claude: exec without CLAUDE_CONFIG_DIR
    Claude-->>Shell: resumes session without re-auth

    Note over Shell,Claude: If real claude is before wrapper in PATH, CLAUDE_CONFIG_DIR reaches claude directly and re-auth bug persists
Loading

Reviews (1): Last reviewed commit: "Stop exporting CLAUDE_CONFIG_DIR=$HOME/...." | Re-trigger Greptile

Comment thread Resources/bin/claude
Comment on lines +38 to +53
normalize_claude_config_dir() {
# Issue #4255: Claude treats CLAUDE_CONFIG_DIR being set to its default
# path differently from the variable being absent, so normalize that case.
if [[ "${CLAUDE_CONFIG_DIR:-}" == "$HOME/.claude" ]]; then
unset CLAUDE_CONFIG_DIR
fi
}

# Pass through if not in a cmux terminal, hooks are disabled, or the cmux
# socket is unavailable (stale env / app not running).
IN_CMUX=0
if [[ -n "$CMUX_SURFACE_ID" ]]; then
IN_CMUX=1
fi

normalize_claude_config_dir

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.

P1 Primary Swift-side fix is absent — wrapper normalization is the only guard

The PR description identifies three Swift files (AgentLaunchEnvironmentPolicy.swift, TerminalStartupEnvironment.swift, RestorableAgentSession.swift) as the root-cause fix sites that should stop emitting CLAUDE_CONFIG_DIR=$HOME/.claude in the generated launch command, and explicitly labels this wrapper change as "defense-in-depth." None of those files appear in this changeset (or in the repository at all). The emitted "Resume in new tab" command string therefore still contains the problematic prefix — it is only neutralized at runtime because the wrapper intercepts it. A user who copies that command and runs it in a shell where the real claude binary appears before the cmux wrapper in PATH, or any execution path that bypasses the wrapper, will still trigger the forced re-auth. The fix is incomplete relative to the PR's own description of what constitutes a full resolution.

Comment thread Resources/bin/claude
IN_CMUX=1
fi

normalize_claude_config_dir

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.

P2 Normalization fires unconditionally for non-cmux users too

normalize_claude_config_dir is called at line 53, before the IN_CMUX/socket guard on line 55. This means a user who is entirely outside cmux and has deliberately set CLAUDE_CONFIG_DIR=$HOME/.claude in their environment (e.g., to force the custom-config-dir branch for debugging) will have it silently unset by the wrapper before exec "$REAL_CLAUDE" "$@". The PR description acknowledges this as intentional for a "probably empty" set of users, but for a wrapper that is otherwise transparent when not in cmux, silently mutating the environment in the pass-through path may surprise users who rely on this being a no-op outside cmux.

@cubic-dev-ai cubic-dev-ai 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.

No issues found across 1 file

Re-trigger cubic

@mvanhorn

Copy link
Copy Markdown
Contributor Author

Greptile is right -- the PR description listed both fix sites but the diff only ships the wrapper-side defense-in-depth one. I went looking for the 3 Swift files I named in the issue body (AgentLaunchEnvironmentPolicy / TerminalStartupEnvironment / RestorableAgentSession) and grep does'nt find CLAUDE_CONFIG_DIR anywhere in the Swift sources -- the code that assembles the resume command lives somewhere I can't immediately locate. The wrapper-side normalization unconditionally unsets CLAUDE_CONFIG_DIR=$HOME/.claude before exec, so the bug is masked for the typical user path (claude resolves to the cmux wrapper). Any execution path that bypasses the wrapper still hits the re-auth, so the root-cause fix in the launch-command assembler is still worth doing as a follow-up if a maintainer can point at the right file.

@teamleaderleo

Copy link
Copy Markdown
Collaborator

Thank you for this! The Claude config-dir normalization is on main in 136eb2a :)

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.

Resume launch command exports CLAUDE_CONFIG_DIR=$HOME/.claude (the default), triggers Claude CLI custom-config-dir branch and forces re-authentication

2 participants