Claude Code v2.1.138 ships CLAUDE_CODE_SESSION_ID as an environment variable in every Bash subprocess -- the same session_id your hooks already receive. That means hooks and Bash tool calls can finally cross-reference session context without routing through a shared file. Plus a screen renderer opt-out and three production-grade bug fixes.
I've been watching the Claude Code changelog closely since v2.1.133. The session ID env var landed in v2.1.138, released at 06:33 UTC on May 9, 2026, and it's the kind of quiet shipping that hooks-heavy teams feel immediately.
What shipped in Claude Code v2.1.138?
Claude Code v2.1.138 adds CLAUDE_CODE_SESSION_ID to every Bash subprocess environment, a CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 opt-out for native terminal scrollback, and a paste progress hint. Bug fixes cover SIGINT graceful shutdown, --resume emoji crashes, plan-mode permission handling, IDE mouse wheel speed, and a 10GB+ MCP stdio memory leak.
The full release landed at 06:33 UTC on May 9, 2026, per the GitHub releases page and the official changelog. Anthropic is shipping Claude Code releases daily at this point -- v2.1.133 shipped on May 8. Staying current matters for production teams because features and fixes accumulate fast.
The v2.1.138 changeset, distilled:
- New: CLAUDE_CODE_SESSION_ID injected into every Bash subprocess environment
- New: CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 for native terminal scrollback
- New: "Pasting..." footer hint during Ctrl+V image paste reads
- Fix: SIGINT graceful shutdown -- terminal modes restored, --resume hint printed
- Fix: --resume emoji-surrogate crash
- Fix: --permission-mode ignored when resuming plan-mode sessions
- Fix: Mouse wheel scrolling speed in Cursor and VS Code 1.92-1.104
- Fix: Unbounded memory growth (10GB+) from MCP stdio servers writing non-protocol stdout
- Fix: Unauthorized MCP connectors show "needs auth" instead of "failed"
What does CLAUDE_CODE_SESSION_ID actually unlock?
CLAUDE_CODE_SESSION_ID in Bash subprocesses closes a gap that's been annoying hooks-heavy builders since the hooks system shipped. Before v2.1.138, hooks received session_id in their JSON stdin payload but the Bash tool itself had no programmatic way to read it. Now every subprocess gets it automatically -- enabling session-scoped logging, cache directories, and multi-agent coordination without file-based workarounds.
Before this fix, I was routing around the gap by having hooks write the session ID to a temp file at startup and reading it back in Bash scripts. It worked, but it introduced race conditions when two hooks fired close together and required manual temp file cleanup. The env var approach eliminates all of that.
Here's what this unlocks in practice:
Session-scoped audit logs. A PostToolUse hook can write to ~/.claude/logs/$CLAUDE_CODE_SESSION_ID.log without any coordination overhead. Any Bash script invoked later in the same session can append to the same file. No shared state protocol needed between hook and script.
Cache directories by session. If you build scripts that cache intermediate results -- expensive API calls, parsed ASTs, file indexes -- scope the cache directory to $CLAUDE_CODE_SESSION_ID. The cache stays isolated per session and you can clean up by session ID when the session ends, with no risk of cross-session cache poisoning.
Multi-agent coordination. Teams running parallel Claude Code sessions -- CI pipelines, orchestrated agent swarms -- can route subprocess output back to the correct session context without guessing or building external session registries. Each agent's subprocesses know which session they belong to.
The hooks reference documents 12 lifecycle events Claude Code exposes: PreToolUse, PostToolUse, Notification, Stop, SubagentStop, SessionStart, PreCompact, and more. Each hook receives session_id in its JSON stdin context. Now every Bash subprocess spawned within those hooks -- or directly by Claude Code -- also carries the session identifier.
Get the AI Agent Briefing
One email per week. The best AI agent news, tutorials, and tools -- written by someone who actually builds with them.
Subscribe Free
Who should enable CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1?
Claude Code's default renderer uses the terminal's alternate screen -- the same mode used by vim, less, and htop. This gives you a clean full-screen UI but loses scrollback history when you exit. Set CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 and Claude Code stays in the normal terminal buffer, so everything scrolls and persists in your terminal emulator's native history.
Three cases where this is the right call:
Headless CI/CD. Running Claude Code in a GitHub Actions runner, Jenkins agent, or any automated environment? Alternate screen mode produces ANSI escape sequences that log pipelines interpret as noise. Native scrollback mode gives you clean stdout that log parsers, artifact viewers, and alert systems handle correctly.
Shared tmux or screen sessions. If you pair program over tmux or share terminal sessions via screen, alternate screen mode means your collaborator loses context when Claude Code exits. Native scrollback keeps the full conversation visible in the scrollback buffer.
Log capture pipelines. Piping claude output through tee or redirecting stdout to a file? Alternate screen escape sequences corrupt the log file. Native scrollback mode gives you clean, parseable output.
Set it once in your shell profile for permanent effect:
export CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1
Or prefix specific runs without changing the global config:
CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 claude
The trade-off: Claude Code's interactive diff viewer and multi-panel displays won't render correctly without the alternate screen buffer. If you use those features in interactive development sessions, keep the default for those contexts and use the env var prefix for CI runs.
The bug fixes that matter for production teams
Three fixes in v2.1.138 address real production pain: SIGINT graceful shutdown restores terminal state on any external interrupt, the MCP stdio memory buffer is now capped after hitting 10GB+ in long sessions, and MCP auth status shows "needs auth" instead of "failed" so you debug in the right direction from the start.
SIGINT graceful shutdown. Before this fix, an external interrupt -- an IDE stop button, a kill -INT from another process, a Kubernetes pod termination signal -- could leave the terminal in raw mode. You'd need to type reset or open a new terminal session to recover. The fix runs the full shutdown sequence on SIGINT: terminal modes are restored and the --resume hint is printed. Source: GitHub issue #29096 and the May 2026 Releasebot digest.
MCP stdio memory leak (the 10GB+ fix). MCP servers using stdio transport communicate through subprocess stdin/stdout. The problem: if an MCP server writes anything to stdout that isn't valid MCP JSON-RPC -- a startup banner, debug log output, a progress message -- Claude Code was accumulating it in an unbounded buffer. In long sessions with verbose servers, this buffer grew past 10GB before the process crashed or was killed by the OS. This is especially common with Python MCP servers where developers don't explicitly suppress stdout logging. The fix caps the non-protocol buffer. If you run any MCP servers that might write diagnostic output to stdout, update to v2.1.138 immediately.
MCP auth display fix. Unauthorized MCP connectors -- OAuth-gated services like Jira, Linear, Notion, Azure DevOps, or any MCP server that requires an auth token -- previously showed "failed" in the /mcp status view. That looks identical to a server error. The correct message is "needs auth," which tells you exactly what to do: run the authentication flow. This single word change shifts the debug path from "is my MCP server down?" to "do I need to authenticate?" and eliminates minutes of misdirected troubleshooting per incident.
What's still missing after v2.1.138?
CLAUDE_CODE_SESSION_ID solves cross-process session correlation but doesn't add session enumeration or programmatic metadata querying. You can read the current session ID from the env var, but there's no API to list active sessions, inspect their state, or route output to a specific session from outside Claude Code.
A few open gaps worth knowing:
No session listing API. You can read $CLAUDE_CODE_SESSION_ID from within a session, but there's no way to enumerate all running sessions from an external script. Teams running multiple parallel Claude Code agents in CI still need an external registry or shared state file for cross-session coordination at the orchestrator level.
CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN has no auto-detection. A hook or script that wants to format output differently based on the current render mode has to check the env var itself. There's no Claude Code API call to query whether alternate screen is active.
The MCP memory fix is stdio-only. HTTP-transport MCP servers communicate over the network, not through subprocess stdout, so this fix doesn't apply to remote MCP servers. Remote MCP server buffering issues would require separate fixes in a different part of the stack.
None of these are blockers for most production builds. The session ID env var specifically feels like infrastructure -- the kind of primitive that unlocks a category of tooling. I expect hook libraries and agent frameworks to start using $CLAUDE_CODE_SESSION_ID as a standard correlation key within weeks.
FAQ
How do I access CLAUDE_CODE_SESSION_ID in a hook script?
CLAUDE_CODE_SESSION_ID is a standard environment variable available in every Bash subprocess spawned by Claude Code after v2.1.138. In shell scripts, read it with $CLAUDE_CODE_SESSION_ID. In Python scripts, use os.environ['CLAUDE_CODE_SESSION_ID']. Hooks also receive session_id in their JSON stdin payload -- the env var gives the same value to scripts that run within the session but aren't hooks themselves.
What breaks if I set CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1?
The interactive diff viewer and multi-panel displays won't render correctly without the alternate screen buffer -- they rely on cursor-addressed output to position content on screen. The core conversation flow, tool use, and text output all work fine in native scrollback mode. For CI, log capture, and pair programming over tmux, disabling alternate screen is the right trade-off. For interactive local development where you use the diff viewer regularly, keep the default.
Does the MCP memory leak fix apply to all MCP server types?
The fix applies only to stdio transport MCP servers -- local servers that run as subprocesses communicating via stdin/stdout. HTTP-transport remote MCP servers are unaffected by this fix. If your Python or Node MCP server writes startup banners, debug logs, or progress messages to stdout instead of stderr, this fix caps that buffer before it exhausts memory. The safest practice regardless: redirect all MCP server logging to stderr explicitly in your server code.
How do I update Claude Code to v2.1.138?
Run npm update -g @anthropic-ai/claude-code if you installed via npm. Verify with claude --version. For CI environments that pin the version in package.json, update the pin to 2.1.138 or later and run a fresh install. The GitHub releases page lists all versions with full changelogs so you can audit what changed before updating pinned installs.
Get the AI Agent Briefing
One email per week. The best AI agent news, tutorials, and tools -- written by someone who actually builds with them.
Subscribe Free