Skip to content

Enhancement: expose CLAUDE_SESSION_ID environment variable in hooks and tool subprocesses #59216

@bjsassone

Description

@bjsassone

Preflight Checklist

  • I have searched existing requests and this feature hasn't been requested yet
  • This is a single feature request (not multiple features)

Problem Statement

Claude Code assigns a unique UUID to each session and uses it to name the transcript file (~/.claude/projects/<slug>/<uuid>.jsonl). However, this UUID is not exposed to hook commands or Bash tool subprocesses. There is no supported, documented way for hooks or skills to know which session they belong to.

Without a session identity, skills and hooks that need to write session-scoped state (markers, per-session summaries, temporary files) must resort to heuristics. The most common workaround — identifying the current session by finding the most recently modified JSONL in the project directory — is a race condition: when two sessions share the same project directory, the "most recent" signal flips between them as each session writes, causing hooks to misidentify which session they belong to.

Proposed Solution

Expose the current session UUID as CLAUDE_SESSION_ID in the environment of all hook commands and Bash tool subprocesses, alongside the existing session-level variables (CLAUDECODE, AI_AGENT, etc.).

Example value:
CLAUDE_SESSION_ID=9e031b73-2bfa-4d04-b1dd-46d56eaa2b13

This would allow hooks and skills to directly construct the JSONL path, write collision-free session-scoped temp files, and implement reliable per-session state without filesystem heuristics. This is an additive change — the UUID is already computed internally; the only change is surfacing it in the subprocess environment.

Alternative Solutions

  1. Read /proc/self/fd/2 (current Linux workaround)
    CC CLI writes each tool invocation's output to <tmp>/claude-<uid>/<slug>/<uuid>/tasks/<id>.output. On Linux, the current bash subprocess's fd/2 (stderr) points to this file, so readlink /proc/self/fd/2 extracts the UUID from the path. This works but: (a) depends on an undocumented internal directory structure that could silently break, (b) is Linux-only — fails on macOS and Windows, (c) requires every skill developer to independently discover this non-obvious trick. (Was only discovered after multiple turns after suggesting somehow making use of the PID.)

  2. Modification-time heuristic
    Find the most recently modified JSONL in the project directory. Unreliable when multiple sessions share a directory — race condition causes misidentification.

  3. Search JSONL for known message content
    Scan all session JSONLs for a recently-written unique message. Better than modification time but still not race-condition-free if two sessions write identical content simultaneously, and requires multiple file reads. One method that only works for a user invoked skill: Scan all session JSONLs for the skill's invocation text in user messages. If exactly one JSONL contains it, that session is unambiguously identified. If more than one contains it (two sessions invoking the same skill simultaneously), surface a warning asking the user to run only one at a time. Limitations: (a) only works when the user explicitly types the skill command — when Claude invokes the skill by inference, no user message containing the invocation exists, so the search finds zero matches; (b) requires reading all session JSONLs on every invocation; (c) still technically race-prone if two sessions invoke simultaneously, though the warning handles this gracefully rather than silently misidentifying.

None of these alternatives provide the reliability and portability of a first-class environment variable.

Priority

Low - Nice to have

Feature Category

Developer tools/SDK

Use Case Example

A /summarize skill writes a session summary file keyed to the current session's transcript. It needs to know which JSONL to read and what filename to write. With CLAUDE_SESSION_ID:

JSONL=~/.claude/projects/$PROJECT_SLUG/$CLAUDE_SESSION_ID.jsonl
SUMMARY=~/.claude/summaries/session-summary-$(date +%F)-${CLAUDE_SESSION_ID:0:8}.md

Without it, the skill must use a heuristic that fails when two sessions are active in the same directory simultaneously — exactly the scenario where session summaries are most useful (multiple parallel work streams).

Additional Context

The session UUID already appears as the sessionId field in the first entry of each JSONL file, confirming it is a stable, internally-assigned identity. Surfacing it as an environment variable requires no new concept — only exposure of an existing value through an additional channel.

Hook scripts currently have access to CLAUDECODE=1, AI_AGENT, CLAUDE_CODE_ENTRYPOINT, and ANTHROPIC_BASE_URL via the environment. CLAUDE_SESSION_ID fits naturally alongside these.

Metadata

Metadata

Assignees

No one assigned

    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