Summary
While debugging "restart didn't auto-launch the Codex bridge" (aggie-co, real machine, 2026-06-17), two observations contradict the documented launcher/request-file design and suggest that machinery may be redundant:
-
The SessionStart hook fires on the user's FIRST turn, not at TUI launch. A sentinel-gated trace in session-start.sh's codex block stayed empty after a fresh codex launch and only logged fired the instant the user typed a message. (This is the real cause of the "I restarted and nothing happened" reports — there is a launch→first-turn window with no bridge.)
-
When the hook fires, AGMSG_CODEX_BRIDGE_LAUNCHER is NOT inherited from codex-monitor.sh (trace shows launcher=0). So the hook never takes the request-file path — it takes the direct-launch fallback (nohup codex-bridge.js … from inside the hook), and that path works: socket connect + thread resume + turn delivery all succeed. No request file is ever written; the launcher process (codex-bridge-launcher.sh) runs but sits idle.
Why this contradicts the design
The launcher + request-file rendezvous exists specifically to dodge an EPERM that was reproduced on this same machine: a direct Unix-socket connect from the sandboxed hook returned EPERM, so the hook was made to only write a request file and an out-of-sandbox launcher owned the connection. (Documented as a hard dead-end: "launching the bridge directly from the hook → socket EPERM".)
Yet the direct path connected fine here. Most likely reconciliation: the original EPERM came from an in-process synchronous connect inside the hook, whereas the current code nohups a detached child, which escapes the sandbox and connects without EPERM. If that holds, the launcher/request-file layer is dead weight.
Open questions / what to verify
- Is
launcher=0 (env not propagated from codex-monitor.sh to the hook) expected Codex behavior? If so, the request-file path can never be triggered by the hook as written — meaning it has never actually run in the normal flow.
- Does the detached-child direct launch reliably escape the sandbox across Codex versions, or is the EPERM intermittent/version-specific? Controlled test: force the launcher path off, restart several times, watch for any EPERM in the bridge log.
- If direct launch is reliable: remove
codex-bridge-launcher.sh + the request-file rendezvous + the AGMSG_CODEX_BRIDGE_LAUNCHER plumbing, and have the hook launch the detached bridge directly. Large simplification.
Do NOT rip it out yet
The launcher guards a reproduced EPERM; one contrary observation isn't enough to remove a safety net. Verify the EPERM premise first.
Related
#41 (Codex monitor bridge), #149 (no teardown on session end), #150 (one identity per project), #151 (enable-needs-restart). The first-turn-fire finding also means the user-facing docs should say "the bridge starts after your first message," which is being updated separately.
Summary
While debugging "restart didn't auto-launch the Codex bridge" (aggie-co, real machine, 2026-06-17), two observations contradict the documented launcher/request-file design and suggest that machinery may be redundant:
The SessionStart hook fires on the user's FIRST turn, not at TUI launch. A sentinel-gated trace in
session-start.sh's codex block stayed empty after a freshcodexlaunch and only loggedfiredthe instant the user typed a message. (This is the real cause of the "I restarted and nothing happened" reports — there is a launch→first-turn window with no bridge.)When the hook fires,
AGMSG_CODEX_BRIDGE_LAUNCHERis NOT inherited fromcodex-monitor.sh(trace showslauncher=0). So the hook never takes the request-file path — it takes the direct-launch fallback (nohup codex-bridge.js …from inside the hook), and that path works: socket connect + thread resume + turn delivery all succeed. No request file is ever written; the launcher process (codex-bridge-launcher.sh) runs but sits idle.Why this contradicts the design
The launcher + request-file rendezvous exists specifically to dodge an EPERM that was reproduced on this same machine: a direct Unix-socket connect from the sandboxed hook returned EPERM, so the hook was made to only write a request file and an out-of-sandbox launcher owned the connection. (Documented as a hard dead-end: "launching the bridge directly from the hook → socket EPERM".)
Yet the direct path connected fine here. Most likely reconciliation: the original EPERM came from an in-process synchronous connect inside the hook, whereas the current code
nohups a detached child, which escapes the sandbox and connects without EPERM. If that holds, the launcher/request-file layer is dead weight.Open questions / what to verify
launcher=0(env not propagated fromcodex-monitor.shto the hook) expected Codex behavior? If so, the request-file path can never be triggered by the hook as written — meaning it has never actually run in the normal flow.codex-bridge-launcher.sh+ the request-file rendezvous + theAGMSG_CODEX_BRIDGE_LAUNCHERplumbing, and have the hook launch the detached bridge directly. Large simplification.Do NOT rip it out yet
The launcher guards a reproduced EPERM; one contrary observation isn't enough to remove a safety net. Verify the EPERM premise first.
Related
#41 (Codex monitor bridge), #149 (no teardown on session end), #150 (one identity per project), #151 (enable-needs-restart). The first-turn-fire finding also means the user-facing docs should say "the bridge starts after your first message," which is being updated separately.