Skip to content

XERK-130: active sessions no longer read idle on narrow panes#313

Merged
xerhab merged 1 commit into
mainfrom
XERK-130
Jul 25, 2026
Merged

XERK-130: active sessions no longer read idle on narrow panes#313
xerhab merged 1 commit into
mainfrom
XERK-130

Conversation

@xerhab

@xerhab xerhab commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

What

The ticket: session working/idle accuracy — "more often than not active sessions are marked as idle".

Reviewing the live sessions on the fleet host found the cause. tmux keeps a window at its smallest-ever attached client width; a session once viewed from a phone renders ~54 columns. At that width the Claude Code TUI ellipsizes the footer's · esc to interrupt hint to · esc to inte…, and both busy detectors key on the full string:

  • _busy_from_capture in hub-agent.py — the heartbeat's paneBusy, which drives every status surface (fleet dots, session cards, glasses glyph, Android list) and the turn-finished notification;
  • parsePaneLiveTurn's gate in tunnel-agent.js — the live chat's working bar / Stop button.

So every working session on a narrowed pane read idle for its entire turn. Four of five live sessions on the host were on 54-col panes.

Fix

Both detectors now accept two additional shapes (same shapes on both sides, per the existing parity contract):

  • the width-truncated hint remnant on the mode footer line: mode-glyph (/) anchored line whose last ·-segment is any prefix of esc to interrupt ending in the TUI's own . Character-class prefix matching covers every cut point; middle segments vary across sessions ((shift+tab to cycle) comes and goes, a · PR #98 chip can sit before the hint) so the anchor is the glyph + tail, not fixed wording. The idle suffix · ← for agents can never match (doesn't start with e). This is the only visible signal while text streams on a narrow pane (no spinner painted then) or while the pane is scrolled up.
  • the column-0 spinner line (✢ Determining… (12m 19s · ↓ 44.2k tokens), · Perusing… (54m 38s · still thinking)): glyph-agnostic but excluding the assistant bullet and prompt, requiring the gerund's ellipsis — the completed-turn line an idle pane keeps on screen (✻ Brewed for 9s) has none, and echoed pane captures in tool output are indented, so neither fakes busy.

Both fail toward idle (today's behaviour) if the TUI wording shifts, and stay off when TURMA_PANE_BUSY_MARKERS is emptied.

How it was verified

  • Empirically diagnosed and verified against the real fleet: captured live panes of 5 running sessions; a probe claude TUI at 200 and 54 columns captured the exact idle footer (· ← for agents, no hint), busy footer (full hint), truncated busy footer, and completed-turn line.
  • Ran the new _busy_from_capture against all 5 live panes: the two working sessions flipped idle→busy (the defect), the idle/dialog ones stayed idle — before/after comparison in the session transcript.
  • python3 -m unittest agent.tests.test_hub_agent: 737 tests OK (10 new narrow-pane cases in TestPaneBusy).
  • node --test agent/tests/tunnel-agent.test.js: 62 tests pass (4 new parsePaneLiveTurn fixtures).

Agent-side only — no web UI change, so no Android parity work.

…hint alone

Live-session review found why active sessions read idle: tmux keeps a pane
at its smallest-ever client width (a phone leaves ~54 columns), and at that
width the Claude Code TUI ellipsizes the footer's '· esc to interrupt' to
'· esc to inte…' — so the plain substring match in _busy_from_capture (the
heartbeat's paneBusy) and parsePaneLiveTurn's gate (the live working bar)
both read every working session on such a pane as idle for its whole turn.

Both now accept two additional shapes, verified against live panes:
- the mode footer line's width-truncated hint remnant: mode glyph anchor,
  then a last '·'-segment that is any prefix of 'esc to interrupt' ending in
  the TUI's own '…' (middle segments vary: '(shift+tab to cycle)' comes and
  goes, a 'PR #98' chip can sit before the hint; the idle '· ← for agents'
  suffix can never match). The only visible signal while text streams on a
  narrow pane (no spinner line then) or the conversation is scrolled up.
- the column-0 working-spinner line ('✢ Determining… (12m 19s · ↓ 44.2k
  tokens)', '· Perusing… (54m 38s · still thinking)'). The gerund's ellipsis
  is required so the completed-turn line an idle pane keeps on screen
  ('✻ Brewed for 9s') can't fake busy; assistant text can't sit at column 0.

Both new shapes fail toward idle (today's behaviour) on a future TUI wording
change, and stay disabled when TURMA_PANE_BUSY_MARKERS is emptied.
@xerhab
xerhab merged commit 03c8101 into main Jul 25, 2026
5 checks passed
@xerhab
xerhab deleted the XERK-130 branch July 25, 2026 23:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant