fix(terminal): let Claude use truecolor so its themed backgrounds render - #409
Draft
irisitymichaelgrundberg wants to merge 2 commits into
Draft
Conversation
Claude draws the user's own messages as a block of background color, and inside a Codeman pane that block was invisible. tmux hands each pane TERM=screen, which supports-color reads as 16 colors, and Claude's registry entry deleted COLORTERM on top of that. Claude therefore quantized every RGB color its theme asked for down to the basic palette, where rgb(55, 55, 55) and every other dark background becomes ESC[40m, the terminal's own black. Changing the color in a custom Claude theme moved nothing on screen. Claude now exports COLORTERM=truecolor and unsets NO_COLOR, matching codex, gemini, antigravity, pi, grok and omp. CLAUDECODE stays unset, because Claude reads it as a signal that it is running nested inside itself. Both the tmux session and the attach client read this one registry entry, so they cannot disagree. PR Ark0N#3 introduced the unset in February, citing xterm.js#484 for the claim that xterm.js mishandles truecolor. xterm.js closed that issue in April 2019, Codeman now depends on @xterm/xterm 6, and TmuxManager already sets terminal-overrides ",*:Tc" on its own tmux server, so 24-bit color reaches the browser today for every CLI that asks for it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…pawn path
buildClaudeEnv(), the direct-PTY fallback taken when mux creation fails, now
reads getCli('claude').env and applies its unset and exports lists. It used to
delete COLORTERM and CLAUDECODE from a hand-maintained list of its own, which
left it contradicting the registry entry that the tmux pane and the attach
client both read. An engine value needing a mux name has nothing to resolve
against on this path, so it is skipped rather than guessed.
Claude no longer unsets NO_COLOR. The invisible-background bug does not need
it, and unsetting it overrides a preference the user set deliberately, so a
user who exports NO_COLOR globally keeps monochrome panes. The other seven
truecolor CLIs still unset it; that inconsistency is intentional and the
comment on the entry says so.
The invariants doc gains a Terminal colour env paragraph under Session launch
modes, where a reader looking up Claude will find it — the previous sentence
sat under a heading that lists only the non-Claude CLIs. It now says the lists
are the stock catalog and a clis.json override replaces them wholesale, and
that the declarations reach the tmux pane, its attach client and the direct
PTY but not a remote pane, whose command carries no env exports at all. Docker
hands COLORTERM=truecolor to every mode, including the two the registry says
must unset it.
The changeset named six peer CLIs and there are seven: deepseek also exports
truecolor. A test beside the existing OpenCode assertion pins the new
behaviour, so a future registry edit cannot make the backgrounds vanish again
in silence.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Claude draws the user's own messages as a block of background color. Inside a Codeman pane that block is invisible, and no Claude theme can change that. This exports
COLORTERM=truecolorfor Claude, which is what the other seven CLIs already do.The problem
Two things combine. tmux hands each pane
TERM=screen, whichsupports-colorreads as 16 colors, and Claude's registry entry deletedCOLORTERMon top of that. Claude then quantizes every RGB color its theme asks for down to the basic palette.Measured with the
chalkversion Claude bundles, at 16 colors:rgb(55, 55, 55)(built-in dark)ESC[40mrgb(28, 48, 84)(a custom theme)ESC[40mrgb(240, 240, 240)(built-in light)ESC[47mEvery dark background lands on
ESC[40m, so the block is emitted and paints the terminal's background over itself. Claude's*-ansithemes work, because they name colors likeansi:blackBrightand skip the conversion entirely.Detected levels, same library:
TERMCOLORTERMscreenscreentruecolorWhy this reverses #3
#3 added
unset COLORTERMin February, reporting that truecolor caused "gray/white backgrounds appearing where they shouldn't" in xterm.js, and citing xtermjs/xterm.js#484. Three things have changed or were already true:@xterm/xterm^6.0.0, which renders 24-bit color.TmuxManagersetsterminal-overrides ",*:Tc"on its own tmux server (src/tmux-manager.ts), so 24-bit color already reaches the browser for the CLIs that ask for it.I want to flag one reading honestly, because I cannot prove it. Suppressing truecolor makes Claude's dark block collapse into the terminal background and disappear. If that is what the reporter saw go away, then the symptom was Claude's user-message block working as designed, not an xterm.js defect.
Changes
src/config/cli-registry/stock.ts— Claude's entry exportsCOLORTERM=truecolor.CLAUDECODEstays unset.src/session-cli-builder.ts—buildClaudeEnv(), the direct-PTY fallback taken when mux creation fails, now reads the same registry entry as the tmux pane and its attach client. It previously deletedCOLORTERMfrom a hand-maintained list of its own, which would have left the fallback contradicting the entry.docs/architecture-invariants.md— a Terminal colour env paragraph under Session launch modes, where a reader looking up Claude will find it. The sentence it replaces sat under a heading listing only the non-Claude CLIs.test/tmux-manager.test.ts— pins the new behaviour beside the existing OpenCode assertion.Claude does not unset
NO_COLOR, unlike the other seven truecolor CLIs. The bug does not need it, and unsetting it would override a preference the user set deliberately. The inconsistency is intentional and the entry's comment says so.An SSH-remote pane is not covered.
buildRemoteLaunchCommand()carries no env exports at all, so a remote Claude session keeps the old rendering. That predates this change, and the invariants doc now states it rather than implying every pane is covered. Docker panes takeCOLORTERM=truecolorfrom the hardcodedenvCreate/execEnv, which apply to every mode including the two the registry says must unset it — also pre-existing, also now documented.Verification
npm test— 6870 passed, 12 skipped, 0 failed.npm run typecheck,npm run lint,npm run format:check,npm run check:frontend-syntaxall clean.expected [...] to include 'export COLORTERM=truecolor'.buildClaudeEnv()withNO_COLOR=1andCLAUDECODE=1in the parent env: returnsCOLORTERM=truecolor, noCLAUDECODE, andNO_COLORpreserved.buildEnvExportsagainst a build: a Claude pane emitsunset CLAUDECODE,export COLORTERM=truecolor. OpenCode still emitsunset COLORTERM, unchanged.🤖 Generated with Claude Code