/ 6 min read

Fixing Codex CLI colors over SSH in Ghostty

Codex CLI looked flat over SSH from Ghostty because the Ubuntu devbox did not know xterm-ghostty, and the shell environment was disabling color. This is the setup I use and the fix that made the Codex textbox background render correctly again.

I run most of my coding setup on machines that are not in my backpack.

My daily machine is a MacBook. I travel with it, work from random places, and spend a lot of time unplugged from power. My IP address changes all the time. Some days I am on hotel Wi-Fi, some days I am tethered to my phone, and some days I want to check something from the phone itself without opening the laptop at all.

So I keep the real work somewhere else.

At a fixed place I have a small Ubuntu devbox. I also use a VPS for the same kind of work. Both sit on Tailscale. My laptop and phone connect into that private network, and I SSH into whichever box has the context I need. Codex runs there, not on the device in my hands.

This setup is boring in the best way. My laptop stays cool. Battery lasts longer. My phone can become a thin client when I need it. Long-running sessions do not die because I closed the lid or changed networks. I can leave a Codex session open on the devbox, come back later from a different device, and keep going.

The annoying part was cosmetic, but it was annoying enough to fix.

Codex CLI did not look right over SSH from Ghostty. The app worked, but the styling was off. The most obvious missing piece was the grey background behind the input textbox. Locally, Codex has a nice TUI with shaded areas and clear visual separation. Over SSH, my prompt area looked flat. It was usable, but the whole interface felt half-rendered.

I first blamed Tailscale SSH because that is how I usually connect. Then I tried regular SSH and saw the same thing. That ruled out Tailscale. The problem sat somewhere between Ghostty, SSH, Ubuntu, and Codex's terminal rendering.

The setup

The client side:

  • macOS
  • Ghostty as the terminal
  • SSH or Tailscale SSH into remote machines

The server side:

  • Ubuntu devbox at a fixed place
  • Ubuntu VPS with the same issue
  • Codex CLI installed on the remote machine
  • Bash as the interactive shell

Ghostty sets TERM=xterm-ghostty. That is the right value. The catch is that the remote machine also needs to know what xterm-ghostty means.

Terminal apps read TERM as more than a label. They ask the system's terminfo database what the terminal can do. Colors, background color erase, cursor movement, alternate screen behavior, keyboard handling, mouse support: a lot of that comes from terminfo.

On my Ubuntu box, this failed:

infocmp xterm-ghostty

The output was:

infocmp: couldn't open terminfo file /usr/share/terminfo/x/xterm-ghostty

That was the first real clue. Ghostty was telling the remote machine "I am xterm-ghostty", and Ubuntu was replying "never heard of it."

The first fix: install Ghostty terminfo

Ghostty documents this exact SSH problem. Newer terminal emulators often ship their own TERM value before every remote system has that entry in its terminfo database.

The usual fix is to copy the Ghostty terminfo entry to the remote host:

infocmp -x xterm-ghostty | ssh user@host -- tic -x -

That works when your local machine has the terminfo source available through infocmp. In my case, I was already inside the Ubuntu box while debugging, so I installed the compiled entry on the remote machine instead.

Ubuntu 24.04 did not have xterm-ghostty, even after installing the extended ncurses package:

sudo apt-get install -y ncurses-term
infocmp xterm-ghostty

Still missing.

I pulled a packaged ghostty-terminfo entry and installed the compiled file into my user terminfo directory:

mkdir -p ~/.terminfo/x
install -m 0644 xterm-ghostty ~/.terminfo/x/xterm-ghostty

After that:

infocmp xterm-ghostty >/dev/null && echo terminfo-ok
tput colors

Returned:

terminfo-ok
256

That fixed the remote terminal capability lookup. But Codex still did not look quite right.

The second fix: clean up the SSH environment

The next clue came from printing the color-related environment:

echo "$TERM"
echo "$COLORTERM"
echo "$TERM_PROGRAM"
echo "$NO_COLOR"

I had:

xterm-ghostty


1

TERM was correct. COLORTERM and TERM_PROGRAM were empty. Worse, NO_COLOR=1 was set.

NO_COLOR is not a vague preference. It is a convention that tells command-line programs to disable ANSI color output. If a TUI respects it, backgrounds and styling can disappear. That matched what I saw in Codex.

For Ghostty SSH sessions, I wanted three things:

  • keep TERM=xterm-ghostty
  • set COLORTERM=truecolor
  • unset NO_COLOR

I added this near the top of ~/.bashrc, after the interactive-shell check:

# Ghostty over SSH: make color capability explicit for TUI apps such as Codex.
if [ "${TERM:-}" = "xterm-ghostty" ]; then
    export COLORTERM="${COLORTERM:-truecolor}"
    export TERM_PROGRAM="${TERM_PROGRAM:-ghostty}"
    unset NO_COLOR
fi

Then I opened a fresh SSH session and checked:

echo "$TERM $COLORTERM $TERM_PROGRAM ${NO_COLOR-unset}"
infocmp xterm-ghostty >/dev/null && echo terminfo-ok
tput colors

Expected output:

xterm-ghostty truecolor ghostty unset
terminfo-ok
256

After that, Codex rendered correctly. The grey textbox background came back.

The short version

If Codex CLI looks flat or colorless over SSH from Ghostty, check these on the remote machine:

echo "$TERM"
echo "$COLORTERM"
echo "$TERM_PROGRAM"
echo "$NO_COLOR"
infocmp xterm-ghostty >/dev/null && echo terminfo-ok
tput colors

You want:

TERM=xterm-ghostty
COLORTERM=truecolor
TERM_PROGRAM=ghostty
NO_COLOR unset
tput colors -> 256

Install terminfo if infocmp fails:

infocmp -x xterm-ghostty | ssh user@host -- tic -x -

If you cannot do that, use the downgrade path:

TERM=xterm-256color codex

That avoids the unknown terminal type, but you lose the Ghostty-specific entry. I would rather fix terminfo once and keep the terminal honest.

Why this matters to me

I know this sounds like a small thing. The app worked before. I could still type prompts, read diffs, and run commands.

But I spend hours in Codex now. The TUI is part of the workspace. When the input area loses its background, the interface becomes harder to scan. It feels like the terminal is lying about the state of the app. Tiny visual bugs become friction when you stare at them all day.

The whole point of my devbox setup is that my laptop and phone stay light. I want my devices to act like windows into the same remote workspace, not like machines carrying the whole environment around. SSH should feel local enough that I forget about it.

For Codex in Ghostty, that meant teaching Ubuntu what Ghostty is and making sure the shell was not telling Codex to turn colors off.

Once both were fixed, the setup felt like it should have from the start.

Links

  • Ghostty terminfo docs: https://ghostty.org/docs/help/terminfo
  • Ghostty shell integration docs: https://ghostty.org/docs/features/shell-integration
  • NO_COLOR convention: https://no-color.org/