Skip to content

Codex bridge: no teardown on session end → orphaned bridge/app-server/watch-once that also blocks relaunch #149

@fujibee

Description

@fujibee

Summary

When a Codex monitor session ends (the user closes the TUI), the Codex bridge stack is not torn down. The codex-bridge.js process, the shared codex app-server, and the armed watch-once.sh all keep running, and the run-dir artifacts (codex-bridge.<team>.<name>.pid/meta/log, codex-app-server.<hash>.pid/sock/log) are left behind. Worse than a leak: the orphaned bridge holds the identity pidfile, so relaunching the same project gets no fresh bridge — the single-instance guard sees the orphan as "alive" and skips launch, leaving the new session attached to nothing while the orphan keeps serving the dead thread.

Repro (observed 2026-06-17)

A codex-test monitored project, then close its Codex TUI:

  • TUI (codex --remote) and codex-bridge-launcher.sh: exit (tied to the TUI). ✅
  • codex-bridge.js, codex app-server --listen, watch-once.sh: still alive. 🔴
  • run artifacts: codex-bridge.agmsg.codex-test.{pid,meta,log} + codex-app-server.<hash>.{pid,sock,log} left behind.
  • bridge log ends at armed — no shutdown/teardown.
  • Project isolation holds: a separate monitored project (ag-dev-agent) was untouched.

Root cause

  • No Codex teardown on SessionEnd. session-end.sh only cleans up the claude-code watcher; it has no codex-bridge teardown.
  • SessionEnd may not fire at all on a hard TUI close (SIGKILL), same class as watch.sh: self-exit when owning CC session is no longer alive #67.
  • Mutual life support. The bridge keeps its WebSocket open to the app-server, so the app-server still has a client and never shuts down; the bridge re-arms watch-once on a loop and never self-exits. Neither dies.
  • No GC. Nothing reaps a stale codex-bridge.*.pid whose owning session is gone.

Consequence

Orphans persist until reboot or manual kill, AND they block relaunch: the orphaned bridge holds codex-bridge.<team>.<name>.pid, so the next session's SessionStart skips bridge launch (single-instance guard), and the reused app-server keeps the orphan attached to the now-dead thread. This is the "restart doesn't fix it" symptom.

Proposed directions

  1. SessionEnd teardown: session-end.sh (codex path) kills the project's bridge + launcher, optionally the app-server if it has no other clients, and removes the run artifacts.
  2. Bridge self-exit: codex-bridge.js detects its owning session/TUI is gone (app-server connection closed, or a liveness signal) and exits — robust to SessionEnd never firing. Mirrors watch.sh: self-exit when owning CC session is no longer alive #67.
  3. Orphan GC: SessionStart reaps stale codex-bridge.*.pid / codex-app-server.* whose pids are dead (and lets a stale-but-alive-orphan be replaced when the owning TUI is gone).

Related

#67 (watch.sh self-exit when owning session dead), #127 (orphaned watcher advances watermark), #41 (the Codex monitor bridge itself).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions