stablyai / stablyai/orca

[Bug]: CLAUDE_CODE_CHILD_SESSION stamp variants still leak into transcripts (residual after #9961)

Open
#9,155 3 comments 0 reactions 1 assignee Claimed by @OrcaWin View on GitHub
bug
Dominant language
TypeScript
Stars
69.7k
Forks
4.5k
Avg merge
15h 28m
Merged PRs (30d)
471

Description

## Summary

When the `orca-terminal-daemon` process inherits `CLAUDE_CODE_CHILD_SESSION=1` (plus the sibling `CLAUDECODE`, `CLAUDE_CODE_SESSION_ID`, `CLAUDE_CODE_EXECPATH`, `CLAUDE_CODE_ENTRYPOINT` env vars) from an ancestor `claude` CLI process, every PTY the daemon spawns keeps propagating those vars to the child `claude` CLI process running inside the tab. The child `claude` treats itself as a "child session" of a long-dead parent and silently **skips writing the primary transcript** at `~/.claude/projects//.jsonl`, while still reporting the (never-created) path to Orca via the agent hook. As a result:

- The Orca UI shows the tab is fine (terminal replay works from `terminal-history/output.log`)
- `agent-hooks/last-status.json` records a `transcriptPath` that **doesn't exist on disk**
- `claude -c` in the same directory says "No conversation found to continue" — because none was ever written
- Data loss is silent and permanent (the tab's conversation cannot be resumed after close)

Once the daemon is contaminated, **every** new tab in that daemon lifetime is affected. The contamination is sticky and only clears on a full daemon restart.

## Repro

1. Run `claude` in any directory (call this session A).
2. From inside session A's Bash tool (or any child shell of it), start Orca (e.g. `orca`, or a shortcut launched with the polluted env).
- Session A's process exports `CLAUDECODE=1`, `CLAUDE_CODE_CHILD_SESSION=1`, `CLAUDE_CODE_SESSION_ID=`, `CLAUDE_CODE_EXECPATH=`, `CLAUDE_CODE_ENTRYPOINT=cli` to any child.
- `orca-terminal-daemon` forks with all of those inherited.
3. In Orca, open a new terminal tab in a totally unrelated project directory, and let its startup command launch `claude` in that cwd.
4. Chat with claude — messages exchange normally, tools work, hooks fire.
5. Close the tab or run `claude -c` in the same cwd from a plain terminal → "No conversation found to continue".
6. Inspect `~/.claude/projects//` → only an empty `memory/` subdir, no `.jsonl`.
7. Inspect `/agent-hooks/last-status.json` → the entry for that worktree has `providerSession.transcriptPath` pointing to a file that does not exist.

The bug reproduces reliably as long as the daemon was started from an env carrying `CLAUDE_CODE_CHILD_SESSION=1`. Killing the daemon (`orca-terminal-daemon.exe` on Windows / matching process on POSIX) and reopening Orca from a clean shell temporarily fixes it — until the next time it is launched from within a `claude` session.

## Evidence

Environment diff between two live `claude.exe` processes on the same machine (read via `psutil.Process(pid).environ()`):

**pid 22380 — claude launched inside an Orca tab (no jsonl written)**
```
CLAUDECODE=1
CLAUDE_CODE_CHILD_SESSION=1
CLAUDE_CODE_SESSION_ID=08a1a595-d1ec-4142-9680-0eec5fc15e17
CLAUDE_CODE_EXECPATH=C:\Users\Lee\.local\bin\claude.exe
CLAUDE_CODE_ENTRYPOINT=cli
ORCA_WORKTREE_ID=…::D:/claude/xianyu-rpc/r0rpc
```

**pid 22468 — claude launched from a plain PowerShell in the same session (jsonl 276KB, works fine)**
```
(none of the CLAUDE_CODE_* vars above are present)
```

Process chain for the broken tab: `claude(22380) ← powershell(4400) ← orca-terminal-daemon.exe(16460)`. The daemon's own env already contains the polluted vars, so **the leak originates at daemon startup**, not at PTY spawn time.

The "parent" session `08a1a595-…` referenced in `CLAUDE_CODE_SESSION_ID` lives at `~/.claude/projects/C--Users-Lee/08a1a595-….jsonl`, mtime frozen at a date long before the current Orca session — confirming the child is chained to a dead session, not a live one.

Orca's hook status confirms the child claude *reported* a transcript path that was never written:
```
"worktreeId": "…::D:/claude/xianyu-rpc/r0rpc",
"providerSession": {
"id": "ae5def5f-3bdd-4138-8644-7d9411d9fca3",
"transcriptPath": "C:\\Users\\Lee\\.claude\\projects\\D--claude-xianyu-rpc-r0rpc\\ae5def5f-….jsonl"
}
```
`ls` on that path → `No such file or directory`. `hookEventName` on the same entry is `PostToolUse` (so conversation definitely happened).

## Root Cause

`src/main/ipc/pty.ts` scrubs some inherited env keys before spawning a PTY (see `AGENT_HOOK_RUNTIME_ENV_KEYS` around L211 and its use in `buildPtyHostEnv` at L941), but the Claude CLI's own contract env — the `CLAUDE_CODE_*` / `CLAUDECODE` set — is never cleaned. Searching the whole codebase for those keys turns up **only a test file** (`src/main/runtime/claude-agent-teams-service.test.ts`), i.e. they are never actively deleted from `spawnEnv` on any code path.

## Suggested Fix

Add a new constant next to `AGENT_HOOK_RUNTIME_ENV_KEYS` in `src/main/ipc/pty.ts`:

```ts
// Why: when Orca's daemon is launched from inside a `claude` CLI session,
// it inherits these Claude-internal envs and then leaks them into every
// PTY it spawns. A child `claude` seeing CLAUDE_CODE_CHILD_SESSION=1
// treats itself as a subordinate session and does not persist its own
// transcript to ~/.claude/projects//.jsonl, silently making
// the conversation unresumable. Strip these before every PTY spawn so
// each tab's claude sees a clean session context.
const CLAUDE_CODE_INHERITED_ENV_KEYS = [
'CLAUDECODE',
'CLAUDE_CODE_CHILD_SESSION',
'CLAUDE_CODE_SESSION_ID',
'CLAUDE_CODE_EXECPATH',
'CLAUDE_CODE_ENTRYPOINT'
] as const
```

And extend the existing scrub loop inside `buildPtyHostEnv` (right after the current `AGENT_HOOK_RUNTIME_ENV_KEYS` loop around L941):

```ts
for (const key of CLAUDE_CODE_INHERITED_ENV_KEYS) {
delete baseEnv[key]
}
```

Corresponding test in `src/main/ipc/pty.test.ts`: assert that a `baseEnv` seeded with all five `CLAUDE_CODE_*` keys comes back with them removed after `buildPtyHostEnv`.

This matches the shape of the existing hook-env scrubbing pattern and is scoped to the exact daemon-inherited env that causes the bug. It also permanently prevents recurrence — even if a user relaunches Orca from a `claude` session tomorrow, the daemon-level pollution can no longer leak into PTYs.

## Environment

- Orca `1.4.144-rc.1` (built from `main` @ `64181fdd4`) on Windows 11
- Claude Code `2.1.212`, Windows binary at `C:\Users\Lee\.local\bin\claude.exe`
- Node 22.16, pnpm 10.24.0
- Only tested on Windows; the same env-inheritance mechanism exists on macOS/Linux, so I expect the bug to reproduce there too, but I have not verified.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.