feat(tui): animate the harness status line and capture every attention state - #235
Conversation
The rail now distinguishes working, waiting, and failed harnesses through animated spinners and colored pulses, with lifecycle cues for completed or errored sessions. Blocking errors like usage limits or expired credentials are detected from the terminal tail, and the attention pulse is configurable in seconds with a frame-driven implementation that works across terminals. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update test fixture constructors to include the newly added `working` and `attention_blink_seconds` fields, keeping the test suite compiling after the corresponding struct changes. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The ATTENTION_GLYPH constant was imported but no longer used in the rail rows rendering code, so the import has been removed to keep the codebase clean and avoid compiler warnings. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The event loop now references the frame interval constant through the public `medulla_tui` crate path instead of the internal `crate` alias, ensuring the constant is accessible from outside the crate and aligning with the crate's public API. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The appearance usage section now explains that theme and accent color settings apply globally across the entire application, rather than being limited to the current view. This removes ambiguity for users who previously might have expected per-screen customization. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The appearance usage screen now displays the configured blink interval by importing `blink_seconds` from the theme module, so users can see the exact timing used for attention indicators. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The appearance module now stores its state more directly, reducing unnecessary indirection and making the code easier to follow. This change does not alter any visible behavior. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The appearance module now stores theme and accent color directly instead of wrapping them in an intermediate struct, reducing unnecessary indirection and making the state easier to read and modify. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The appearance module now stores theme and accent color directly instead of wrapping them in an intermediate struct, reducing unnecessary indirection and making the state easier to read and modify. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Import the blink timing conversion functions from the theme module so they can be used when constructing the status line appearance configuration. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The session now checks whether the underlying PTY session has already closed while waiting for attention, preventing a hang when the session terminates unexpectedly during the wait. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds unit tests for the attention mechanism in the rail agent renderer, covering the computation of attention weights and their application to the rendered output. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The agent status panel was previously hidden unless the rail was actively being edited. It now displays whenever the rail is selected, making the current agent state visible without requiring an edit action. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The test previously asserted that an idle harness displays a hollow circle, but the actual behavior renders a filled circle. The assertion now matches the implemented spinner state for idle harnesses. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The attention detection loop now processes pty resize events, which were previously ignored. This ensures the terminal dimensions stay synchronized with the underlying pty when the user resizes the window. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The appearance settings tests now account for an additional attention control in the navigation sequence, increasing the number of key presses needed to reach the resources and device indicators sections. This aligns the test expectations with the updated settings layout. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Adds unit tests covering the feature settings module, verifying default values, serialization, and update behavior to ensure the settings logic works as expected. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add tests for the attention blink configuration and rendering behavior, covering conversion of seconds to milliseconds, clamping of out-of-range values, and the frame-based pulse alternation. Also verify that disabled blinking stays bright and that sub-frame periods still alternate correctly. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add tests for the attention detection logic in the PTY worker, covering blocking errors from usage limits and expired tokens, ensuring errors scrolled out of the live tail are not flagged, and verifying that prompts outrank errors and ordinary error output is ignored. Also test that the cue vocabulary is ordered from certain to vague, with plan-exit menus named by their accept options. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add unit tests covering the attention session logic in the PTY worker, verifying correct behavior for session start, end, and edge cases to improve coverage and prevent regressions. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add the session_tests module to the attention module's test configuration, ensuring the session-related tests are included in the test build alongside the existing tests module. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Reformatted several multi-line expressions and assertions across the rail rendering and attention session code to improve readability, with no behavioral changes. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Replace the modulo comparison in the attention blink calculation with the more idiomatic `is_multiple_of` method, and update the tests to construct themes with struct update syntax instead of mutating defaults. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The attention manager now gracefully ignores requests when no session is currently active, preventing a potential panic from attempting to access a missing session state. This makes the attention flow robust to out-of-order or stale requests. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The attention type parsing now gracefully handles unknown or malformed input instead of panicking, returning a fallback value that keeps the terminal session stable. This prevents crashes when receiving unexpected data from the PTY. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The attention manager now gracefully ignores requests that arrive when no session is active, instead of panicking. This prevents a crash in edge cases where the terminal state is inconsistent. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The attention detection logic in the PTY worker now correctly handles an edge case where the detection state could become stale, preventing false positives. This improves reliability when processing rapid input sequences. Co-authored-by: Medulla <medulla@tinyhumans.ai>
The attention detection loop now processes pty resize events, which were previously ignored. This ensures the terminal dimensions stay in sync when the user resizes the window, preventing stale geometry from affecting layout and rendering. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Add tests for the attention matcher's working-state detection, capturing live Claude Code progress output that lacks the "esc to interrupt" cue. The new cases verify Claude's spinner, gerund, and timer lines count as working, while lookalike fragments in ordinary output do not, and confirm Codex's existing format remains recognized. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Added comments to the example configuration explaining the new attention highlighting behavior, including how the pulse animation works via Medulla's frame clock and how failed harnesses are distinguished with red coloring regardless of the configured attention color. Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/detect.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/tests.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 15c9f1ec16
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/detect.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/tests.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/detect.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/tests.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/tests.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/tests.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 64c025ce4c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/detect.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/tests.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/tests.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/tests.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 2ca2358d54
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/detect.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/detect.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Checkpoint of work in progress, touching src/tui/src/worker/pty/attention/tests.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 770696baa3
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Checkpoint of work in progress, touching src/sdk/src/codex_overrides/tests.rs. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ry modules The single 685-line test file for harness attention detection has been replaced with separate modules for cues, errors, prompts, and working state, each in its own file under a new `tests/` directory. This makes the test suite easier to navigate and maintain by grouping related test cases together. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
The `pairs.insert` line in the `overrides` helper function was incorrectly indented with a leading dash, causing a syntax error. This change fixes the indentation to use proper spacing. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
tinysweeper found nothing blocking. Approving.
$0.0552 · 347,991 in / 42,877 out · 250,834 cached (72%) · z-ai/glm-5.2, deepseek/deepseek-v4-pro
critique: $0.0467 · 134,452 in / 23,759 out · 64,332 cached (48%) · deepseek/deepseek-v4-pro, z-ai/glm-5.2
security: $0.0052 · 116,930 in / 12,817 out · 102,399 cached (88%) · z-ai/glm-5.2
tests: $0.0019 · 46,851 in / 4,445 out · 41,228 cached (88%) · z-ai/glm-5.2
description: $0.0013 · 47,643 in / 1,220 out · 40,972 cached (86%) · z-ai/glm-5.2
A harness row could say a session was alive. It could not say what it was
doing, and it went quiet at two of the moments that matter most — when the
harness died, and when its work finished. This makes the row animate, widens the
attention vocabulary to cover the states nothing was reporting, and fixes a
detector that had silently stopped matching current Claude Code.
Animation
A working harness spins.
SessionRowgains aworkingflag, set by theattention poller from the harness's own screen. A live-but-idle session still
draws
●; one mid-turn draws a braille spinner off the existing 90ms frameclock. This is the signal that could not be obtained any other way — a harness
thinking hard writes nothing, so
busy,last_output_at, andstatereadidentically for a working session and one sitting at a composer.
A stuck harness pulses, visibly. The cue used
Modifier::SLOW_BLINK, whichdelegates the decision to the terminal — and most terminals, plus every
multiplexer, drop it. The blink was therefore invisible to most of the people it
was for. It now alternates bold/dim on the frame counter, so the rhythm is the
same everywhere. Dim rather than absent: the cue carries the wording that says
what the harness wants, and text that vanishes for half a second is text you have
to wait to read.
The rate is configurable in seconds.
Settings › Appearance gains a Blink rate row beside the existing blink
toggle, cycling 0.3s–3.0s and persisting live. A failure pulses red regardless
of the configured colour, so "it is asking you something" and "it broke" are
never the same colour.
The states that were never captured
is_workingwas dead for current Claude. Verified against a live session:Claude Code v2.1.224 never prints "esc to interrupt" — it draws
✽ Considering… (7s · ↓ 193 tokens · thinking with medium effort). Thatfunction is what vetoes the vague cues, so recent Claude had no veto at all.
Now matched structurally (spinner glyph + ellipsis + elapsed timer, all three
required), because the gerund comes from a long and unstable list. Codex still
uses the old wording and is untouched.
often an ordinary composer — and the row went still. Now red
✕pluscodex exited with 137, or the recorded write error when there is one.These are printed instead of a completed turn, so the work did not happen.
Matched provider-agnostically (the wording comes from the model API, not any
one CLI's chrome) and bounded to the live tail, so an error the operator
already dealt with does not flag the row forever.
session nobody had used. Now
✓ … finished — read and release.to generic permission wording when a narrow pane reflows it.
The
⚠badge and the rail rows had drifted apart: the rail flags a harness thecount knew nothing about, so a badge could read zero above a blinking rail. Both
now answer from one
row_cue. A completed session is deliberately shown butnot counted — nothing is held up while it waits, and a badge that ticks up on
every successful task is a badge you learn to ignore.
Notes for review
●is kept for running-but-idle. The only new glyph vocabulary is thespinner; rewriting the one symbol operators already know, to say nothing new,
seemed a bad trade.
harness's last frame cannot be answered, and a row that keeps asking is a row
nobody can clear.
Themeholds the pulse in whole milliseconds so it staysEq(it is comparedacross the render tests); seconds are the config and UI unit.
Validation
cargo test --workspace— 4438 passed, 0 failedcargo clippy --all-targets -- -D warnings— cleancargo fmt --check— cleanclaudeandcodexunder tmux: the spinner advancesduring a turn and settles to
●; a Codex trust dialog produced⚠ codex · unmanagedwith anAgents ⚠1badge; ANSI capture showed the rowalternating SGR
1/2in yellow, and speeding up after setting 0.3s inSettings — which landed in the config as
attentionBlinkSeconds = 0.3.Rebased on
main(bcfb679a), resolving two doc conflicts against theconcurrent status-line settings work.
Summary by CodeRabbit