Skip to content

bug: CLAUDE_CODE_SESSION_ID absent from hook/Bash tool env, breaking hook→session lookup #526

@galexy

Description

@galexy

Split out from #519.

Symptom

CLAUDE_CODE_SESSION_ID — the env var that would let ox hooks deterministically identify the Claude Code session that triggered them — is absent from the Bash tool env in recent Claude Code versions.

From the report in #519:

Also: CLAUDE_CODE_SESSION_ID is absent from the Bash tool env, same as #258 observed.

This was also noted in #258, suggesting the gap has existed across multiple ox release cycles — but it may be worth revisiting whether a recent Claude Code version change (the report saw 2.1.112) changed the env injection behavior in a way that now matters more than it did before.

Why it matters

Several ox code paths want to correlate a hook invocation with a specific claude session:

  • Session marker lookupcmd/ox/agent_prime.go:180-189 keys idempotent-prime and session-state-reuse decisions on agentSessionID. When empty, the whole idempotent/marker code path is bypassed and other heuristics (ancestor PID match, sole-active-recording) take over.
  • Session capture-prior linking — the ox session verify design and the adapter protocol assume we can correlate raw.jsonl ↔ claude's session log. Without the env var, this has to fall back to time-window + project matching.
  • bug: session recording produces empty raw.jsonl (header only, 0 turns captured) on macOS / Claude Code 2.1.112 / ox 0.6.3 #519's state-store duality — if the hook-invoked recorder is keyed on CLAUDE_CODE_SESSION_ID but that var is never set, the recorder writes under one key and lookups by session ID never find it. This is one hypothesis for why PostToolUse hooks fire but never append to raw.jsonl.

What to investigate

  1. Confirm the env var is actually missing. Run Claude Code 2.1.x, add a hook that dumps its env to a temp file, verify CLAUDE_CODE_SESSION_ID is or isn't present.
  2. Check across Claude Code versions. If older versions emitted it, identify the version that changed.
  3. Check hook-type variation. Maybe SessionStart gets it (via stdin payload), but PostToolUse doesn't (only inherits process env).
  4. If Claude Code no longer emits it, decide how ox discovers the session ID. Options:
    • Parse it from hook stdin payload (which Claude Code does send, per existing adapter code).
    • Walk up the process tree and match against ~/.claude/projects/**/<session-id>.jsonl by PID/timestamp.
    • Have ox agent prime persist the discovered session ID to a marker file at session start and have subsequent hooks read from there.
  5. Follow up on bug: stale SAGEOX_AGENT_ID leaks across Claude Code sessions, breaking session recording #258 — same observation there; it may be the same underlying gap that's contributing to both.

Acceptance criteria

  • Root cause identified: is CLAUDE_CODE_SESSION_ID missing from all ox-invoked hooks in current Claude Code versions, or only some? Or is it present under a different name?
  • ox has a reliable way to get the claude session ID at hook time without relying on this env var, OR it's documented that ox requires a Claude Code version that still injects it.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions