You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
agmsg version: observed on v1.1.13 (v1.1.13-5-g3a38479); the code path is unchanged on current main (1a12fd6, v1.2.2+19) Host: Linux 6.6 (WSL2), bash 5 Codex: codex-cli 0.147.0 (npm global), interactive TUI through the agmsg shim, delivery mode monitor Host agents: Claude Code (leader) + Codex peers in the same project
Summary
In monitor mode, once a Codex role has a recorded seat (the role→thread record actas / codex-record-session.sh writes), relaunching a plain codex in that project gives a session that never receives anything visibly: the bridge is alive, delivery status is green, inbound messages are consumed and marked read — but they land in the recorded thread, and the TUI in front of the operator is a different, fresh thread. The operator sees nothing; the sender sees "read".
This is #350's symptom on a different road. #350 was the bridge binding to loaded and catching the wrong thread; #353 fixed that by binding it to the role's recorded thread. The half that is still open is the TUI side: nothing makes the TUI open that same thread, and since #579/#583 nothing can move the seat to the thread the TUI did open.
Why it cannot recover on its own
Three pieces, each correct alone:
codex-monitor.sh launches a plain codex as codex --remote <url> — a fresh thread, every time (codex-monitor.sh:247).
So: seat = T1. Operator relaunches codex → TUI on fresh T2. Bridge resumes T1 and delivers there. First turn on T2 → SessionStart → codex-record-session.sh sees a seat and exits without writing. actas in T2 → same. The seat stays T1 forever; every later launch repeats this. The only way out is to know T1's id and type codex resume <T1> by hand — and #353's closing note ("freshness holds because a role re-runs actas on resume, which rewrites the record") no longer holds after #579, which is presumably why this was not caught then.
Evidence
run/codex-bridge.dqx-buttle.minori.log (bridge for a seated role, plain relaunches over several days): the bridge starts turns on the recorded thread while the operator's TUI is elsewhere —
codex-bridge: wakeup 1 for dqx-buttle/minori
codex-bridge: started turn on thread 019fea06-1d47-7383-8a83-421f97662422
codex-bridge: no turn activity within 60s; assuming the turn ended and resuming
codex-bridge: armed dqx-buttle/minori
codex-bridge: wakeup 2 for dqx-buttle/minori
codex-bridge: started turn on thread 019fea06-1d47-7383-8a83-421f97662422
run/role-session.dqx-buttle__minori holds session=019fea06-… (recorded 2026-08-10); ~/.codex/sessions/2026/08/10/rollout-…-019fea06-….jsonl exists. Every codex launched afterwards opened a different thread, and the turns above were not visible in any of them.
What would fix it
Make the TUI make the same choice the launcher makes: a plain monitored codex opens the role's recorded thread — codex resume --remote <url> <thread> — when that is unambiguous (one Codex role registered for the project, seat in this project, rollout still on disk, via the agmsg_role_resume_uuid gate spawn/resurrect already use); otherwise fresh, saying why. An explicit codex resume … stays as given.
And once TUI and bridge share one thread, the bridge should attach to the thread the TUI loaded (poll thread/loaded/list for it) rather than thread/resume it itself: turn/start needs only the id (the no-rollout fallback has relied on that since #276), and a bridge-side resume is the already has an active writer collision of #906 against Codex Desktop.
I have this running locally since 2026-08-10 (logs show TUI loaded thread …; attaching without a competing resume followed by delivered wakes) and will open a PR.
Related: #350 / #353 (the bridge half of this), #579 (why the seat cannot move), #816 (the missing-seat case; this issue is the present-seat case), #365 ("rebind the saved role on SessionStart" asks for the same outcome for Codex Desktop), #906 (active-writer collision).
agmsg version: observed on v1.1.13 (
v1.1.13-5-g3a38479); the code path is unchanged on currentmain(1a12fd6, v1.2.2+19)Host: Linux 6.6 (WSL2), bash 5
Codex: codex-cli 0.147.0 (npm global), interactive TUI through the agmsg shim, delivery mode
monitorHost agents: Claude Code (leader) + Codex peers in the same project
Summary
In monitor mode, once a Codex role has a recorded seat (the role→thread record
actas/codex-record-session.shwrites), relaunching a plaincodexin that project gives a session that never receives anything visibly: the bridge is alive,delivery statusis green, inbound messages are consumed and marked read — but they land in the recorded thread, and the TUI in front of the operator is a different, fresh thread. The operator sees nothing; the sender sees "read".This is #350's symptom on a different road. #350 was the bridge binding to
loadedand catching the wrong thread; #353 fixed that by binding it to the role's recorded thread. The half that is still open is the TUI side: nothing makes the TUI open that same thread, and since #579/#583 nothing can move the seat to the thread the TUI did open.Why it cannot recover on its own
Three pieces, each correct alone:
codex-monitor.shlaunches a plaincodexascodex --remote <url>— a fresh thread, every time (codex-monitor.sh:247).codex-bridge-launcher.shbinds the bridge to the role's recorded thread and nothing else ("the role-session record is the sole thread authority", Codex monitor: only one identity per project — actas / multiple codex roles disable the bridge #150 phase 2 / Codex bridge reuses a live bridge attached to the wrong thread #350,codex-bridge-launcher.sh:459-472).codex-record-session.shrefuses to let any inference replace a seat that already exists (codex-record-session.sh:75-87, codex monitor never arms when a project has more than one past session: the role-session seat it requires can no longer be written #579): only an explicitCODEX_THREAD_IDmay, and codex 0.141+ does not export it to hooks (Codex monitor bridge never engages on recent codex CLI (--remote is ws-only; SessionStart hook can't resolve the thread id) #170).So: seat = T1. Operator relaunches
codex→ TUI on fresh T2. Bridge resumes T1 and delivers there. First turn on T2 → SessionStart →codex-record-session.shsees a seat and exits without writing.actasin T2 → same. The seat stays T1 forever; every later launch repeats this. The only way out is to know T1's id and typecodex resume <T1>by hand — and #353's closing note ("freshness holds because a role re-runsactason resume, which rewrites the record") no longer holds after #579, which is presumably why this was not caught then.Evidence
run/codex-bridge.dqx-buttle.minori.log(bridge for a seated role, plain relaunches over several days): the bridge starts turns on the recorded thread while the operator's TUI is elsewhere —run/role-session.dqx-buttle__minoriholdssession=019fea06-…(recorded 2026-08-10);~/.codex/sessions/2026/08/10/rollout-…-019fea06-….jsonlexists. Everycodexlaunched afterwards opened a different thread, and the turns above were not visible in any of them.What would fix it
Make the TUI make the same choice the launcher makes: a plain monitored
codexopens the role's recorded thread —codex resume --remote <url> <thread>— when that is unambiguous (one Codex role registered for the project, seat in this project, rollout still on disk, via theagmsg_role_resume_uuidgate spawn/resurrect already use); otherwise fresh, saying why. An explicitcodex resume …stays as given.And once TUI and bridge share one thread, the bridge should attach to the thread the TUI loaded (poll
thread/loaded/listfor it) rather thanthread/resumeit itself:turn/startneeds only the id (the no-rollout fallback has relied on that since #276), and a bridge-side resume is thealready has an active writercollision of #906 against Codex Desktop.I have this running locally since 2026-08-10 (logs show
TUI loaded thread …; attaching without a competing resumefollowed by delivered wakes) and will open a PR.Related: #350 / #353 (the bridge half of this), #579 (why the seat cannot move), #816 (the missing-seat case; this issue is the present-seat case), #365 ("rebind the saved role on SessionStart" asks for the same outcome for Codex Desktop), #906 (active-writer collision).
Not in that PR, noted for later
serverRequest/resolved), with Codex bridge: thread stuck in waitingOnApproval deadlocks delivery forever (bridge can't answer approval requests; launcher never replaces the hung bridge) #299's bounded decline as the fallback, is a separate change.mode off) overlap with fix(codex): add invocation-scoped monitor lifecycle #907 / fix(codex-bridge-launcher): reap a same-(project,role) orphan before spawning (#906 link 2) #943 / codex monitor mode: duplicate-bridge leak saturates the user's TasksMax (two incidents in one day) — bridge survives "active writer" failure, launcher respawns without orphan scan, re-arm loop has no backoff #906 and are left to those.