fix: the host ignored $CLAUDE_CONFIG_DIR and read ~/.claude regardless - #565
fix: the host ignored $CLAUDE_CONFIG_DIR and read ~/.claude regardless#565JSmithRobotics wants to merge 1 commit into
Conversation
Claude Code reads $CLAUDE_CONFIG_DIR before ~/.claude, and the probe dl runs inside a container has always read it too, because a devcontainer feature may set it. Only the host side did not: it joined a hardcoded .claude/.credentials.json onto $HOME, so a host that had moved its configuration reported NoToken::NotLoggedIn while holding a perfectly good login. The symptom was silent, which is why it survived. "No credential file at ~/.claude" is also the ordinary macOS state, where the login lives in the keychain, so it is deliberately not warned about; a host that had moved its config got that same quiet answer and no way to tell the two apart. The variable replaces the default rather than being tried ahead of it. Claude Code does not fall back from $CLAUDE_CONFIG_DIR to ~/.claude, and a fallback here would forward a credential out of a directory Claude Code is not reading, which is the same defect one level down: invisible until the host holds two logins, at which point it forwards the wrong one. An empty value counts as unset, matching domain::xdg's rule and what a shell exporting a bare variable means. Order is unchanged above the new arm: DEVLAUNCH_NO_CLAUDE_TOKEN first, then any exported CLAUDE_CODE_OAUTH_TOKEN, and only then the file. The exported token stays above the variable because both are ambient and that hatch is what lets a dl running inside a workspace forward the token it was handed. CREDENTIALS_RELPATH splits into CONFIG_RELPATH and CREDENTIALS_FILENAME, so the directory half is a decision and the filename half is a constant. CONFIG_RELPATH is deliberately not shared with flows::provision's CLAUDE_CONFIG_RELPATH: the same string about two different machines, with a comment in each naming the other. Public-API snapshots are untouched, since every item involved is pub(crate).
Reviewer's GuideThe host-side Claude credential lookup now honors a non-empty Flow diagram for host Claude credential resolutionflowchart TD
A["dl host launch"] --> B{"DEVLAUNCH_NO_CLAUDE_TOKEN set?"}
B -->|yes| C["NoToken::OptedOut"]
B -->|no| D{"CLAUDE_CODE_OAUTH_TOKEN parses?"}
D -->|yes| E["Forward exported access token"]
D -->|no| F{"CLAUDE_CONFIG_DIR non-empty?"}
F -->|yes| G["Read CONFIG_DIR/.credentials.json"]
F -->|no| H["Read HOME/.claude/.credentials.json"]
G --> I{"Access token found?"}
H --> I
I -->|yes| J["Forward access token"]
I -->|no| K["NoToken::NotLoggedIn"]
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
Codecov Report❌ Patch coverage is
Additional details and impacted files
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
Superseded by #570, which is the same branch opened from this repository rather than from a fork. Moved because a cross-fork pull request's base has to be a branch in the base repository, so the stack needed its parents pushed here anyway -- which left three branch names living on two remotes, two of them serving as one PR's head and another's base at the same time. Every update then had to reach both remotes or a diff would quietly misrepresent itself. Same commits, one ref each, and #570 to #573 are now a native GitHub stack. |
A host that has moved its Claude configuration now forwards its login, instead of
reporting itself as not logged in.
Claude Code reads
$CLAUDE_CONFIG_DIRbefore~/.claude, and the probedlruns inside a container has always read it too, because a devcontainer feature
may set it. Only the host side did not: it joined a hardcoded
.claude/.credentials.jsononto$HOME, so a host that had moved itsconfiguration returned
NoToken::NotLoggedInwhile holding a perfectly goodlogin, and
claudein every workspace asked for a login.The symptom was silent, which is why it survived. "No credential file at
~/.claude" is also the ordinary macOS state, where the login lives in thekeychain, so it is deliberately not warned about. A host that had moved its config
got that same quiet answer, with nothing to tell the two apart.
The variable replaces the default rather than being tried ahead of it
Claude Code does not fall back from
$CLAUDE_CONFIG_DIRto~/.claude, and afallback here would forward a credential out of a directory Claude Code is not
reading. That is the same defect one level down: invisible until the host holds two
logins, at which point it forwards the wrong one. An empty value counts as unset,
matching
domain::xdg's rule and what a shell exporting a bare variable means.Order is unchanged above the new arm:
DEVLAUNCH_NO_CLAUDE_TOKENfirst, then anyexported
CLAUDE_CODE_OAUTH_TOKEN, and only then the file. The exported tokenstays above the variable because both are ambient, and that hatch is what lets a
dlrunning inside a workspace forward the token it was handed.One split worth naming
CREDENTIALS_RELPATHbecomesCONFIG_RELPATHplusCREDENTIALS_FILENAME, so thedirectory half is a decision and the filename half is a constant.
CONFIG_RELPATHis deliberately not shared withflows::provision'sCLAUDE_CONFIG_RELPATH: it is the same string about two different machines, and acomment in each names the other. Sharing it would couple the host's layout to the
container's, which is exactly the coupling this bug came from.
Scope
clients/claude.rsplus the README,docs/workspace-tools.mdand the changelog.Public-API snapshots are untouched and verified so, because every item involved is
pub(crate).Independent of #564.
feat: --claude-profile forwards a named Claude loginbuildson the
config_dir()this introduces and carries this commit until this merges;once it does, that PR's diff collapses to its own two commits.
🤖 Generated with Claude Code
https://claude.ai/code/session_01AdSFnBdxie6TosHVmjLY28
Summary by Sourcery
Honor Claude Code’s configured host directory when resolving credentials and forwarding logins to workspaces.
Bug Fixes:
CLAUDE_CONFIG_DIRwhen forwarding host Claude credentials, preventing authenticated hosts with relocated configurations from being treated as logged out.Enhancements:
~/.claude, while preserving existing opt-out and exported-token precedence.Documentation:
CLAUDE_CONFIG_DIR, its replacement semantics, credential lookup order, and empty-value behavior.Tests: