claude-code icon indicating copy to clipboard operation
claude-code copied to clipboard

Support persistent environment variables across Bash calls

Open bukzor opened this issue 1 month ago • 1 comments

Summary

Provide a mechanism for Claude to set environment variables that persist across Bash() tool calls within a session.

Use Case

Multi-step workflows need to maintain state:

# Step 1: Initialize
GIT_INDEX=$(mktemp)
# Step 2 (later Bash call): Use it
git --index-file=$GIT_INDEX ...  # GIT_INDEX is gone

Currently each Bash() call is a fresh subprocess with no way to carry state forward except via files.

Current Workaround (Linux-only)

We discovered that appending to the session's shell snapshot file (~/.claude/shell-snapshots/snapshot-*.sh) persists variables, since it's sourced before each Bash() call:

# Find snapshot via SID
sid=$(cut -d' ' -f6 /proc/self/stat)
snapshot=$(ps -o cmd= --sid "$sid" | sed -n 's/.*source \([^ ]*snapshot[^ ]*\.sh\).*/\1/p')
# Append export
echo "export MY_VAR=value" >> "$snapshot"

This works but is fragile and Linux-only.

Suggested Implementation

Either:

  1. Parse simple exports: Recognize export VAR=value in Bash output and persist it
  2. Dedicated command: claude-env set VAR=value
  3. Document the snapshot mechanism: If it's intended to be stable, document it

Option 1 aligns with shell semantics and requires no new syntax.

bukzor avatar Dec 11 '25 21:12 bukzor

This startup hook fixes it for me :)

#!/usr/bin/env bash

# Read session JSON from stdin
INPUT=$(cat)
CLAUDE_SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // empty')

# Detect project context
PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo "$PWD")
PROJECT_NAME=$(basename "$PROJECT_ROOT")
PROJECT_BRANCH=$(git branch --show-current 2>/dev/null || echo "")

if [ -n "$CLAUDE_ENV_FILE" ]; then
    # Session identity
    echo "export CLAUDE_SESSION_ID=\"$CLAUDE_SESSION_ID\"" >> "$CLAUDE_ENV_FILE"

    # Project context
    echo "export project_root=\"$PROJECT_ROOT\"" >> "$CLAUDE_ENV_FILE"
    echo "export project_name=\"$PROJECT_NAME\"" >> "$CLAUDE_ENV_FILE"
    [ -n "$PROJECT_BRANCH" ] && echo "export project_branch=\"$PROJECT_BRANCH\"" >> "$CLAUDE_ENV_FILE"

    # Inherit from mycc wrapper if present
    [ -n "$myccpid" ] && echo "export myccpid=\"$myccpid\"" >> "$CLAUDE_ENV_FILE"
    [ -n "$ai_model" ] && echo "export ai_model=\"$ai_model\"" >> "$CLAUDE_ENV_FILE"
fi
echo "Session ID: $CLAUDE_SESSION_ID"

exit 0

techjoec avatar Dec 23 '25 10:12 techjoec