Files
orca/src/main/claude
Brennan Benson 0a853a5c0d fix(agent-hooks): stop backgrounded Claude sessions posting a stale pane key (STA-4769) (#15304)
* fix(agent-hooks): stop backgrounded Claude sessions posting a stale pane key (#9236)

A session started with `claude --bg` or `/background` runs in a worker under
the shared daemon, and that worker inherits the environment of whichever pane
first started the daemon — not the pane that dispatched it. ORCA_PANE_KEY there
names an unrelated pane, so the session's hooks overwrite that pane's sidebar
row, from any worktree.

It fails silently and successfully: the script re-sources the endpoint file, so
port and token self-heal and the POST lands, while the pane key has no refresh
path and stays wrong.

Measured on the wire against a throwaway listener: three sessions on one daemon,
and the one dispatched from pane B posted pane A's key and pane A's worktree on
SessionStart, UserPromptSubmit and Stop.

CLAUDE_JOB_DIR is set only in those workers — absent from all 68 live foreground
sessions on this machine — so it is the signal to decline. Declining is the only
option that exists: normalizeHookPayload rejects an absent paneKey outright and
AgentHookEventPayload.paneKey is a required string, so there is no "session with
no pane" representation to post instead. A backgrounded session genuinely has no
pane; attributing it to nothing is correct.

The Windows guard exits rather than jumping to the stdin drain: the drain parks
in more.com and a daemon worker is outside an Orca pane, which is exactly the
abandoned-stdin hang #11549 guards against.

* fix(agent-hooks): guard the Claude statusline against the same stale pane key

The statusline command IS invoked inside a backgrounded worker — measured, with
no client ever attached, and its ancestry terminates at the daemon rather than
at any pane:

  statusline pid=41746 <- claude bg-spare <- claude bg-pty-host <- claude daemon
  CLAUDE_JOB_DIR=/tmp/.../jobs/f1f9edd2

A second session dispatched from a different pane saw the first pane's
ORCA_PANE_KEY with its own correct session id, so this script is a live second
producer of the same misattribution the hook guard closes.

Windows uses exit /b 0 before stdin is owned, per the #11549 contract; POSIX
places the guard after capture, since exiting mid-write there surfaces as EPIPE
the agent can see (#8110).
2026-08-19 15:22:33 -07:00
..