TUI: startup-only palette cache leaves input unreadable after system light/dark changes (0.154.0)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of Codex CLI is running?
codex-cli 0.154.0. The startup-only cache is also present in upstream main at a592c38c16cdd7623dacc9168926ebccedfb67d3.
What subscription do you have?
Not relevant to this terminal-rendering issue.
Which model were you using?
Model-independent; observed in long-running Codex CLI sessions.
What platform is your computer?
macOS, Darwin 25.6.0, arm64.
What terminal emulator and version are you using?
CodePress Terminal, a Tauri/xterm.js host configured to follow the system light/dark appearance. The host updates its terminal palette and answers OSC 10/11 queries. Exact host release not recorded.
What issue are you seeing?
After the terminal changes between light and dark appearance while Codex is already running, the composer and previously rendered user-message blocks retain their old background colors. The terminal's default foreground updates, producing nearly white text on a pale background (or the inverse mismatch). Long-lived sessions become unreadable after an automatic macOS appearance change.
Refocusing and redrawing do not refresh the cached palette. Restarting/resuming refreshes the startup colors, but the next appearance change can break the session again.
This follows up my earlier report #37298, which described a failed refresh permanently poisoning the color cache in 0.146.0. The current implementation has a different failure mode: focus-driven refresh has been removed entirely, so no transient failure is required.
What steps can reproduce the bug?
- Configure a terminal to follow macOS system appearance and start Codex while the terminal is light.
- Send a message so both a user-message block and the composer are visible.
- Change macOS appearance to dark without restarting Codex, or leave the process running across the automatic appearance change.
- Refocus the terminal and type in the composer.
- Observe that the terminal's normal foreground/background have changed but the composer/message backgrounds retain the light-theme color. Repeat dark to light as well.
A terminal host can verify the distinction by recording OSC 10/11 requests: the current focus handler intentionally does not send a new pair on focus regain.
What is the expected behavior?
Codex should adapt its palette-dependent rendering when the terminal's colors change, without restarting the process, losing draft text, dropping/reordering keys or pasted input, or inserting terminal replies into the composer.
Root cause and relevant change
PR #35649, merged July 27, intentionally removed focus-time palette queries because they could block the input loop and discard keystrokes. That input-preservation fix is important, but it also leaves a long-lived TUI unable to adapt to system appearance changes.
Source at the inspected commit:
terminal_palette.rs: the process-global cache stores the startup foreground/background;attemptedprevents re-querying throughdefault_colors().tui/event_stream.rs:FocusGainedexplicitly preserves the startup-cached palette and only returns the focus event.style.rs: user messages get an explicit derived background without a paired explicit foreground. When the terminal's default foreground changes, the old explicit background remains.terminal_probe.rs: the existing Unix color probe uses a direct reader. Itsread_untilhelper explicitly does not replay unrelated input, so simply calling this again from the focus handler would reintroduce the reason for #35649.
Proposed approach
Please restore runtime palette refresh through the normal terminal input/event path rather than reinstating the old synchronous raw-input probe:
- Request OSC 10/11 asynchronously on focus regain as a compatibility fallback. Also support a terminal theme-change notification so a theme switch while the terminal stays focused can refresh the palette; #38575 tracks DECSET 2031 for that case.
- Parse replies through the existing input owner, preserving ordinary keys, bracketed paste, and fragmented/late replies. Coalesce repeated refresh triggers and keep only one bounded refresh outstanding; never wait on terminal replies in the UI input handler.
- Commit a complete valid foreground/background pair atomically. On timeout or malformed/partial replies, preserve the last known good palette and allow a later retry, avoiding #37298's poisoned-cache behavior.
- Invalidate palette-dependent render caches and repaint the composer and affected transcript content when colors actually change. Preserve an explicitly chosen syntax-highlighting theme.
- Preserve startup trust/confirmation protections and terminal ownership during external-editor handoff and suspend/resume; a refresh must not start a second competing stdin reader.
Suggested regression coverage: both light/dark directions in the same process; theme changes without a focus transition; repeated focus notifications; immediate, delayed, fragmented, missing and partial OSC replies; a failed refresh followed by a successful one; typing and bracketed paste during refresh; unchanged draft and input ordering; and recoloring existing visible user-message blocks, not only newly generated output.
Workaround
Launching a new process with FORCE_COLOR=1 codex selects Codex's basic-color fallback, which uses the default/reset color for the derived composer background. This is source-backed, not an interactive validation from this investigation, and sacrifices richer colors. Restarting normally only fixes colors until the next theme change. /theme controls syntax highlighting and does not invalidate this palette cache.
Related issues
- #37298 — my earlier report: one failed requery permanently disabled future refreshes.
- #14105 — composer readability after a live terminal theme switch.
- #38575 — theme-change reporting without a focus transition.
- #18942 — related focus/theme refresh discussion.
- #35649 — intentional removal of focus queries to preserve input.
This report adds the 0.154.0 observation and the current startup-only-cache diagnosis, linking the earlier reports rather than treating this as an unrelated color preference. Per the current contribution policy, I am including the implementation constraints and regression cases here for the maintainers.
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.
Research direction
Start with terminal_palette.rs, tui/event_stream.rs, style.rs, and terminal_probe.rs to understand the startup cache, focus handling, rendering backgrounds, and input ownership. Trace how palette replies and refresh triggers can be handled without a competing reader or blocking input. Done means live theme changes refresh valid colors and affected content while preserving draft text, key ordering, paste input, and retry behavior after failed replies.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100