Status indicator redraws at 32 ms while only waiting on a background terminal
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Quiet
- Tech stack
- rust
- Domain
- cli, performance
Research direction
Start in codex-rs/tui/src/status_indicator_widget.rs at StatusIndicatorWidget::render, then inspect ChatWidget::on_terminal_interaction and the shared waiting-state header. Preserve the 32 ms interval for active turns while using a 200 ms interval for the background-terminal waiting state, and ensure the indicator no longer redraws at full rate while idle.
Written by the indexing model from the issue text.
Description
Summary
The TUI status indicator schedules a new animation frame every 32 ms whenever animations are enabled, including while the agent is only waiting on a background terminal and has nothing to animate.
Reported downstream by @rebroad with measurements and a tested patch: DioNanos/codex-termux#16. The analysis and the numbers below are his; I am filing here because the code is upstream's and the contributing policy asks for an issue rather than a pull request.
Measurement
On Android/Termux, roughly 30% CPU in the codex-main thread while waiting for a separate rustc process. The compiler was not a child of the TUI process — the CPU was the redraws themselves, at about 31 frames per second with nothing changing on screen.
Root cause
StatusIndicatorWidget::render in codex-rs/tui/src/status_indicator_widget.rs:
if self.animations_enabled {
self.frame_requester
.schedule_frame_in(Duration::from_millis(32));
}
The interval does not depend on what the indicator is showing. The Waiting for background terminal state, set by ChatWidget::on_terminal_interaction while polling background output, animates at the same rate as an active turn.
Outline of a fix
The original suggestion was a flat 200 ms. That also slows the indicator while the model is working, so a narrower version keys off the state:
let interval = if self.header == WAITING_ON_BACKGROUND_TERMINAL_HEADER {
Duration::from_millis(200)
} else {
Duration::from_millis(32)
};
self.frame_requester.schedule_frame_in(interval);
About 5 fps for a waiting indicator and an elapsed-time display, unchanged everywhere else. Making the header label a shared constant, used both where the state is set and where the rate is chosen, keeps the two from drifting.
Battery and thermal cost is most visible on phones, but the idle redraws are not platform-specific.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.5k
- Avg merge
- 1m
- Merged PRs (30d)
- 1k
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from openai/codex
-
enhancement remote
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
bug CLI windows-os
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
macOS sandbox blocks hw.optional.arm64 sysctl, causing Flutter to misdetect Apple Silicon as x64 Openbug CLI sandbox
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
bug CLI TUI
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
-
CLI config enhancement skills
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
kwakseongjae/auto-hwp#319 ·
-
area:cli bug filter-quality good first issue priority:medium
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
-
Difficulty 1/5 Under an hour Newbie friendliness 72/100
bevyengine/bevy#25861 ·
-
comp-datalake
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
ClickHouse/ClickHouse#121222 ·
-
A-linter
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
oxc-project/oxc#26863 ·