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
The bottom status bar renders the animated busy segment (breeze spinner + activity verb) as the second left-aligned segment, before all metric segments. The humanized verb has variable display width (thinking = 8 cols, searching = 9, compacting · context = 20, …), so every status change makes all segments to its right — skills, tokens, api, cost, etc. — jump horizontally. The effect is constant visual churn on a line that otherwise holds stable session parameters.
Meanwhile the input separator row (one line above the input box) already shows the same breeze spinner while busy — the animation is duplicated across two adjacent lines, but the verb is deliberately shown only in the bottom bar (crates/zeph-tui/src/widgets/input.rs:19-24 documents this split; the wave equalizer in the side panel is a third busy indicator and is out of scope here).
Move the transient busy status (spinner + verb) up to the input separator row — where the spinner already lives — and keep the bottom line for stable parameters only. Nothing in the bottom bar then changes width mid-turn, and the duplication disappears.
Current Behavior
Bottom bar: crates/zeph-tui/src/widgets/status.rs:322-350push_busy_segment (spinner + verb), pushed second after the mode chip (build_segment_lists, status.rs:280-284); every following segment's x-offset includes the verb width (SegmentList::layout, status.rs:118-220). Right-aligned uptime does not move (status.rs:242-262); everything between the verb and uptime does.
Separator row: crates/zeph-tui/src/widgets/input.rs:26-40push_busy_tail appends the breeze spinner + interrupt hint, explicitly without the verb; test input_busy_width_40 (input.rs:288-303) pins the verb's absence.
Status text source: free-form AgentEvent::Status(String) → SessionSlot::status_label → humanized by status_verbs::humanize (crates/zeph-tui/src/widgets/status_verbs.rs:108-158).
Expected Behavior
Input separator row (busy): you ▸ … ▸▸▹ {verb} · {interrupt hint} … — the humanized verb joins the spinner that is already there. The interrupt-hint text itself is owned by #6646 (esc to interrupt → ctrl+c when that lands); this issue keeps whatever hint is current.
Bottom status bar: the busy segment (spinner + verb) is removed entirely. Remaining left-to-right content — mode chip, [Plan]/Viewing:, skills, tokens, SEC, api, cost, sh:N, cocoon, bg, [SC:N], goal, filters, GRD, tok/s + TTFT, mouse, durable — with right-aligned uptime. Streaming tok/s + TTFT stay in the bottom bar (decided; their appear/disappear shift is accepted for now). The transient Press Ctrl+C again to exit hint from #6646 also stays in the bottom bar as a Priority::Critical segment — it is rare and short-lived, unlike the per-turn busy verb.
Idle rendering of the separator row is unchanged (prompt glyph, mode hint, ~N tokens, queue badges).
Invariants that must keep holding
Spinner Rule (specs/011-tui/spec.md:70-81, specs/001-system-invariants/spec.md:219, specs/constitution.md:40): every background/implicit operation shows a visible spinner + short status, cleared on completion. The rule is location-agnostic in constitution/invariants, but 011-tui currently pins "Status Bar | Current operation spinner + short status text" — the spec must be updated to name the separator row as the canonical location (spec change tracked with this issue).
specs/026-tui-subagent-management/spec.md FR-010 (spinner animates with the throbber tick) — unchanged mechanically, verify wording.
No blocking I/O on the render thread; render is a pure function of existing state (status_label moves render site only, no new channels).
Implementation Notes
input.rs::push_busy_tail gains the humanized verb; truncate the verb before the hint under width pressure (narrow terminals) — the row already has a width-budget pattern.
status.rs::build_segment_lists drops push_busy_segment; remove the now-unused busy plumbing from the status widget.
Invert test input_busy_width_40 (verb must now appear) and update status-bar layout tests that assert the busy segment.
Motion-off mode (motion=Off renders static · instead of animated frames) must carry over to the separator row rendering of the verb.
Description
The bottom status bar renders the animated busy segment (breeze spinner + activity verb) as the second left-aligned segment, before all metric segments. The humanized verb has variable display width (
thinking= 8 cols,searching= 9,compacting · context= 20, …), so every status change makes all segments to its right — skills, tokens, api, cost, etc. — jump horizontally. The effect is constant visual churn on a line that otherwise holds stable session parameters.Meanwhile the input separator row (one line above the input box) already shows the same breeze spinner while busy — the animation is duplicated across two adjacent lines, but the verb is deliberately shown only in the bottom bar (
crates/zeph-tui/src/widgets/input.rs:19-24documents this split; the wave equalizer in the side panel is a third busy indicator and is out of scope here).Move the transient busy status (spinner + verb) up to the input separator row — where the spinner already lives — and keep the bottom line for stable parameters only. Nothing in the bottom bar then changes width mid-turn, and the duplication disappears.
Current Behavior
crates/zeph-tui/src/widgets/status.rs:322-350push_busy_segment(spinner + verb), pushed second after the mode chip (build_segment_lists,status.rs:280-284); every following segment's x-offset includes the verb width (SegmentList::layout,status.rs:118-220). Right-aligned uptime does not move (status.rs:242-262); everything between the verb and uptime does.crates/zeph-tui/src/widgets/input.rs:26-40push_busy_tailappends the breeze spinner + interrupt hint, explicitly without the verb; testinput_busy_width_40(input.rs:288-303) pins the verb's absence.AgentEvent::Status(String)→SessionSlot::status_label→ humanized bystatus_verbs::humanize(crates/zeph-tui/src/widgets/status_verbs.rs:108-158).Expected Behavior
Input separator row (busy):
you ▸ … ▸▸▹ {verb} · {interrupt hint} …— the humanized verb joins the spinner that is already there. The interrupt-hint text itself is owned by #6646 (esc to interrupt→ctrl+cwhen that lands); this issue keeps whatever hint is current.Bottom status bar: the busy segment (spinner + verb) is removed entirely. Remaining left-to-right content — mode chip,
[Plan]/Viewing:, skills, tokens, SEC, api, cost, sh:N, cocoon, bg,[SC:N], goal, filters, GRD, tok/s + TTFT, mouse, durable — with right-aligned uptime. Streaming tok/s + TTFT stay in the bottom bar (decided; their appear/disappear shift is accepted for now). The transientPress Ctrl+C again to exithint from #6646 also stays in the bottom bar as aPriority::Criticalsegment — it is rare and short-lived, unlike the per-turn busy verb.Idle rendering of the separator row is unchanged (prompt glyph, mode hint,
~N tokens, queue badges).Invariants that must keep holding
specs/011-tui/spec.md:70-81,specs/001-system-invariants/spec.md:219,specs/constitution.md:40): every background/implicit operation shows a visible spinner + short status, cleared on completion. The rule is location-agnostic in constitution/invariants, but011-tuicurrently pins "Status Bar | Current operation spinner + short status text" — the spec must be updated to name the separator row as the canonical location (spec change tracked with this issue).specs/026-tui-subagent-management/spec.mdFR-010 (spinner animates with the throbber tick) — unchanged mechanically, verify wording.…only) viastatus_verbs::humanize— unchanged.status_labelmoves render site only, no new channels).Implementation Notes
input.rs::push_busy_tailgains the humanized verb; truncate the verb before the hint under width pressure (narrow terminals) — the row already has a width-budget pattern.status.rs::build_segment_listsdropspush_busy_segment; remove the now-unused busy plumbing from the status widget.input_busy_width_40(verb must now appear) and update status-bar layout tests that assert the busy segment.motion=Offrenders static·instead of animated frames) must carry over to the separator row rendering of the verb.Environment
zeph-tui(featuretui,desktopbundle)