Windows TUI missing shaded background for user input (no tint)

Open 💬 7 comments Opened Jan 7, 2026 by FBakkensen

Summary
On native Windows terminals (PowerShell), the Codex TUI does not render the shaded background/tint for user input blocks and transcript items. The same UI on Linux/macOS shows a distinct background for user input ("chat box" look). Unicode box‑drawing characters render correctly, but the background color never appears on Windows.

Steps to reproduce

  1. Run codex on native Windows (PowerShell).
  2. Observe the input area and user prompt blocks in the transcript.

Expected
User input blocks and the input area should have a subtle shaded background (as seen on Linux/macOS).

Actual
No background tint on Windows; only text and borders are shown.

Environment

  • OS: Windows (native)
  • Shell: PowerShell (pwsh)
  • Terminals tested: Windows Terminal, VS Code terminal, Alacritty (same result)
  • Codex version: 0.79.0 (Windows screenshot)

Notes
This looks like a Windows‑specific rendering limitation in the TUI color pipeline: user_message_style() relies on terminal_palette::default_bg() to compute a blended background, but default_bg() returns None on Windows (default color query is compiled out). As a result, user message styles fall back to no background on Windows.

<img width="1426" height="547" alt="Image" src="https://github.com/user-attachments/assets/b647659c-6ca6-4446-a166-423b9afd8cba" />

<img width="1635" height="1177" alt="Image" src="https://github.com/user-attachments/assets/8b9684f1-3980-4628-a55d-cfd4ecb07cbb" />

View original on GitHub ↗

7 Comments

dmilewski · 5 months ago

can you fix it, it's very annoying

0xble · 4 months ago

I think this is the same bug family as the remote and mosh fallback-background issues, just showing up on Windows.

The core failure mode seems to be that user_message_style() ends up with no usable background when the terminal's default palette can't be queried. In my fork, the fix that helped was to always provide a semantic fallback panel background in that case instead of letting it collapse to no tint. I also found it worked better to use COLORFGBG only to decide dark vs light fallback, not as the exact panel RGB.

That suggests a pretty reasonable upstream shape here:

  • if the default terminal background is unavailable, still render user/composer panels with a stable shaded fallback
  • keep that fallback semantic rather than tying it to exact queried RGB values

Reference implementation from my fork:

tbcarver · 3 months ago

I confirmed with the latest codex version that the text box shading doesn't work on cmd, power shell, wezterm (on windows) but does work in windows terminal.

Getting this fixed would be amazing! Thanks.

jacobhallgren · 3 months ago

Quick update from a deeper dive on this — turns out there are two bugs stacked on top of each other, and fixing only one leaves the symptom. I've pushed a working patch to my fork in case it's useful: https://github.com/jacobhallgren/codex/tree/fix/win-tui-bg

Root cause

Stage 1 — tui/src/style.rs

user_message_style_for(None) falls through to Style::default() and never sets a bg. default_bg() returns None on Windows because the OSC 11 query path is gated #[cfg(all(unix, not(test)))].

Stage 2 — tui/src/terminal_palette.rs

Even with a bg color passed in, best_color() returns Color::default() on Windows shells without COLORTERM. They surface as Ansi16 from supports_color, which falls into the else branch.

Both stages are required — confirmed by patching them in isolation:

  • Stage 1 only → still no tint (best_color downgrades to default).
  • Stage 2 only → still no tint (no bg color is requested in the first place).
  • Both → tint renders correctly.

Fix

  • style.rs: in the None arm, fall back to a new fallback_default_bg() helper that picks dark/light from COLORFGBG (rxvt convention) rather than hardcoding. Same fix applied to proposed_plan_style_for.
  • terminal_palette.rs: stdout_color_level() promotes WT_SESSION and known TERM_PROGRAM values (vscode, WezTerm, Hyper, Tabby) to TrueColor when COLORTERM isn't set. FORCE_COLOR still defers to supports_color if explicitly set.

Mirrors the precedent from #13037 and #13016 — same pattern, different consumer.

@0xble's suggestion above (use COLORFGBG for dark/light selection rather than as a literal panel RGB) is what fallback_default_bg() does. @tbcarver's WezTerm-on-Windows datapoint is covered by TERM_PROGRAM=WezTerm.

Verified

| Terminal | Tint? |
|---|---|
| Windows Terminal | ✓ |
| VS Code integrated terminal | ✓ |
| WezTerm on Windows | ✓ |
| Bare conhost.exe / powershell.exe directly | ✗ (legitimately reports Ansi16; could be a follow-up) |

Light-theme branch verified by setting COLORFGBG=0;15 before launch.

Diff size: 2 files, 44 insertions, 8 deletions, no new dependencies. Targeted tests pass (cargo test -p codex-tui --lib style:: and --lib diff_render::).

Previous attempt #4865 took a much heavier Windows-native route (327-line palette, new dependency); intentionally avoiding that here.

Happy to open a PR per CONTRIBUTING.md if a maintainer wants to invite. Otherwise the branch above is public and the diff is small enough to be picked up under another author if that fits the workflow better.

bowuL · 2 months ago

I've investigated this issue in detail and identified the root cause. Here's my analysis:

Root Cause

In codex-rs/tui/src/terminal_probe.rs, the Windows default_colors() function tries two approaches:

  1. OSC 10/11 escape queries — sends \x1B]10;?\x1B\\ and \x1B]11;?\x1B\\ to stdin, reads response from stdout
  2. GetConsoleScreenBufferInfoEx fallback — reads color table from the console screen buffer

Both fail when Codex runs through Git Bash, MSYS2, or WSL interop because stdin/stdout are pipes, not real console handles:

  • OSC queries fail: can't read terminal responses from a pipe
  • Console API fails: GetConsoleScreenBufferInfoEx requires a real console handle

This causes default_bg() to return None, and user_message_style() in style.rs falls back to Style::default() (no background).

Proposed Fix

terminal_probe.rs: When both OSC and console-API probes fail on the standard output handle, retry by opening CONOUT$ directly. CONOUT$ always refers to the active console screen buffer regardless of how the process was started, so GetConsoleScreenBufferInfoEx can read the color table even when stdout is a pipe.

style.rs: Add a fallback gray (RGB 230, 230, 230) so user messages always have a visible background if every detection path returns None.

I have a working branch with this fix. And finished test for it. Display effect very simple and clean, conforming to the current theme

<img width="1015" height="219" alt="Image" src="https://github.com/user-attachments/assets/07087cc2-f9ac-4f59-92f4-46c95c35b283" />

zen0wu · 2 months ago

adding a data point: when using mosh on a remote server (not related to windows), codex cursor lost its background, and the change above proposed by @bowuL did fix it.

<img width="924" height="449" alt="Image" src="https://github.com/user-attachments/assets/79fc1d8b-6f26-4ced-a8e6-8b6468a1fce5" />

here's the patch in case it's useful

fix-mosh-bg.patch

iZerat · 24 days ago

There are similar issues in JetBrains Rider as well.

In Windows Terminal: the user input block DOES render a background tint (correct).
In JetBrains Rider's embedded terminal: no background tint at all — user prompts and the input area blend into the transcript, hard to distinguish.

So on my machine the bug is inconsistent across Windows terminals: Windows Terminal works, but JetBrains terminals don't.

<img width="1128" height="503" alt="Image" src="https://github.com/user-attachments/assets/dfafc71e-119e-4aaa-991b-769208db902a" />