Customizable live activity indicator details in the CLI TUI
What variant of Codex are you using?
CLI / TUI, currently 0.145.0 on macOS.
What feature would you like to see?
An opt-in extension point for the live activity indicator row shown while a turn is running. This is separate from the persistent footer configured by /statusline.
This would give users and ecosystem integrations a small surface for timely workflow context while the agent is active, for example:
✦ reviewing changes · task: PROJ-123
Tip: CI passed · 3 files changed · view details
The content disappears when the turn finishes, so it does not occupy permanent footer space. Potential uses include task context, build or test state, repository guidance, extension progress, and short workflow hints.
A safe contract could keep the Codex-owned semantic state intact and expose only an ambient detail/tip below it:
- Never replace meaningful states such as approvals, permission review, retries, errors, MCP startup, or subagent waits.
- Show custom content only during ordinary
Working/Thinking. - Accept static configured tips and/or a user-level command provider.
- Run providers asynchronously with a short timeout, cached last-good output, output length/control-character sanitization, and fail-silent behavior.
- Do not allow project-local configuration to register a command.
- Keep animation and accessibility behavior under Codex control.
I am deliberately not prescribing the final TOML shape before maintainer feedback.
Additional information
I searched the issue and PR history before filing:
- #17827 and its prototypes request a command-backed persistent status line/footer.
- #10170 was an earlier implementation of that footer request.
- The current prototypes from @shenxingy and @L-svg-png also target the footer.
This request targets a different existing TUI surface: StatusIndicatorWidget, which already supports a Codex-owned header plus detail rows. The narrow design above would avoid overloading the persistent status line and would prevent custom text from hiding operational or safety-critical state.
Is this best tracked as a distinct enhancement, or should it be folded into #17827? If the team wants an external implementation, I am happy to coordinate with the existing contributors and wait for an explicit invitation before opening a PR, per the repository contribution policy.
2 Comments
Thanks for splitting this out, and for the constraint list — the "never mask operational state" framing looks right to me.
From the footer side, I'd agree these are better tracked separately, for two reasons that show up in the code:
Lifecycle. The footer's
customitem is persistent and interval-driven, owned byChatWidgetfor the session.StatusIndicatorWidgetis constructed inset_task_running(true)and dropped when the turn ends, so a provider here is turn-scoped and would plausibly want fields the footer payload has no reason to carry (current activity, elapsed time).Ownership. The footer segment has no competing owner. The activity header does —
turn_runtime.rsdrives reasoning headers, MCP startup, guardian review, and retry status, with explicit precedence checks (status_header_is_mcp_startup_owned,clear_guardian_review_status). So the genuinely new design work here is precedence policy: what may render, when, and what it must never mask. That question doesn't exist in #17827, so folding them would merge two different discussions.One implementation note that may help:
StatusIndicatorWidgetalready has a low-risk insertion point ininline_message, which renders after the elapsed/interrupt segment with a comment noting it sits there "so that core interrupt affordances stay in a fixed visual location" — which lines up with your constraint almost exactly.And one gap worth designing in from the start rather than retrofitting: the project-local protection is key-specific, not general.
sanitize_project_configremoves exactlytui.status_line_commandfrom project.codex/layers, so a second command-backed key would need its own entry there or a cloned repo could register it.On shared machinery — between @shenxingy's branch and mine there's already an executor and output sanitizer covering the parts both surfaces need: a single timeout envelope over spawn/stdin-write/wait, kill-on-drop, capped concurrent pipe reads, first-line + ANSI/control/bidi stripping with a length cap, keep-last-good, and a failure circuit breaker. If maintainers pick a direction for the footer, whatever lands there seems worth reusing here rather than reimplementing — and it'd be reasonable to shape it with a second consumer in mind.
Agreed on both counts, and the lifecycle/ownership split states it better than my original filing did. The footer item is session-persistent and interval-driven; this one is built and dropped inside a turn. What only exists here is precedence — what may render, when, and what it must never mask. That has no analogue in #17827.
On the sanitization gap. Good catch, and I'd rather fix the shape than add an entry. If the project-layer strip names one key, every future command-backed key has to re-earn the protection, and the failure is silent — a cloned repo registers a provider and nothing looks wrong. Better to make "spawns a process" a property the config schema carries, and drive the strip off that property instead of a list. A second surface then inherits the protection rather than having to remember it. That changes how
sanitize_project_configdecides, not what it removes today. Worth doing under whichever issue lands first; it makes the second one safe by default.On shared machinery. Yes, and the boundary looks clean. Timeout envelope, kill-on-drop, capped pipe reads, first-line plus control/bidi stripping under a length cap, keep-last-good, circuit breaker — none of that knows which surface it feeds. Precedence and lifecycle do, and shouldn't be shared. If the footer direction lands first I'd rather consume what you and @shenxingy build than fork it, and I'm glad to review it against this surface while it's still shapeable. The turn-scoped case mostly adds "the provider must not outlive the turn," which kill-on-drop already covers.
Rather than ask again which issue this belongs to, I've taken my own suggestion and raised the sanitization point on #17827, since it applies to the footer work regardless of what happens here. Leaving this open as the design record for the turn-scoped surface.
Worth noting the demand for this surface is already in that thread, just filed against the footer: @mark-undoio (2026-07-09) describes exactly the turn-time opacity problem — an integrated tool with no way to show progress while the agent drives it — and @Chengyf2004 (2026-08-03) opens with "I need more than a user-customizable status line" and asks for agent-updated semantic progress during work. Neither wants persistent footer space. That matches your point about the turn-scoped payload wanting current activity and elapsed time: when a turn runs long, the thing users can't currently tell is how long this is going to take and what it's doing.