#1491·opentui

Auto remote detection skips TERM/COLORTERM color depth parsing — monochrome truecolor-only output over SSH

Author: yurialCreated Sep 9, 2026Updated Sep 9, 2026

Summary

In an auto-detected remote session (SSH_CONNECTION/SSH_CLIENT/SSH_TTY/MOSH_CONNECTION present in the forwarded host env), checkEnvironmentOverrides returns early and skips TERM/COLORTERM parsing. Both color caps (caps.rgb, caps.ansi256) stay false, so emitColor falls back to unconditional truecolor SGR (38;2/48;2). Terminals and multiplexers without truecolor support render everything in the default foreground — i.e. a monochrome UI over SSH, while the exact same TERM locally emits 38;5 and renders color correctly.

Observed with OpenTUI 0.4.5 and reproduced on current main (v0.5.11).

Environment

  • Terminal chain: macOS Terminal.app → ssh → GNU screen 4.09 (TERM=screen-256color, COLORTERM unset)
  • Any OpenTUI CLI app using createCliRenderer with default options (e.g. OpenCode): remoteMode unset → .auto; host env is forwarded via DEFAULT_FORWARDED_ENV_KEYS (which includes both the SSH markers and TERM/COLORTERM), so env_is_forwarded is true
  • Client terminal supports 256 colors; the multiplexer passes 38;5 through but drops/garbles 38;2

Reproduction

  1. ssh into a host, start screen (term screen-256color)
  2. Run any OpenTUI-based TUI that renders RGB colors
  3. All themed output is monochrome; a raw capture shows 38;2;r;g;b sequences only
  4. The same app, same TERM, without the SSH marker vars (env -u SSH_CONNECTION -u SSH_CLIENT -u SSH_TTY -u MOSH_CONNECTION ...) emits 38;5;n and renders color

Binary-search evidence (probe on the real renderer, TERM=screen-256color, COLORTERM empty):

Conditions SGR output
no SSH vars 38;5 only
SSH vars present 38;2 only
SSH vars + COLORTERM=truecolor 38;2 only (correct — truecolor requested)

Root cause

packages/native/src/terminal.zig (checkEnvironmentOverrides):

zig
const env_is_forwarded = if (self.host_env_map) |*host_env_map| env_map == host_env_map else false;
self.applyKnownUnicodeWidthIdentity();
if (self.opts.remote_mode == .auto and self.remote and env_is_forwarded) {
    return; // skips TERM "256color" -> caps.ansi256 and COLORTERM -> caps.rgb
}

The early return is there to avoid trusting forwarded terminal identity heuristics (TERM_PROGRAM etc.) in remote sessions — the host env describes the server shell, not the client terminal. But TERM and COLORTERM are different: sshd adopts TERM from the client's PTY request, and the docs for remote mode recommend forwarding exactly ["TERM", "COLORTERM"] as endpoint-describing keys. Skipping them leaves no capability source at all: terminal query responses only ever set rgb (kitty detection), never ansi256, so a 256-color-capable remote terminal is indistinguishable from a dumb one.

Workaround

Strip the SSH marker vars when launching the app:

bash
env -u SSH_CONNECTION -u SSH_CLIENT -u SSH_TTY -u MOSH_CONNECTION <app>

Fix

Apply the color-depth keys (TERM 256coloransi256, COLORTERMrgb) before the early return, keeping the return for the identity heuristics. PR incoming.


Note: this issue was diagnosed and resolved fully by an AI agent (OpenCode, automated mode) — reproduction, root-cause analysis, fix, and tests were produced automatically from the investigation session.