Add :inherit_env option for environment variable control#47
Merged
Conversation
Adds :inherit_env session option for controlling which system env vars
the CLI subprocess inherits (:all, [], or a list of strings/{:prefix, ...}
tuples). Widens :env to accept false values for unsetting variables via
Erlang Port's native env unsetting behavior.
- Replace Enum.filter |> Map.new with Map.filter/2 - Remove unnecessary result binding in filter_system_env/3 - Use !!debug instead of debug != false for safer boolean coercion - Replace throw/catch validators with Enum.find pattern (matches codebase style)
Contributor
|
Excellent approach. Glad to have at least sparked the thought. |
Owner
Author
|
Yes thank you 🙏 it needed serious improving |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
:inherit_envsession option to control which system env vars are inherited by the CLI subprocess. Supports:all(default, stripsCLAUDECODE),[](inherit nothing), or a list of exact strings /{:prefix, "..."}tuples for selective inheritance.:envto acceptfalsevalues for unsetting vars, leveraging Erlang Port's native{charlist, false}behavior.filter_system_env/3toClaudeCode.Adapter.Portwith debug logging for unmatched entries.Background
Supersedes the env filtering portion of #42 and closes #44.
#44 proposed 4 options (
filter_env,allowed_env,disallowed_env,env) with a hardcoded allowlist of ~30 CLI-specific env vars plus 5 prefix patterns (ANTHROPIC_,CLAUDE_CODE_,CLAUDE_,VERTEX_REGION_,LC_) and ~14 system essentials (PATH,HOME,SHELL, etc.). While thorough, this approach had issues:Maintenance burden. The allowlist is a snapshot of what Claude Code supports today. The CLI adds, renames, and removes env vars regularly —
DISABLE_PROMPT_CACHING_HAIKU,SLASH_COMMAND_TOOL_CHAR_BUDGET,FORCE_AUTOUPDATE_PLUGINS, etc. Every CLI release could silently break users who depend on a new var that isn't in our list yet. We'd be permanently chasing upstream.Unnecessary complexity. 4 options with 2 operating modes (
filter_env: truevsfalse) and interactions between them (disallowed_envworks in both modes, butallowed_envonly in filtered mode;:envoverridesdisallowed_envbut not the other way around). That's a lot of cognitive overhead for env var filtering.Wrong default for an SDK. Filtering by default is a breaking change — existing users who rely on env vars like
DATABASE_URL,HTTP_PROXY, or custom vars reaching the CLI would need to addallowed_enventries. The Python SDK passes everything through (minusCLAUDECODE), and so should we.This PR takes a simpler approach — 1 new option instead of 3:
CLAUDECODE, matching Python SDK.env: %{"RELEASE_COOKIE" => false}— leverages Erlang Port's native env unsetting.inherit_env: []orinherit_env: ["PATH", "HOME", {:prefix, "ANTHROPIC_"}]— explicit allowlist with string and prefix matching.No built-in allowlist to maintain. No multi-mode interaction rules. Two composable options that cover every use case.
Test plan
filter_system_env/3(:all, empty list, exact strings, prefix tuples, mixed, CLAUDECODE pass-through, unmatched)build_env/2with:inherit_env(async: false, System.put_env with setup/on_exit cleanup)falsevalue pass-through inbuild_env:inherit_envaccepts/rejects, session-only enforcement,:envfalse values)mix test --no-start— 1512 tests passmix quality— compile, format, credo --strict, dialyzer all pass