Do not rely on startup OSC probing for the composer background
What version of Codex CLI is running?
codex-cli 0.131.0
What subscription do you have?
ChatGPT Pro 20x
Which model were you using?
gpt-5.5
What platform is your computer?
Linux 6.8.0-90-generic x86_64 x86_64
What terminal emulator and version are you using (if applicable)?
iTerm2 (ssh)
Codex doctor report
What issue are you seeing?
Codex uses startup OSC 10/11 probing to detect terminal colors for the TUI composer background. This is unreliable over SSH because the response has to round-trip through the local terminal emulator.
Relevant code:
- Startup probe timeout is 100ms:
codex-rs/tui/src/terminal_probe.rs
``rust``
pub(crate) const DEFAULT_TIMEOUT: Duration = Duration::from_millis(100);
- Default colors require both OSC 10 and OSC 11:
``rust``
fn parse_default_colors(buffer: &[u8]) -> Option<DefaultColors> {
let fg = parse_osc_color(buffer, /*slot*/ 10)?;
let bg = parse_osc_color(buffer, /*slot*/ 11)?;
Some(DefaultColors { fg, bg })
}
- Composer background depends on user_message_style():
``rust``
pub fn user_message_style_for(terminal_bg: Option<(u8, u8, u8)>) -> Style {
match terminal_bg {
Some(bg) => Style::default().bg(user_message_bg(bg)),
None => Style::default(),
}
}
In my SSH session, OSC 10/11 are supported, but the responses always arrive after 100ms. As a result, the composer background appears locally, but disappears when running Codex over SSH.
<img width="596" height="250" alt="Image" src="https://github.com/user-attachments/assets/5e93503d-90f6-4ec3-95c7-fb1f3339007f" />
Please consider removing this startup probe as a hard dependency for the composer background. Possible alternatives:
- use a theme/default composer background without probing;
- probe asynchronously and update later;
- retry instead of caching failure;
- allow users to configure the composer background.
Increasing the timeout would help some cases, but the core issue is that fixed startup OSC probing is fragile over SSH.
What steps can reproduce the bug?
- Run Codex on the remote machine.
- Observe that the composer/input background is missing.
The bug is reproducible when OSC 10/11 are supported but the response arrives after Codex's 100ms startup probe timeout.
What is the expected behavior?
_No response_
Additional information
_No response_
5 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
I think this issue also has a more severe startup-input failure mode than missing composer background colors.
I can reproduce a case where Codex exits before the user can interact with startup dialogs, including the project trust selector and session selector, when started inside GNU screen running under rxvt-unicode (
urxvt). The same Codex build works when started directly inurxvt, and it also works inxtermboth with and without GNU screen.Reproduced with:
bullseye)Linux 5.10.0-44-amd64 x86_64codex-cli 0.141.0$HOME/.nvm/versions/node/v20.20.0/bin/codexurxvt)v9.22, released 2016-01-234.08.00, released 2020-02-05The same Codex CLI version is interactive when run directly in the same
urxvtwindow without GNU screen. In the same local environment,xtermalso works both with and without GNU screen (xtermreportedXTerm(366)in the captured environment).Relevant environment from the working direct-
urxvtrun:Relevant environment from the failing
urxvt + screenrun in the same window:CODEX_TUI_DISABLE_KEYBOARD_ENHANCEMENT=1was an early negative-control test in this specific environment. The goal was to check whether Codex's keyboard enhancement path was responsible for the observed input problem. The failure still reproduced with keyboard enhancement disabled, and the laterstracecomparison pointed instead to delayed terminal response bytes from the startup OSC 10/11 default-color probe. I included the variable above only because it documents that the keyboard-enhancement path was evaluated and did not explain this failure.The failure mechanism appears to be in the startup OSC 10/11 default-color probe, not in the dialog code itself.
From strace comparison between the failing
urxvt + screenrun and a working direct-urxvtrun:ESC \).urxvt + screenpath, Codex reads the cursor response and an incomplete OSC 11 body before the bounded startup-probe timeout expires.ESCbyte to input.Escapeas cancel/quit, so Codex exits immediately before the user can select anything.This is related to this issue because it is another consequence of relying on startup OSC probing with a short deadline. The symptom is different from the composer background disappearing: the delayed terminal response leaks into the interactive input stream and triggers an actual dialog action.
I tested a minimal local fix that keeps the OSC 10/11 default-color probe but terminates those queries with BEL (
\x07) instead of ST (ESC \). The parser already accepts both BEL and ST responses. With BEL termination, the sameurxvt + screenstartup trust selector becomes interactive again in my environment.This also matches existing precedent in the repository: PR #18261 changed terminal title OSC updates from ST to BEL because an ST terminator could leak through terminal integrations. This startup color-probe case appears to be the same class of robustness issue, but on the input side of startup probing.
Related context:
10;rgb/11;rgbtext entering input and were closed as fixed by older work.The focused patch I tested locally changes only the OSC 10/11 query terminator from ST to BEL in the startup default-color probe. It does not disable default-color probing, does not special-case
urxvt, GNU screen, or$TERM, and does not change dialog handling.As per contributing.md, I did not open a PR but you can inspect the patch that I have tested locally within the above described environment
Implementation update for the shared OSC 10/11 subsystem:
The focus fix replaces sequential multi-second Crossterm waits with the existing batched probe under one shared 100 ms deadline, pauses/recreates the event source around that probe, and preserves previously cached colors when refresh times out.
It does not change the startup deadline or solve a missing initial color cache over high-latency SSH. This issue therefore remains the relevant appearance/remote tradeoff when reviewing the bounded focus change.
**Additional data point: intermittent total probe failure over VS Code Remote SSH (not just slow OSC 10/11)**
I'm hitting this on VS Code Remote SSH (Linux,
codex-cli 0.147.0) and want to add evidence for a failure mode that's a bit different from the "OSC responses always arrive after 100ms" case in the original report.Symptom: the composer/UI background is intermittently dark — sometimes light, sometimes dark, across otherwise-identical launches in the same terminal.
Instrumented both sides. I enabled
log_dirto capture codex's ownterminal startup probes completedline, and separately confirmed (via an externalTIOCSTIpre-fill of OSC 10/11 replies before launch) whether a reply was sitting in the tty input queue. Aligned by timestamp:Two observations that I think are new relative to the current thread:
cursor_position,default_colors, andkeyboard_enhancementare simultaneously false and the read window burns the full ~99ms. Cursor position (ESC[6n) is answered by the local terminal and doesn't need an OSC round-trip, so a failure that also loses the cursor response points to the whole read window getting nothing, rather than only the OSC 10/11 reply being slow.05:03:12a full 48-byte OSC 10/11 reply was confirmed present in the tty queue, yet codex still reporteddefault_colors=false. This suggests the fd codex actually reads (it dupsSTDIN) can become decoupled from the terminal that answers queries — notestdoutis not a TTY in this environment (VS Code shell integration wraps it), soSTDINand/dev/ttyare not guaranteed to be the same endpoint.Rough failure rates (small sample, my machine, simulating the same 100ms-bounded probe):
tmux(tmux-256color): 6/6 fail, and they still fail with a 600ms timeout — consistent with tmux not forwarding OSC 10/11 by default.Why this matters for the fix direction: since the failure is intermittent and can survive a correct pre-injected reply, workarounds that race the probe (injecting replies, bumping the timeout) reduce the frequency but can't make it deterministic. In line with this issue's title, it would help to let users declare the background explicitly and skip the probe entirely — e.g. an env/config like
CODEX_TUI_ASSUME_BG=light|dark|<hex>(or atui.assume_backgroundsetting) that seedsdefault_bg()and bypasses startup color detection. That gives remote/multiplexer users a deterministic escape hatch without changing probe behavior for everyone else.Happy to share the raw logs or the probe-simulation script if useful.