A terminal monitor sees task_complete
. It sends an alert. The user returns and finds that the event belongs to an old turn, a background worker, or a session they already resumed.
The parser found a real event. The product state was still wrong.
Our local parser returns a completion flag, a turn key, and the event's semantic timestamp. The turn key deduplicates repeated observations. The timestamp lets later activity revoke the result.
TurnStatus {
isDone
turnKey
activityDate
}
Claude and Codex need separate adapters. Claude stop reasons are not sufficient on their own because an API-error record can use a completion-shaped envelope. Codex uses event types such as task_complete
and turn/completed
.
The monitor combines the turn timestamp with newer local session activity. A fresh completed turn becomes needsYou
. Newer user activity can move it back to working, while the freshness cap eventually returns it to idle.
Filesystem modification time remains a fallback. It cannot be the main clock because bookkeeping writes do not carry the same meaning as user activity.
A longer attention window preserves alerts for users who step away, but keeps old state around longer. Watchers improve latency, but a periodic scan is still needed for dropped events. Upstream record changes require parser fixtures that cover errors and later activity, not just the happy path.
I help run Agent Island, where this state model is used for local Claude Code and Codex monitoring.