Skip to content

[FEATURE] CLAUDE_ENV_FILE should propagate to PowerShell tool and child plugins, not bash-only #60697

@ChrisonSimtian

Description

@ChrisonSimtian

What's the problem

CLAUDE_ENV_FILE (populated by SessionStart / Setup / CwdChanged / FileChanged hooks) is documented as making env vars "available in all subsequent Bash commands that Claude Code executes during the session" — and that's exactly what it does. The values land in bash tool subprocesses, but nothing else sees them.

On Windows with PowerShell as the daily driver, this creates a sharp split: bash tool calls have my OAuth / API tokens, while the PowerShell tool, the statusline command, MCP servers, and any external plugin Claude Code spawns directly all see $null for those same vars. Subagents have the same problem (already filed as #46696).

Why it matters

We use a SessionStart hook to resolve 1Password references in .claude/secrets.env via op inject and write the resulting export KEY='value' lines to $CLAUDE_ENV_FILE. This is exactly the workflow the docs describe.

Result today, on Windows + pwsh:

  • Bash tool: JIRA_TOKEN, OCTOPUS_API_KEY, etc. all populated ✅
  • PowerShell tool: all $null
  • Statusline (pwsh, configured in .claude/settings.json): can't see the loaded vars, so it falsely shows 🔒 0/3 even though everything is loaded
  • Any pwsh-based plugin / MCP server: same — can't see them
  • 3rd-party plugins: not under our control, so no "just wrap it" workaround

We can patch our own statusline plugin to fall back to parsing ~/.claude/session-env/<sid>/sessionstart-hook-*.sh to recover a truthful indicator, but that's a band-aid for one consumer. The PowerShell tool, MCP servers, and external plugins remain blind. There is no user-land fix that covers all of them.

What I'd like

Make CLAUDE_ENV_FILE semantics tool/shell-agnostic: when a hook appends KEY=value (or export KEY='value') lines to $CLAUDE_ENV_FILE, Claude Code should set those env vars on its own process so that every child process — bash tool, PowerShell tool, MCP servers, plugins, subagents, statusline command — inherits them naturally via OS-level env propagation.

That removes a whole class of "why doesn't X see my secrets" problems and also subsumes #46696 (subagent inheritance) and arguably #51862 (bash-tool sourcing), since with vars on the parent process there's no need to source anything per-child.

Acceptance suggestions

  • Parser accepts both KEY=value and export KEY='value' (the latter is what bash-style hook examples in your own docs produce).
  • Single-quote escaping ('\'') honored, since op inject output uses that.
  • $env:CLAUDE_ENV_FILE itself still set inside hook subprocesses so existing hooks continue to work unchanged.
  • Optional: surface the resolved env via /env (which would also close part of [DOCS] Built-in commands reference missing /env coverage for PowerShell tool #41268).

Workarounds considered and rejected

  • Wrapper script for pwsh tools — works for the statusline (one entry point we control), but doesn't reach MCP servers, external plugins, or future tooling that Claude Code spawns directly. Wrapping isn't viable as a general answer.
  • Persist secrets to Windows User env via [Environment]::SetEnvironmentVariable($k, $v, 'User') — works mechanically but writes rotating 1Password tokens to the registry, persists past the session, and survives Claude Code exits. Security-smell.
  • Always launch Claude Code from a pre-populated shell (e.g. op run -- pwsh then claude) — works perfectly when remembered, but the SessionStart hook exists precisely because plain claude launches need to recover. Today the recovery is bash-only.

Environment

  • Claude Code: latest stable, Windows 11
  • Shell: PowerShell 7
  • Hook: SessionStart writing export KEY='value' lines to $CLAUDE_ENV_FILE (the exact format your hooks docs show)

Filed via Claude Code on my own behalf — meta enough that I had to flag it 😄

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions