Skip to content

Shelling out to claude from inside a Claude Code session silently breaks session registration (inherited CLAUDE_CODE_* env) #680

Description

@tu11aa

Surfaced by the #667 live smoke (merged in docs/specs/2026-08-13-agent-control-channel-design.md, section "Smoke Test: claude approve/deny of a HELD peer message (2026-08-17)").

Symptom

A claude process launched from a shell that is itself running inside a Claude Code session comes up believing it is a child of the launching session. Observed on Claude Code 2.1.233:

  • it registers its .sock and inbox .key under ~/.claude/sessions/
  • but it never writes its <pid>.json registry entry
  • its transcript banner reads: Transcript saving is off — inherited CLAUDE_CODE_CHILD_SESSION marker

Cause

nohup claude ... & (or any spawn) inherits the parent session's environment, including:

CLAUDE_CODE_CHILD_SESSION, CLAUDE_CODE_MESSAGING_SOCKET, CLAUDE_CODE_MESSAGING_TOKEN, CLAUDE_CODE_SESSION_ID, CLAUDE_PID

The child sees the child-session marker and skips its own registration.

Fix that worked

Spawn with a sanitized environment:

env -i HOME="$HOME" PATH="$PATH" TERM="$TERM" CLAUDE_CODE_HARBOR_KITE=1 claude ...

After which registration behaved normally.

Why this matters for squadrant

The daemon itself is not directly exposedsquadrantd spawns crews from its own Node process, not from inside a Claude Code session. Verified, not assumed.

But any path that shells out to claude from within another Claude Code session hits this silently:

  • a crew spawning a crew
  • a hook that invokes claude
  • a plugin or script run from a captain/crew pane
  • anything a user runs by hand from inside a session

The failure is silent: no error, the session appears to work, but it is invisible to ~/.claude/sessions/ — which is exactly the registry #667 slice 1's ClaudePeerRegistrySource reads for liveness. An unregistered session is permanently unknown to that source.

Suggested handling

  • Audit any code path that launches claude for inherited CLAUDE_CODE_* and strip it explicitly.
  • Consider a shared spawn helper that always clears the marker set, so this cannot be reintroduced per-call-site.
  • Document the trap for anyone writing tooling around claude.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions