App Server: expose read-only subscriber presence separately from loaded-thread state

Open 💬 0 comments Opened Jul 27, 2026 by jchy20

What variant of Codex are you using?

Codex CLI with the managed app-server daemon/proxy (codex-cli 0.145.0) on Linux. A separate read-only monitoring client connects to that daemon over the documented app-server protocol.

What feature would you like to see?

Please expose a supported, read-only way for an app-server client to distinguish:

  1. a thread that is loaded because an interactive client such as the Codex TUI is currently attached; and
  2. a thread that remains loaded only as warm runtime state after its last interactive client unsubscribed or disconnected.

A privacy-preserving API could expose aggregate presence only, for example:

{
  "threadId": "…",
  "subscriberCount": 2,
  "interactiveSubscriberCount": 1
}

This could be a new thread/presence/list method, optional presence fields on an existing thread metadata response, or another shape the maintainers prefer. A thread/presence/changed notification would be useful, but polling a supported read API would be sufficient.

If client kinds can be derived safely from initialization metadata, counts by broad kind (tui, desktop, remote-control, observer, other) would let an observer answer whether a TUI is still attached without exposing connection IDs. If client-kind classification is not appropriate, even a supported zero-versus-nonzero subscriber count would address the core loaded-versus-attached ambiguity for observers that unsubscribe their own connection.

Additional information

Reproduction
  1. Start a Codex TUI connected to the managed daemon. A new thread is created and loaded.
  2. Use /resume to continue a previously stored thread.
  3. From a separate initialized app-server connection, call thread/loaded/list and read metadata for the returned threads.
  4. Both the unused startup thread and the resumed thread can remain loaded and report an idle runtime status.
  5. Close the TUI. The resumed idle thread can remain in thread/loaded/list during the no-subscriber inactivity grace period.

The public protocol exposes the loaded/runtime state, but not whether another interactive client remains subscribed. Therefore idle cannot be interpreted as “ready in an open terminal.”

The desired behavior is not to unload threads immediately or remove the grace period. The requested presence value should simply change promptly when a TUI switches threads, unsubscribes, or disconnects, while the underlying zero-subscriber thread may remain loaded as today.

Why this matters

Read-only integrations such as status bars, accessibility tools, monitoring dashboards, and physical indicators need to answer questions like:

  • How many Codex terminals are currently waiting for a prompt?
  • Which attached thread is working or waiting for approval/input?
  • Did /resume replace the unused startup thread in the terminal?
  • Did the user close the terminal, even though Codex retained its runtime state?

Without a supported presence signal, integrations must guess using private SQLite/rollout formats, process working directories, file modification times, or recency heuristics. Those approaches are fragile across frequent Codex releases and ambiguous when multiple TUI sessions share a working directory.

This feature would also let clients avoid accidentally treating a persisted or warm-cached thread as an active user-facing session.

Non-goals

This request does not require:

  • reading transcript content;
  • attaching to, steering, or starting turns;
  • receiving or answering approvals;
  • exposing connection IDs or other client-sensitive metadata;
  • changing the existing unload grace period;
  • installing a helper or interposing a relay between the TUI and daemon.

It is only a request for aggregate, read-only presence associated with already-loaded threads.

Implementation context

In the 0.145.0 source, app-server already appears to maintain per-thread connection membership internally (connection_ids and thread_ids_by_connection):

https://github.com/openai/codex/blob/25af12f7e61572b0bc18ddb1008be543b91519b0/codex-rs/app-server/src/thread_state.rs#L283-L365

The public thread status types expose runtime state but not subscriber presence:

https://github.com/openai/codex/blob/25af12f7e61572b0bc18ddb1008be543b91519b0/codex-rs/app-server-protocol/src/protocol/v2/thread.rs#L1304-L1348

Related but distinct issues:

  • #25914 requests discovery/attachment for the active Codex Desktop thread. This request is narrower, read-only, and concerns loaded threads on a shared CLI daemon.
  • #21551 discussed writable peer-client co-presence. This request does not ask for co-control or multi-client turn interaction.
  • #14137 concerns orphan cleanup after unexpected disconnects. This request also covers the intentional period where a correctly unsubscribed zero-subscriber thread remains loaded.
Suggested acceptance criteria
  • A read-only client can distinguish a loaded thread with no interactive subscribers from one with at least one interactive subscriber.
  • Presence updates promptly after /resume, explicit unsubscribe, and connection close.
  • A zero-subscriber thread may remain loaded during the existing grace period without being reported as interactively attached.
  • The API exposes aggregate state only and does not reveal connection identifiers.

View original on GitHub ↗