Preflight Checklist
Problem Statement
The env block in ~/.claude/settings.json treats values as literal strings, so it's not possible to reference other environment variables. This makes it awkward to share settings across machines (where absolute paths differ) and, more importantly, impossible to augment variables like PATH — any value I set replaces the inherited one rather than prepending to it. In practice I end up either hardcoding machine-specific absolute paths or giving up on using the env block for anything that depends on the user's existing environment.
Proposed Solution
Expand $VAR / ${VAR} references inside env values when Claude Code loads settings.json. Substitution should see both the process environment and keys already defined earlier in the same env block, so entries can build on each other:
{
"env": {
"MY_TOOL_HOME": "$HOME/.mytool",
"PATH": "${MY_TOOL_HOME}/bin:${PATH}"
}
}
After expansion, PATH would be prepended with ~/.mytool/bin instead of clobbered, and MY_TOOL_HOME would resolve per user. Unknown variables could either expand to empty (shell-style) or be left literal — either is fine as long as it's documented.
Alternative Solutions
- Hardcoding absolute paths per machine and keeping separate
settings.json files — works but doesn't travel.
- Wrapping
claude in a shell script that exports the variables before launch — works but defeats the point of having an env block in settings.json.
- Using a hook to mutate the environment — heavier than needed for static config.
Priority
Medium - Would be very helpful
Feature Category
Configuration and settings
Use Case Example
- I use Claude Code on two machines with different home directories and different locations for a local toolchain I want on
PATH.
- I'd like a single
~/.claude/settings.json (checked into my dotfiles) that works on both.
- With substitution I can write
"PATH": "${HOME}/.mytool/bin:${PATH}" once and have it resolve correctly on each machine, without clobbering the PATH I already have from my shell.
- Today I either maintain per-machine copies of
settings.json or skip the env block entirely for anything path-related.
Additional Context
Most config systems that expose an env block (docker-compose, systemd unit files, direnv, VS Code terminal.integrated.env.*) support some form of variable expansion, so the ergonomics would match what users already expect.
Related / prior art:
Preflight Checklist
Problem Statement
The
envblock in~/.claude/settings.jsontreats values as literal strings, so it's not possible to reference other environment variables. This makes it awkward to share settings across machines (where absolute paths differ) and, more importantly, impossible to augment variables likePATH— any value I set replaces the inherited one rather than prepending to it. In practice I end up either hardcoding machine-specific absolute paths or giving up on using theenvblock for anything that depends on the user's existing environment.Proposed Solution
Expand
$VAR/${VAR}references insideenvvalues when Claude Code loadssettings.json. Substitution should see both the process environment and keys already defined earlier in the sameenvblock, so entries can build on each other:{ "env": { "MY_TOOL_HOME": "$HOME/.mytool", "PATH": "${MY_TOOL_HOME}/bin:${PATH}" } }After expansion,
PATHwould be prepended with~/.mytool/bininstead of clobbered, andMY_TOOL_HOMEwould resolve per user. Unknown variables could either expand to empty (shell-style) or be left literal — either is fine as long as it's documented.Alternative Solutions
settings.jsonfiles — works but doesn't travel.claudein a shell script that exports the variables before launch — works but defeats the point of having anenvblock insettings.json.Priority
Medium - Would be very helpful
Feature Category
Configuration and settings
Use Case Example
PATH.~/.claude/settings.json(checked into my dotfiles) that works on both."PATH": "${HOME}/.mytool/bin:${PATH}"once and have it resolve correctly on each machine, without clobbering thePATHI already have from my shell.settings.jsonor skip theenvblock entirely for anything path-related.Additional Context
Most config systems that expose an
envblock (docker-compose, systemd unit files, direnv, VS Codeterminal.integrated.env.*) support some form of variable expansion, so the ergonomics would match what users already expect.Related / prior art:
${VAR}expansion in the MCP serverenvblocks of user-scope.claude.json. Same substitution pattern, sibling config file; this issue asks for the equivalent insettings.json's top-levelenvblock.${VAR}expansion for project-scope.mcp.json, which is the precedent cited in Feature request: ${VAR} env var expansion in user-scope .claude.json MCP configs #43693.op://secret references in thesettings.jsonenv section; general variable substitution would compose with or subsume that use case.urlfield; different location but same underlying gap.