Summary
A Codex seat on herdr can resolve its own pane as a different seat's pane. where.sh and fix.sh then act on the wrong pane. Pokes and placement records can land on another agent.
Cause (measured)
codex-monitor.sh starts one app-server per project and reuses it for every later Codex seat in that project (port file run/codex-app-server.<sha1>.port). Under codex --remote, an agent's shell commands run inside the app-server process, not in the TUI client (already noted in _app-server.sh). The app-server inherited HERDR_PANE_ID / HERDR_SOCKET_PATH from the pane that launched it first.
The herdr driver's terminal_detect trusts the inherited HERDR_PANE_ID. So every Codex seat that attached to a reused app-server reports the first seat's pane as its own.
Observed on one herdr session with three Codex seats in the same project:
| process |
listens / connects |
inherited HERDR_PANE_ID |
| app-server |
listens 127.0.0.1:52700 |
w1:p3 (seat A's pane) |
| seat A TUI |
--remote ws://127.0.0.1:52700 |
w1:p3 |
| seat B TUI |
--remote ws://127.0.0.1:52700 |
w1:pD |
| seat C TUI |
--remote ws://127.0.0.1:52700 |
w1:pE |
In seat B, peek of seat B showed seat B's own conversation, while where.sh returned w1:p3 (seat A). fix.sh run from seat B's tool calls returned undetermined reason=not_found.
It is not specific to running several herdr sessions. The same reuse across two herdr sessions would also carry the wrong socket, not only the wrong pane.
The earlier measurement that justified trusting HERDR_PANE_ID (every process carrying it sat in its own pane) did not include a Codex seat attached to another seat's app-server.
Impact
where / self-naming / placement records for later Codex seats name another seat's pane.
- Actions derived from that location (
poke, arrange, fix) target another agent. In the observed run, a stop command was poked into the other seat.
Direction (to decide)
- Fail closed now: when the caller runs inside a shared Codex app-server, do not trust the inherited
HERDR_PANE_ID. Report the pane as unresolved instead of naming another seat's pane.
- Root fix: give each Codex seat its own app-server, or carry the TUI's pane into the execution context. Per-project reuse is what makes the inherited environment wrong.
Summary
A Codex seat on herdr can resolve its own pane as a different seat's pane.
where.shandfix.shthen act on the wrong pane. Pokes and placement records can land on another agent.Cause (measured)
codex-monitor.shstarts one app-server per project and reuses it for every later Codex seat in that project (port filerun/codex-app-server.<sha1>.port). Undercodex --remote, an agent's shell commands run inside the app-server process, not in the TUI client (already noted in_app-server.sh). The app-server inheritedHERDR_PANE_ID/HERDR_SOCKET_PATHfrom the pane that launched it first.The herdr driver's
terminal_detecttrusts the inheritedHERDR_PANE_ID. So every Codex seat that attached to a reused app-server reports the first seat's pane as its own.Observed on one herdr session with three Codex seats in the same project:
HERDR_PANE_ID127.0.0.1:52700w1:p3(seat A's pane)--remote ws://127.0.0.1:52700w1:p3--remote ws://127.0.0.1:52700w1:pD--remote ws://127.0.0.1:52700w1:pEIn seat B,
peekof seat B showed seat B's own conversation, whilewhere.shreturnedw1:p3(seat A).fix.shrun from seat B's tool calls returnedundetermined reason=not_found.It is not specific to running several herdr sessions. The same reuse across two herdr sessions would also carry the wrong socket, not only the wrong pane.
The earlier measurement that justified trusting
HERDR_PANE_ID(every process carrying it sat in its own pane) did not include a Codex seat attached to another seat's app-server.Impact
where/ self-naming / placement records for later Codex seats name another seat's pane.poke,arrange,fix) target another agent. In the observed run, a stop command was poked into the other seat.Direction (to decide)
HERDR_PANE_ID. Report the pane as unresolved instead of naming another seat's pane.