[BUG] SessionStart hook doesn't receive CLAUDE_ENV_FILE when installed by a plugin
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
The https://code.claude.com/docs/en/hooks#persisting-environment-variables explains that a CLAUDE_ENV_FILE should be available to SessionStart hooks. I can verify this works for project hooks or personal hooks, but this does not work for plugin hooks.
What Should Happen?
The plugin hook should be passed CLAUDE_ENV_FILE
Error Messages/Logs
Steps to Reproduce
Put a repro here: https://github.com/gabelevi/claude_session_start_env_bug (it's basically the test plugin from the docs)
It has two hooks:
- A local hook which does
echo $CLAUDE_ENV_FILE > /tmp/CLAUDE_ENV_FILE_project.txt - A plugin hook which does
echo $CLAUDE_ENV_FILE > /tmp/CLAUDE_ENV_FILE_plugin.txt
If I install the marketplace & plugin and restart claude, I can see that both /tmp/CLAUDE_ENV_FILE_plugin.txt and /tmp/CLAUDE_ENV_FILE_project.txt were created at the same time. But /tmp/CLAUDE_ENV_FILE_plugin.txt is always empty while /tmp/CLAUDE_ENV_FILE_project.txt contains the absolute path of my session's env file (e.g. /Users/username/.claude/session-env/c76b6e6b-25ce-453c-81e0-de5bc413ca2f/hook-0.sh)
Claude Model
Sonnet (default)
Is this a regression?
I don't know
Last Working Version
No response
Claude Code Version
2.0.36
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
No response
Where is quality control? :-)
This is a really stupid bug - but agree its confirmed - all works with the env file but its NOT created when the hook is added as a plugin then the $CLAUDE_ENV_FILE is NOT populated
You can as a workarround take the session id from the json and construct the CLAUDE_ENV_FILE with $CLAUDE_HOME/session-env/CLAUDE_SESSION_ID/hook-0.sh and then do the exports into that file - then it will be called - that works and can confirm it - i had to do it like that - Claude just reads the hook-0.sh when it loads bash sessions after that file is created i also store CLAUDE_SESSION_ID so i can use it later
# Read and log the input JSON
INPUT_JSON=$(cat)
# Extract session_id from JSON and export CLAUDE_SESSION_ID
export CLAUDE_SESSION_ID=$(echo "$INPUT_JSON" | grep -o '"session_id":"[^"]*"' | cut -d'"' -f4)
# Create CLAUDE_ENV_FILE if not set
if [ -z "$CLAUDE_ENV_FILE" ] && [ -n "$CLAUDE_SESSION_ID" ] && [ -n "$CLAUDE_HOME" ]; then
export CLAUDE_ENV_FILE="$CLAUDE_HOME/session-env/$CLAUDE_SESSION_ID/hook-0.sh"
# Create the directory if it doesn't exist
mkdir -p "$(dirname "$CLAUDE_ENV_FILE")"
# Create the file if it doesn't exist
touch "$CLAUDE_ENV_FILE"
echo "✓ Created CLAUDE_ENV_FILE: $CLAUDE_ENV_FILE" >> "$LOG_FILE"
fi
Im not sure what it breaks but i have no files in my whole session library other than hook-0.sh and ONLY files i created my self i presume each hook will have a unique file numbered so probably it should have a increment if it exists or just use a higher number but dont know how claude reads it :/
Tested with reporter's exact repro from https://github.com/gabelevi/claude_session_start_env_bug:
| Hook Type | Before Fix | After Fix |
|--------------|---------------------------------------------------|---------------------------------------------------|
| Project hook | ✅ /Users/dalton/.claude/session-env/.../hook-0.sh | ✅ /Users/dalton/.claude/session-env/.../hook-0.sh |
| Plugin hook | ❌ (empty) | ✅ /Users/dalton/.claude/session-env/.../hook-1.sh |
Thanks for the report & repro @gabelevi 😄 Fixed in next release.