anthropics / anthropics/claude-agent-sdk-python

discussion: ClaudeAgentOptions.env only supports implicit parent-env inheritance with no documented isolated environment mode

Aperta
#934 2 commenti 0 reazioni 0 assegnatari Vedi su GitHub
documentation enhancement question
Lingua principale
Python
Stelle
8.1k
Fork
1.3k
Merge medio
2g 31m
PR unite (30g)
1

Descrizione

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:
Image

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

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.