Repository navigation
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/<slug>/<uuid>.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.jsonrecords atranscriptPaththat doesn't exist on diskclaude -cin 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
- Run
claudein any directory (call this session A). - 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=<A's id>,CLAUDE_CODE_EXECPATH=<path>,CLAUDE_CODE_ENTRYPOINT=clito any child. orca-terminal-daemonforks with all of those inherited.
- Session A's process exports
- In Orca, open a new terminal tab in a totally unrelated project directory, and let its startup command launch
claudein that cwd. - Chat with claude — messages exchange normally, tools work, hooks fire.
- Close the tab or run
claude -cin the same cwd from a plain terminal → "No conversation found to continue". - Inspect
~/.claude/projects/<slug-of-cwd>/→ only an emptymemory/subdir, no<uuid>.jsonl. - Inspect
<orca-user-data>/agent-hooks/last-status.json→ the entry for that worktree hasproviderSession.transcriptPathpointing 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:
// 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/<slug>/<uuid>.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 constAnd extend the existing scrub loop inside buildPtyHostEnv (right after the current AGENT_HOOK_RUNTIME_ENV_KEYS loop around L941):
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 frommain@64181fdd4) on Windows 11 - Claude Code
2.1.212, Windows binary atC:\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.
Activity
lishixiang0705 commentedon Jul 30, 2026
Confirming this reproduces on macOS too (Orca
1.4.156, Claude Code CLI2.1.220).Environment observed on a
claude-spawned Bash subprocess running inside an Orca-managed terminal pane on this machine — all five keys from #10188's denylist are present:Also matches the "sticky across auto-updates" behavior noted in #9961's writeup: this machine currently has three different
orca-terminal-daemonprotocol generations alive at the same time (v23, v26, v28), consistent with a contaminated launch surviving multiple app auto-updates without a full daemon restart.#9961 (merged) only strips
CLAUDE_CODE_CHILD_SESSION/CLAUDE_CODE_SESSION_ID/CLAUDE_CODE_BRIDGE_SESSION_ID, soCLAUDECODEandCLAUDE_CODE_EXECPATHare still leaking through on this build. Would be good to get #10188 merged to close the remaining gap.nwparker commentedon Aug 23, 2026
Closing because child-session stamps are stripped at spawn (PR #9961).
Disagree? Please respond! I will re-visit this ticket in 5 days. If you respond, I will re-open it 🙏.
[-]Terminal PTY inherits CLAUDE_CODE_CHILD_SESSION from an ancestor claude process; child claude tabs silently skip transcript persistence[/-][+][Bug]: CLAUDE_CODE_CHILD_SESSION stamp variants still leak into transcripts (residual after #9961)[/+]nwparker commentedon Aug 25, 2026
Re-opening — core fix landed in #9961 but residual stamp-key coverage is still open in PR #10188.
fix(terminal): strip inherited CLAUDECODE, EXECPATH, and ENTRYPOINT m…