Session ID Discovery
This is a standalone utility. You don’t need the rest of Hotline to use it.
The Answer: CLAUDE_CODE_SESSION_ID
Claude Code exports CLAUDE_CODE_SESSION_ID into every Bash tool call it spawns as of 2.1.132 (per the changelog; the environment variables reference documents it for hook commands and stdio MCP servers too — the Bash path is the one Hotline exercises and has live-verified). It matches the resumable session ID and the transcript filename, so a running agent reads its own identity straight out of the environment:
printf '%s\n' "$CLAUDE_CODE_SESSION_ID"
That’s what Hotline uses. Self-awareness of the session ID is what lets an agent reconnect to itself via --resume, key per-session state without collisions, or call another agent and keep track of the conversation — which is kind of the whole point of Hotline.
Don’t read the variable by hand, though: session-init.sh resolves identity across every harness Hotline supports, in one call, and validates what it finds:
| Rung | Source | caller_kind |
|---|---|---|
| 1 | $HOTLINE_CALLER_SESSION_ID — explicit override |
override |
| 2 | $CLAUDE_CODE_SESSION_ID, validated as a UUID |
native |
| 3 | $CODEX_THREAD_ID — Codex callers |
codex |
| 4 | Fingerprint discovery (below) | — |
bash /path/to/plugins/hotline/scripts/session-init.sh
# → {"status":"cached","session_id":"…","caller_kind":"native"}
bash /path/to/plugins/hotline/scripts/session-init.sh --expanded
# → also transcript_path, claude_pid, project_dir
The capability was requested in anthropics/claude-code#25642, anthropics/claude-code#13733 and anthropics/claude-code#17188 — all three now closed. See the environment variables reference for the variable itself.
The Compatibility Path: Fingerprinting
Before 2.1.132 there was no such variable. Hooks received the session ID in their stdin payload, but the running agent itself had no way to know its own identity. Hotline’s original mechanism solved that, and it’s still shipped and still the fallback whenever the native value is missing or malformed — a client older than 2.1.132, an environment that strips the variable, a wrapper that sanitizes the shell.
Two scripts, a two-step fingerprint method:
-
session-fingerprint.sh— Checks for a cached session ID. If found (exit 0), it writes the ID to stdout and you’re done. If not found (exit 1), it generates a unique fingerprint string and writes it to stderr. -
session-discover.sh— Takes that fingerprint string, greps the recent transcript files for it, and extracts the session ID from the matching filename. Caches the result so all future calls are instant.
The trick: the fingerprint string gets emitted into stderr during a Bash tool call, which means it appears in the conversation transcript. The discover script then finds which transcript file contains it. Transcript filename minus .jsonl = session ID. Boom.
Fingerprint Usage
The two steps must be separate tool calls — the fingerprint reaches the transcript only after the first call returns.
First call (two-step):
# Step 1: Check cache / generate fingerprint
bash /path/to/plugins/hotline/scripts/session-fingerprint.sh
# Exit 0 → stdout has your session ID. Done!
# Exit 1 → stderr has a fingerprint like SESSION_FINGERPRINT_<uuid>
# Step 2: Discover session from fingerprint (must be a separate tool call —
# the transcript needs to be written first)
bash /path/to/plugins/hotline/scripts/session-discover.sh "SESSION_FINGERPRINT_<uuid>"
# Exit 0 → stdout has your session ID, now cached for future calls
Subsequent calls (cached):
bash /path/to/plugins/hotline/scripts/session-fingerprint.sh
# Exit 0, stdout = session ID. Instant.
Exit Codes
| Script | Exit 0 | Exit 1 | Exit 2 |
|---|---|---|---|
session-fingerprint.sh |
Cache hit — session ID on stdout | Cache miss — fingerprint on stderr | No claude process in ancestry |
session-discover.sh |
Found — session ID on stdout | Fingerprint not found in transcripts | — |
Global PATH Access
For convenience, symlink the scripts so they’re available everywhere:
ln -s /path/to/plugins/hotline/scripts/session-fingerprint.sh ~/bin/session-fingerprint
ln -s /path/to/plugins/hotline/scripts/session-discover.sh ~/bin/session-discover
Now any hook or script can call session-fingerprint without knowing where the plugin lives.
How the Fingerprint Works Under the Hood
session-fingerprint.shwalks the process tree ($$→$PPID→ …) to find theclaudeparent PID- Checks
/tmp/claude-session-<pid>for a cached session ID - On cache miss, generates
SESSION_FINGERPRINT_<uuid>— a unique string that will appear in the transcript session-discover.shgreps the 5 most recent.jsonltranscript files for that fingerprint- The transcript filename IS the session ID (e.g.,
609dc906-c675-440a-b694-25f828519f3f.jsonl) - Caches the result to
/tmp/claude-session-<pid>so all future calls skip discovery
Two Claude sessions in the same directory get different claude parent PIDs, so their caches never collide.