Windows Terminal detection via WT_SESSION changes TUI background from white to black
Summary
On Windows, Codex CLI renders with a black background when launched inside Windows Terminal, but renders with a white background when WT_SESSION is absent.
The key point is that the terminal host itself does not need to change: removing only the WT_SESSION environment variable inside the same Windows Terminal session changes Codex from black to white.
Environment
- Codex CLI:
0.147.0 - Installation: npm
- OS: Windows 11 Pro (
10.0.26200) - PowerShell:
7.6.4 - Windows Terminal / ConPTY when reproducing the black rendering
Reproduction
- Open PowerShell 7 in Windows Terminal.
- Run:
codex
- Codex renders with the undesired black background.
- Exit Codex.
- In the same Windows Terminal tab, run:
Remove-Item Env:WT_SESSION -ErrorAction SilentlyContinue
codex
- Codex now renders with the expected white background.
codex doctor --json difference
With the normal Windows Terminal environment:
WT_SESSION: present
terminal: Windows Terminal
After removing only WT_SESSION:
WT_SESSION: absent
terminal: unknown
Other terminal characteristics remain effectively the same, including stdin/stdout/stderr being terminals and VT processing being enabled.
Additional checks
I also compared the Win32 console color information returned by GetConsoleScreenBufferInfoEx() between:
- Windows Terminal -> PowerShell 7
- directly launched
pwsh.exe-> conhost
Both returned the same values:
wAttributes : 0x0007
Foreground : index 7 -> #CCCCCC
Background : index 0 -> #0C0C0C
The full 16-entry ColorTable was also identical in both cases.
This suggests the behavior is not caused by a different Win32 console color table. The observable switch is tied to Codex detecting Windows Terminal through WT_SESSION.
Expected behavior
Codex should render consistently in Windows Terminal regardless of whether WT_SESSION is present, or terminal detection should not change the TUI background in this way.
Actual behavior
WT_SESSIONpresent -> Codex detectsWindows Terminal-> black renderingWT_SESSIONremoved -> Codex reports terminal asunknown-> white rendering
The same Windows Terminal tab can be used for both cases; only the environment variable is changed.
6 Comments
Additional findings from testing on Codex CLI 0.147.0:
Windows Terminal is visually using a light profile (
Catppuccin Latte, opacity 100%, Acrylic off), but the legacy Win32 console state exposed byGetConsoleScreenBufferInfoEx()reports:With that state, launching
codexproduces the dark/black composer background.If I change only the PowerShell RawUI colors before launching Codex:
then
GetConsoleScreenBufferInfoEx()changes to:Launching
codexfrom the same Windows Terminal session then produces a light composer background. The Windows Terminal profile itself is unchanged.This suggests the key mismatch is between the background actually rendered by Windows Terminal and the legacy Win32 console attributes that Codex can see. The
#0C0C0Cvalue is not the visible Catppuccin Latte background; it is the legacy console background attribute.I also think
WT_SESSIONitself is still useful for detecting TrueColor capability, so simply removing theWT_SESSION -> TrueColorpromotion could regress Windows Terminal color rendering. The problematic combination appears to be:WT_SESSIONpromotes output to TrueColor, so Codex emits an explicit RGB background.A possible fix would be to preserve the TrueColor capability promotion while avoiding use of the legacy Win32 console background as an authoritative semantic background under Windows Terminal, or otherwise distinguish terminal color capability from background-color reliability.
Narrowing from
main@ 1f41cc5d92 —WT_SESSIONgates two coupled things, and your same-tab toggle flips both:WT_SESSIONpresent → unconditional truecolor promotion (tui/src/terminal_palette.rs#L52-L70); absent → thesupports-colorresult stands, typically ANSI-16 on Windows. At ANSI-16 Codex leans on the terminal's default colors (your white); at truecolor it renders explicit RGB, including painted region backgrounds.default_bg()/set_default_colors_from_startup_probe). Styles fall back to unpainted when the probe returnsNone(style.rs#L35-L41), so a black full-background means the probe returned a dark value in the WT_SESSION path — most plausibly a ConPTY/OSC-11 answer that doesn't match your visible theme.Discriminator you can run in the same tab:
printf '\x1b]11;?\x07'with and withoutWT_SESSIONset, and compare the RGB reply against what Codex paints. If the reply is your actual (light) background but Codex shows black, the probe plumbing is at fault; if the reply itself is dark, WT/ConPTY is misreporting and Codex should sanity-check probe results against rendering (or preferColor::Resetinheritance for large fills). Either way, decoupling "terminal can do truecolor" from "paint backgrounds from probed colors" — promoting color depth without switching background strategy — would stop an env-var toggle from changing the entire theme.Thanks — the decoupling point matches what I’m seeing as well. One correction on the likely background source, though: on current
main, the Windows implementation does not appear to consume OSC 10/11 fordefault_colors(). It explicitly usesGetConsoleScreenBufferInfoEx()instead, with the comment that reading OSC replies from the Windows console input queue can discard composer typeahead.That lines up with the local experiment here: changing only the Win32 RawUI attributes changes
GetConsoleScreenBufferInfoEx()fromto
and Codex’s composer changes from dark to light accordingly, while the Windows Terminal profile itself remains unchanged.
So for this case, the dark semantic background seems to be coming from the legacy Win32 console buffer state rather than an OSC-11 reply. An OSC-11 check could still be useful to compare what Windows Terminal considers its real default background, but it does not look like the current Windows Codex path is using that value.
That makes the proposed separation look even more appropriate: keep
WT_SESSIONfor truecolor capability, but avoid treating the legacy Win32 console background as authoritative for semantic/painted backgrounds when running under Windows Terminal.Additional 0.148.0 regression data point from native Windows Terminal + PowerShell:
0.147.0appeared to render the composer text correctly with the same terminal/profile configuration.0.148.0, the composer gets a dark background while typed text is also dark, making the input nearly unreadable.iTerm2 Tango Light.#000000, background#FFFFFF, ANSI black#000000.tui.theme = "inspired-github".This version boundary suggests that 0.148.0 introduced or exposed a composer foreground/background selection regression on Windows Terminal light schemes. The terminal profile itself was unchanged between the two Codex versions.
I compared
rust-v0.147.0andrust-v0.148.0, and the 0.148.0 regression appears to line up very closely with PR #38641 (Harden TUI startup input handling).In 0.147.0, the Windows
default_colors()path first queried OSC 10/11 and used the returned RGB values when available, falling back toGetConsoleScreenBufferInfoEx()only if the OSC probe failed.In 0.148.0, the Windows OSC path was removed to avoid consuming the console input queue (and potentially losing composer typeahead), so the Windows implementation now goes directly to
GetConsoleScreenBufferInfoEx().The input-safety goal of #38641 makes sense and should probably be preserved. The problem is that under Windows Terminal, the legacy Win32 console attributes returned by
GetConsoleScreenBufferInfoEx()are not necessarily the colors actually rendered by the active Windows Terminal profile.In my environment, Windows Terminal is visibly using a light profile, while the Win32 console state reports:
Changing only the RawUI/Win32 background attributes to the light side changes that value to:
and Codex's composer switches from dark to light, even though the Windows Terminal profile itself is unchanged.
This also provides a plausible explanation for the new 0.148.0 report above: an environment where 0.147.0 successfully got the actual light background via OSC could become dark in 0.148.0 once the OSC path is removed and the legacy Win32 background becomes the only source.
I also checked
style.rs; the composer background calculation itself is unchanged between 0.147.0 and 0.148.0. That makes the Windows default-background acquisition change look like the more likely version-boundary regression.I would not suggest reverting #38641 and reintroducing unconditional Windows OSC reads. A safer fix seems to be to separate terminal color capability from painted-background trust:
WT_SESSION -> TrueColorcapability detection, so syntax/diff rendering does not regress.GetConsoleScreenBufferInfoEx()as authoritative for large semantic/painted regions such as the composer.Color::Reset/ no explicit background) rather than painting an RGB derived from the legacy console palette.Conceptually, something like:
with painted UI styles using
painted_region_bg()instead of rawdefault_bg().Longer term, it may be cleaner for
DefaultColorsto retain the source as well as the RGB values, e.g.:Then an OSC-derived background can continue to be used normally, while a legacy Win32 value under Windows Terminal can be treated as non-authoritative for semantic fills.
A regression test could cover the case
WT_SESSION+ Windows Terminal + legacy Win32 background#0C0C0Cand assert that the composer does not end up with an explicit dark RGB background when that value is only coming from the legacy console buffer.Still present on stable
codex-cli 0.150.1(Windows Terminal 1.24.11911.0, Windows 11 10.0.26200, PowerShell 7.6.5, light theme).0.147.0remains the last good version in the same profile.Opened a 0.150.1 confirmation with the 0.148 OSC-drop vs
GetConsoleScreenBufferInfoExsource comparison: https://github.com/openai/codex/issues/41242Note that #39418 was closed as completed, but
rust-v0.150.1still only usesGetConsoleScreenBufferInfoExon Windows and never restores OSC 10/11.