Skip to content

plat 035

github-actions[bot] edited this page Sep 20, 2026 · 1 revision

← Pulse platform issue index

PLAT-035 — retained tmux follow-up stays globally busy after returning to its prompt

Coordination Value
Assigned agent Codex
Ticket state implemented; runtime reverify
Last synchronized 2026-08-05
  • Priority: P0
  • Owner: retained coding-agent turn lifecycle and tmux live-attach stream
  • Source workflows: Social Media and LinkedIn
  • Related ticket: PLAT-020 preserves the same session/tmux during a schedule-to-chat conversion. PLAT-035 is the more general completion defect affecting any direct follow-up sent to a retained Claude/Codex pane.

Problem and runtime evidence

The active-sessions API reported both workflows as running/busy even though their live Claude and Codex tmux panes had returned to idle input prompts. The execution tree contained no running main agent, child, or tracked execution; terminal_busy and background_live were false. The stale authority was foreground_turn.busy=true, set when direct retained input was delivered.

No matching streaming_end, agent_end, conversation_end, or unified_completion event reached the backend for those retained turns, so the Global Activity Monitor displayed indefinite loading spinners.

Why the previous fix was incomplete

Commit fac60abac added the correct settlement consumer: when a structured main-terminal completion event arrives, clear the logical busy state while retaining the live tmux process. Its regression test manually injected streaming_end. It therefore proved what happens after an event arrives but did not prove a real retained Claude/Codex input produces that event.

Fix

  • The shared tmux control-mode stream now supports backend output observers that do not require a browser viewer and do not claim the visible viewer slot.
  • Direct retained turns subscribe to that real output stream. Output schedules a quiet-boundary, in-band pane capture; there is no fixed capture polling.
  • multi-llm-provider-go owns canonical readiness classification for Claude, Codex, Cursor, and Pi, so the server does not duplicate fragile provider prompt/approval/activity rules.
  • A provider-ready screen must remain stable across a second check. A transient idle repaint cannot close a turn that immediately continues.
  • A stable idle composer emits canonical unified_completion. Existing lifecycle handling clears foreground_turn.busy and session status while leaving the tmux process live and reusable.
  • Starting another retained turn cancels the earlier watcher; settlement also removes its watcher, so no per-session observer accumulates.

Verification

The new backend regression does not inject a completion event. It starts with an active Codex pane, proves the session remains busy, sends a tmux stream output notification after changing the pane to its idle composer, and verifies:

  • unified_completion was generated by the stream lifecycle;
  • the session becomes completed rather than globally loading;
  • the terminal's logical turn becomes inactive/completed;
  • process_state remains live for the next message.

Provider-level tests cover idle and active Claude/Codex screens, while the canonical function also delegates Cursor and Pi to their existing adapter rules. Focused backend and provider test suites pass. A rebuilt real Claude and Codex retained follow-up must still verify /api/sessions/active transitions back to idle/completed; no backend restart was performed during implementation.

Acceptance

For every supported retained coding CLI, sending a follow-up changes the session to running, real tmux output returning to a stable idle composer emits one completion, the Global Activity Monitor stops loading, and the same tmux continues accepting later input. The test must not manufacture the completion event it claims to verify.

Clone this wiki locally