~/.claude/settings.json loads in sessions started with CLAUDE_CONFIG_DIR pointing elsewhere (hooks, statusLine, env, model, enabledPlugins all bleed)
Version: claude-code 2.1.126 (macOS 25.4.0, zsh)
Edit (re-scoped): This issue originally framed the bug as "SessionStart hooks bleed". That framing was too narrow — the real bug is that~/.claude/settings.jsonis loaded into sessions started withCLAUDE_CONFIG_DIRpointing elsewhere, and every field in it bleeds (hooks, statusLine, env, model, enabledPlugins, …). Hooks are one symptom of many.
Summary
When CLAUDE_CONFIG_DIR=/path/to/alt-config is set, the alt config's settings.json is not honored. ~/.claude/settings.json is loaded into the alt session instead (or fully shadows the alt one). Every field declared in it applies — hooks execute, statusLine script runs, env vars are set, model is selected, enabledPlugins are activated.
Sibling of #47056 (~/.claude/CLAUDE.md loads despite CLAUDE_CONFIG_DIR). Both look like config-file resolution still hardcodes ~/.claude/ regardless of CLAUDE_CONFIG_DIR. Other things — memory dir, plugins runtime path, sessions/projects state — do correctly honor CLAUDE_CONFIG_DIR.
Repro
- Set up an alt config with distinguishable values:
``bash``
mkdir -p ~/.claude-private
cat > ~/.claude-private/settings.json <<'EOF'
{
"permissions": {"defaultMode": "auto"},
"statusLine": {"type": "command", "command": "~/.claude-private/statusline.sh"}
}
EOF
cat > ~/.claude-private/statusline.sh <<'EOF'
#!/bin/bash
echo "PRIVATE STATUSLINE"
EOF
chmod +x ~/.claude-private/statusline.sh
- In
~/.claude/settings.json, set distinguishable values:
``jsonc`
{
"model": "claude-opus-4-7",
"env": {"CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING": "1"},
"statusLine": {"type": "command", "command": "~/.claude/statusline.sh"},
"hooks": {
"SessionStart": [{
"matcher": "startup",
"hooks": [{ "type": "command", "command": "~/.claude/hooks/test.sh" }]
}]
}
}
~/.claude/statusline.sh
With outputting WORK STATUSLINE and ~/.claude/hooks/test.sh outputting WORK HOOK FIRED`.
- Launch alt session:
``bash``
CLAUDE_CONFIG_DIR=~/.claude-private claude
- Observe in the alt session:
- Statusline renders
WORK STATUSLINE(the alt one would have shownPRIVATE STATUSLINE). - System prompt contains
SessionStart:startup hook success: WORK HOOK FIRED. - Inside the session,
echo $CLAUDE_CODE_DISABLE_ADAPTIVE_THINKINGprints1(set by work'senvblock). - Model is Opus 4.7 (from work's
model), even though the alt config didn't specify one.
Expected
With CLAUDE_CONFIG_DIR set, settings.json and everything declared in it (hooks, statusLine, env, model, enabledPlugins) should be loaded from the alt root. ~/.claude/settings.json should be ignored, or at minimum fully shadowed by the alt config's settings.json.
Actual
~/.claude/settings.json is loaded fully into the alt session. The alt config's own settings.json is either not read or is fully shadowed by the home one. CLAUDE_CONFIG_DIR continues to be honored for runtime/data paths (memory dir, plugins runtime, sessions/projects state), but not for config-file loading.
Impact
For users running parallel configs (e.g. work alongside personal), all work-side settings.json content bleeds into the supposedly isolated session: hooks execute (and can read work state, write to work files, inject content into the prompt), env vars apply, statusline scripts render, plugins are pre-enabled, the model selection is inherited. In my case, the work SessionStart hook injected work-memory file paths into the prompt and the assistant followed them, reading work memory in a session intended to be isolated.
Workaround
For hooks and statusLine (command-style fields), guard each home-side script at the top:
[[ "$CLAUDE_CONFIG_DIR" == *".claude-private"* ]] && exit 0
For declarative fields (env, model, enabledPlugins), no user-level workaround — the alt config isn't read, so those values can't be overridden from there.
Related
- #47056 —
~/.claude/CLAUDE.mdloaded despiteCLAUDE_CONFIG_DIR(sibling bug, likely same root cause) - #55065 —
CLAUDE_CONFIG_DIRsemantics inconsistent across settings.json vs. skills directory
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗