anthropics / anthropics/claude-agent-sdk-python
discussion: ClaudeAgentOptions.env only supports implicit parent-env inheritance with no documented isolated environment mode
- Langage dominant
- Python
- Étoiles
- 8.1k
- Forks
- 1.3k
- Merge moyen
- 2 j 31 min
- PR mergées (30 j)
- 1
Description
hey, i was exploring `src/claude_agent_sdk/_internal/transport/subprocess_cli.py` to understand how the SDK spawns the Claude Code CLI subprocess and noticed that `connect()` always builds the subprocess environment by inheriting the full parent `os.environ` and then merging user provided `ClaudeAgentOptions.env` on top of it
```python
inherited_env = {k: v for k, v in os.environ.items() if k != "CLAUDECODE"}
process_env = {
**inherited_env,
"CLAUDE_CODE_ENTRYPOINT": "sdk-py",
**self._options.env,
"CLAUDE_AGENT_SDK_VERSION": __version__,
}
```
at a normal usage level this makes sense because `env={"MY_VAR": "value"}` works as an override/addition mechanism, the confusing part is that this inheritance behaviour does not seem to be explicitly documented on `ClaudeAgentOptions.env` and there also does not appear to be a supported way to request a clean or isolated subprocess environment
this looks related to #573 but in this case the concern is broader as users currently get implicit full inheritance but no explicit way to choose between merge with parent env and isolated/clean subprocess env
### Impact
due to this, users cannot create a deterministic or sandboxed subprocess environment and also, sensitive parent variables may be inherited unintentionally and CI/reproducibility use cases become harder
(main point: current behaviour may be intentional but the API contract is not explicit enough to make that clear)
### How to reproduce
Reproduction
```python
import os
import anyio
from claude_agent_sdk import ClaudeAgentOptions
from claude_agent_sdk._errors import CLIConnectionError
from claude_agent_sdk._internal.transport.subprocess_cli import SubprocessCLITransport
class EnvCaptured(Exception):
pass
async def fake_open_process(*args, **kwargs):
env = kwargs["env"]
print("MY_CUSTOM_VAR:", env.get("MY_CUSTOM_VAR"))
print("HOME inherited:", "HOME" in env)
print("PATH inherited:", "PATH" in env)
print("ANTHROPIC_API_KEY inherited:", "ANTHROPIC_API_KEY" in env)
raise EnvCaptured("Stopped after capturing subprocess env")
async def fake_check_claude_version():
return None
async def main():
os.environ["ANTHROPIC_API_KEY"] = "dummy-secret"
options = ClaudeAgentOptions(
env={"MY_CUSTOM_VAR": "hello"},
max_turns=1,
)
transport = SubprocessCLITransport(prompt="hello", options=options)
transport._cli_path = "dummy-claude"
transport._build_command = lambda: ["dummy-claude"]
transport._check_claude_version = fake_check_claude_version
original_open_process = anyio.open_process
anyio.open_process = fake_open_process
try:
await transport.connect()
except CLIConnectionError as e:
if "Stopped after capturing subprocess env" in str(e):
print("Captured env successfully; reproduction complete.")
else:
raise
finally:
anyio.open_process = original_open_process
anyio.run(main)
```
Output:
was the current inheritance-only behaviour intentional or is the lack of an isolated environment mode an oversight? happy to make a pr if this direction sounds useful
Guide de contribution
Aucun guide de contribution indexé pour ce dépôt
Évaluation
Cette issue n'a pas encore été évaluée.