TUI cannot be woken by local same-user tooling: no thread-owner registration or external resync for an idle `codex` session
What variant of Codex are you using?
CLI (TUI), compared against App and the VS Code extension. Observed oncodex-cli 0.145.0 (macOS arm64, Homebrew) and Linux x86_64, ChatGPT.app
2026-07-24 build, VS Code extension 26.721.41059.
What feature would you like to see?
How this differs from existing issues (please read before deduplicating):
this asks for a mechanism on the TUI side. #11907 and #21974 ask the App
to refresh or observe other surfaces; #21743 and #32466 report Desktop
staleness; #25914 asks for an app-server discovery contract. #11957 asked
for TUI resync and was closed as a duplicate of #11907, an App-side refresh
request, so the TUI-side ask has not yet been evaluated on its own. None of
those changes anything about an idle TUI's ability to receive a local signal.
There is currently no supported way for a local same-user process to wake an
idle, already-open codex TUI session when its persisted thread is updated
externally.
Codex App and the VS Code extension both solve this for their own surfaces
through the same-user IPC router at $CODEX_HOME/ipc/ipc.sock: each registers
as the owner of its loaded thread and services follower requests such asthread-follower-start-turn, so an externally initiated turn renders live in
the already-open task. The TUI does not participate. It links the router only
as a short-lived client for IDE context discovery. The TUI is therefore the
only major Codex surface whose open session cannot be reached by local
same-user tooling.
Any one of the following would close the gap. The first matches how App and
the extension already behave:
- TUI thread-owner registration. On start or resume, the TUI registers its
loaded thread ID as owner with the same-user IPC router it already links,
and services thread-follower-start-turn — running an ordinary turn with
normal rendering, approval handling, and interrupt behavior. This gives the
TUI parity with App and the extension, and would additionally let the App
follow a live TUI session, which is the capability #21974 asks for from the
other direction.
- Minimal externally triggered resync. A documented signal telling an idle
TUI that its persisted thread changed, on which it re-reads the rollout and
renders externally appended turns. This is #11957's ask with a concrete
transport attached.
- A documented supported alternative, if the team prefers a different
surface — for example a discoverable per-session app-server endpoint with an
explicit wake method.
Constraints that appear necessary regardless of shape, based on what was needed
to deliver this safely on App and VS Code: same-user socket ownership and
permission validation; idle-boundary gating (queue or return busy during an
active turn); idempotent, exactly-once turn creation; and preservation of
composer state.
Additional information
Why this matters. Long-running local work — CUDA and CMake builds, large
test suites, data processing — should not hold an agent turn open while it
runs. I maintain Codex Process Jobs,
a plugin in the Plugins Directory that runs such commands as detached OS
processes and delivers a sanitized completion back to the owning task. On App
and the VS Code extension, routing that completion through the router's owner
path renders it live in the open task. On the TUI it can only be persisted and
surfaced at the next hook boundary, because nothing can reach an idle TUI. The
same workflow is materially worse on the CLI than on every other surface.
Evidence (all read-only inspection of shipped binaries; no vendor files
modified).
- A
stringssweep of the shippedcodex-cli 0.145.0native binary contains
the IPC client vocabulary for IDE context discovery — codex-ipc,
ipc-0.sock, ide-context, canHandle, codex-tui, sourceClientId,
workspaceRoot, and same-user ownership/permission validation errors — and
zero occurrences of follower or thread-stream.
- The Rust
codexbinary bundled inside ChatGPT.app likewise contains no
follower vocabulary. The follower handlers live in the App's Electron layer
and in the extension's out/extension.js, which contains the full method and
event set (thread-follower-start-turn, -steer-turn, -interrupt-turn,
-submit-user-input, -load-complete-history, thread-stream-*,
client-discovery-*). This is why the capability exists on two surfaces but
not the third.
- Every hook event in the shipped CLI (
SessionStart,TurnStart,
PreToolUse, PostToolUse, UserPromptSubmit, Stop, SessionEnd)
requires user or agent activity, so hooks cannot substitute for a wake while
the TUI is idle.
- A turn appended to the same thread by a separate
codex app-serverprocess
persists correctly in the rollout, but the open TUI does not display it.
Controlled run on 2026-07-27 against 0.145.0: a detached job was launched
from an open TUI, the launch turn ended, and the terminal was left untouched.
The rollout records the notifier-owned turn in full — synthetic notice at
03:34:46, assistant reply at 03:34:48, and a matching task_complete —
while the open TUI displayed none of it. The launch turn had ended 90 seconds
earlier, ruling out a busy-turn race. The completion became visible only via
a hook boundary on a later prompt.
Reproduction for the binary claims. Note that codex on the npm/Homebrew path
is a Node wrapper; the sweep must target the native vendor binary, or it will
report "no follower vocabulary" for the wrong reason:
ROOT="$(dirname "$(readlink -f "$(command -v codex)")")/.."
BIN="$(find "$ROOT/node_modules/@openai" -type f -name codex -perm -u+x -path '*vendor*' | head -1)"
file "$BIN" # expect a native executable
strings -a "$BIN" | grep -Ei "follower|thread-stream" | head # expect no output
strings -a "$BIN" | grep -Eo "codex-ipc|ide-context|codex-tui" | sort -u # positive control
Alternatives considered and rejected. Terminal keystroke injection —TIOCSTI is blocked on modern macOS and restricted on Linux, and
terminal-emulator automation is emulator-specific and unsafe while a user is
composing. Holding a Stop hook open — recreates the blocked-turn problem that
detaching exists to solve. --remote/WebSocket attach to a shared app-server —
architecturally sound and clearly the direction of travel since #11166 landed,
but it requires a special invocation and a separately managed persistent
server, so it cannot be the default for ordinary local TUI usage.
I am not proposing a pull request, per the invitation-only contribution policy.
I am glad to supply further analysis, additional platform testing, or
verification against a proposed design if that would help.
1 Comment
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action