Problem
ClaudeCode.Adapter.Port.build_env/2 calls System.get_env() and passes every system environment variable to the CLI subprocess. The CLI only uses a specific set of documented env vars. Passing everything is wasteful (the shell command string grows unnecessarily large) and leaks host environment state that the CLI doesn't need.
Proposed Solution
Filter environment variables to only those the CLI actually uses. Based on the official env vars documentation, the CLI recognizes vars from these categories:
Namespace prefixes (filter by prefix)
ANTHROPIC_ — API keys, auth, base URL, model config, Foundry/Bedrock
CLAUDE_CODE_ — Feature flags, config, tool settings
CLAUDE_ (broader) — CLAUDE_AUTOCOMPACT_PCT_OVERRIDE, CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR, CLAUDE_CONFIG_DIR, CLAUDE_ENV_FILE, CLAUDE_STREAM_IDLE_TIMEOUT_MS
VERTEX_REGION_ — Vertex AI region overrides
Non-namespaced vars (explicit allowlist required)
AWS_BEARER_TOKEN_BEDROCK
BASH_DEFAULT_TIMEOUT_MS, BASH_MAX_OUTPUT_LENGTH, BASH_MAX_TIMEOUT_MS
CLAUDECODE
DISABLE_AUTOUPDATER, DISABLE_COST_WARNINGS, DISABLE_ERROR_REPORTING, DISABLE_FEEDBACK_COMMAND, DISABLE_INSTALLATION_CHECKS, DISABLE_PROMPT_CACHING, DISABLE_PROMPT_CACHING_HAIKU, DISABLE_PROMPT_CACHING_OPUS, DISABLE_PROMPT_CACHING_SONNET, DISABLE_TELEMETRY
ENABLE_CLAUDEAI_MCP_SERVERS, ENABLE_TOOL_SEARCH
FORCE_AUTOUPDATE_PLUGINS
HTTP_PROXY, HTTPS_PROXY, NO_PROXY
IS_DEMO
MAX_MCP_OUTPUT_TOKENS, MAX_THINKING_TOKENS
MCP_CLIENT_SECRET, MCP_OAUTH_CALLBACK_PORT, MCP_TIMEOUT, MCP_TOOL_TIMEOUT
SLASH_COMMAND_TOOL_CHAR_BUDGET
USE_BUILTIN_RIPGREP
Standard system vars (needed for CLI to function)
PATH — tool resolution (git, rg, etc.)
HOME — config/data directory
SHELL — shell detection
TERM — terminal capabilities
LANG, LC_* — locale
USER, LOGNAME — user identity
TMPDIR, TMP, TEMP — temp directory
XDG_CONFIG_HOME, XDG_DATA_HOME — XDG directories
NODE_EXTRA_CA_CERTS, NODE_TLS_REJECT_UNAUTHORIZED — Node.js TLS config (CLI is Node-based)
Implementation Approach
- Define prefix list:
["ANTHROPIC_", "CLAUDE_CODE_", "CLAUDE_", "VERTEX_REGION_"]
- Define explicit allowlist for non-namespaced vars
- Define system essentials allowlist (
PATH, HOME, etc.)
- In
build_env/2, filter System.get_env() through these lists before merging SDK and user vars
- User-provided
:env vars should still be passed through unfiltered (they are intentional overrides)
Notes
- The env vars doc page may change over time — the allowlist should be easy to maintain
- Consider a module attribute or config for the allowlist so it's easy to update
- The SDK-injected vars (
CLAUDE_CODE_ENTRYPOINT, CLAUDE_AGENT_SDK_VERSION) are added after filtering via sdk_env_vars/0 so they're unaffected
Problem
ClaudeCode.Adapter.Port.build_env/2callsSystem.get_env()and passes every system environment variable to the CLI subprocess. The CLI only uses a specific set of documented env vars. Passing everything is wasteful (the shell command string grows unnecessarily large) and leaks host environment state that the CLI doesn't need.Proposed Solution
Filter environment variables to only those the CLI actually uses. Based on the official env vars documentation, the CLI recognizes vars from these categories:
Namespace prefixes (filter by prefix)
ANTHROPIC_— API keys, auth, base URL, model config, Foundry/BedrockCLAUDE_CODE_— Feature flags, config, tool settingsCLAUDE_(broader) —CLAUDE_AUTOCOMPACT_PCT_OVERRIDE,CLAUDE_BASH_MAINTAIN_PROJECT_WORKING_DIR,CLAUDE_CONFIG_DIR,CLAUDE_ENV_FILE,CLAUDE_STREAM_IDLE_TIMEOUT_MSVERTEX_REGION_— Vertex AI region overridesNon-namespaced vars (explicit allowlist required)
AWS_BEARER_TOKEN_BEDROCKBASH_DEFAULT_TIMEOUT_MS,BASH_MAX_OUTPUT_LENGTH,BASH_MAX_TIMEOUT_MSCLAUDECODEDISABLE_AUTOUPDATER,DISABLE_COST_WARNINGS,DISABLE_ERROR_REPORTING,DISABLE_FEEDBACK_COMMAND,DISABLE_INSTALLATION_CHECKS,DISABLE_PROMPT_CACHING,DISABLE_PROMPT_CACHING_HAIKU,DISABLE_PROMPT_CACHING_OPUS,DISABLE_PROMPT_CACHING_SONNET,DISABLE_TELEMETRYENABLE_CLAUDEAI_MCP_SERVERS,ENABLE_TOOL_SEARCHFORCE_AUTOUPDATE_PLUGINSHTTP_PROXY,HTTPS_PROXY,NO_PROXYIS_DEMOMAX_MCP_OUTPUT_TOKENS,MAX_THINKING_TOKENSMCP_CLIENT_SECRET,MCP_OAUTH_CALLBACK_PORT,MCP_TIMEOUT,MCP_TOOL_TIMEOUTSLASH_COMMAND_TOOL_CHAR_BUDGETUSE_BUILTIN_RIPGREPStandard system vars (needed for CLI to function)
PATH— tool resolution (git, rg, etc.)HOME— config/data directorySHELL— shell detectionTERM— terminal capabilitiesLANG,LC_*— localeUSER,LOGNAME— user identityTMPDIR,TMP,TEMP— temp directoryXDG_CONFIG_HOME,XDG_DATA_HOME— XDG directoriesNODE_EXTRA_CA_CERTS,NODE_TLS_REJECT_UNAUTHORIZED— Node.js TLS config (CLI is Node-based)Implementation Approach
["ANTHROPIC_", "CLAUDE_CODE_", "CLAUDE_", "VERTEX_REGION_"]PATH,HOME, etc.)build_env/2, filterSystem.get_env()through these lists before merging SDK and user vars:envvars should still be passed through unfiltered (they are intentional overrides)Notes
CLAUDE_CODE_ENTRYPOINT,CLAUDE_AGENT_SDK_VERSION) are added after filtering viasdk_env_vars/0so they're unaffected