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
feat: show whether bound Codex threads are running in the App (#5081)
* feat(status): observe bound Codex thread activity for the App status route
Add a read-only host thread observer contract with typed states
(turn_open, idle, archived, unknown with a typed reason) and a Codex
adapter that reads the local thread store and rollout turn markers.
Unrecognized store or record shapes are unknown, never an open turn.
Only the App status route attaches the result; other collect_status
callers are unchanged.
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(app): show observed host thread turns as execution
An open host-recorded turn with a recent event runs the Goal with the
live ring; silent turns disclose their silence and turns without an
event for six hours are not execution. Observed idle threads read as
idle instead of deferring to the host.
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(status): keep partial and malformed host observations honest
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
* fix(status): preserve claim clocks and escaped event semantics
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
---------
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Co-authored-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
The broker only sees turns a host claims. A host thread registered with
79
+
`bind-agent-thread` but never attached is observed separately, read-only, from
80
+
the host's own local store. The App status route (`/status.json`) adds
81
+
`run_history.goals[].host_thread_activity` with up to 32 bound-thread rows:
82
+
`agent_id`, `host_surface`, `state`, and the `turn_started_at`,
83
+
`last_turn_ended_at` and `last_event_at` timestamps when known. Thread ids,
84
+
paths and message content are not included.
85
+
86
+
The observation's `completeness` is `complete` only when every valid binding
87
+
fits within that read budget; otherwise it is `incomplete`. The App can show
88
+
an observed recent open turn from either, but reports all hosts idle only from
89
+
a complete observation containing only idle or archived threads. Missing or
90
+
unrecognized completeness is treated as incomplete. Malformed event payloads
91
+
make that thread `unknown` without failing the status route; a later recognized
92
+
turn marker restores its observed state.
93
+
94
+
|`state`| Meaning |
95
+
| --- | --- |
96
+
|`turn_open`| The host recorded a turn start without an end. A host that exits mid-turn leaves this behind, so the App shows it as running only while `last_event_at` is recent. |
97
+
|`idle`| The latest recorded turn ended. |
98
+
|`archived`| The host archived the thread. |
99
+
|`unknown`| Not observable; `reason` is `unsupported_host`, `store_unavailable`, `thread_not_found`, `record_unrecognized` or `no_turn_marker`. |
100
+
101
+
Codex local surfaces (`codex-app`, `codex-cli-tui`, `codex-ide-plugin`) are read
102
+
from `<CODEX_HOME>/state_<n>.sqlite` and the thread's rollout JSONL. The Codex
103
+
store is not a public contract: any shape the adapter does not recognize is
104
+
`unknown`, never `turn_open`. Remote surfaces such as `codex-app-ssh` are
105
+
`unsupported_host`. Homes are searched in the order `CODEX_HOME`, `~/.codex`,
106
+
then sibling `~/.codex-*` directories; set `LOOPX_CODEX_HOMES` (an
107
+
`os.pathsep`-separated list) to search exactly those homes instead.
0 commit comments