~/.claude/settings.json loads in sessions started with CLAUDE_CONFIG_DIR pointing elsewhere (hooks, statusLine, env, model, enabledPlugins all bleed)

Open 💬 4 comments Opened May 1, 2026 by paolobrolin

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.json is loaded into sessions started with CLAUDE_CONFIG_DIR pointing 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

  1. 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
``

  1. 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" }]
}]
}
}
`
With
~/.claude/statusline.sh outputting WORK STATUSLINE and ~/.claude/hooks/test.sh outputting WORK HOOK FIRED`.

  1. Launch alt session:

``bash
CLAUDE_CONFIG_DIR=~/.claude-private claude
``

  1. Observe in the alt session:
  • Statusline renders WORK STATUSLINE (the alt one would have shown PRIVATE STATUSLINE).
  • System prompt contains SessionStart:startup hook success: WORK HOOK FIRED.
  • Inside the session, echo $CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING prints 1 (set by work's env block).
  • 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.md loaded despite CLAUDE_CONFIG_DIR (sibling bug, likely same root cause)
  • #55065 — CLAUDE_CONFIG_DIR semantics inconsistent across settings.json vs. skills directory

View original on GitHub ↗

This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗