True Color, Image Protocols and Modern Terminal Features
Configure TERM, COLORTERM, sixel, Kitty graphics, and iTerm2 inline image protocols correctly across Kitty, WezTerm, foot, Alacritty, and tmux.
Before you start
- ▸A modern terminal emulator installed (Kitty, WezTerm, foot, or similar)
- ▸Basic familiarity with shell configuration files (.bashrc, .zshrc)
- ▸tmux 3.3a or later if working inside a multiplexer
- ▸Root or sudo access for package installation
Modern terminal emulators have outpaced the assumptions baked into most shell configs. True color (24-bit RGB), sixel graphics, the Kitty graphics protocol, and inline image support are all real and usable today — but only if your environment variables, terminal settings, and applications are aligned. This guide maps the full picture: what each capability is, how to detect it, and how to configure it correctly.
Understanding the Key Environment Variables
Two variables gate most color behavior. Getting them wrong causes either washed-out 8-color output or garbled escape sequences.
TERM
TERM tells applications which terminfo entry to load. It describes capabilities in a structured database rather than encoding them directly. Common values:
- xterm-256color — 256-color palette; the safe default for most emulators
- tmux-256color — use inside a tmux session
- kitty — set automatically by Kitty; unlocks Kitty-specific extensions
- foot — set by Foot; enables its specific terminfo entries
- alacritty — Alacritty's own entry (available since its 0.12 release)
Never hard-code TERM=xterm. It caps you at 8 colors regardless of what the emulator supports. Conversely, do not set TERM manually inside an emulator that sets it itself — you will break capability detection.
COLORTERM
COLORTERM is the informal but widely-adopted signal for 24-bit (true color) support. Applications like Neovim, bat, delta, and fzf check it before emitting 24-bit RGB escape sequences.
- truecolor — the standard value; set by Kitty, Foot, WezTerm, iTerm2, GNOME Terminal ≥ 3.36, Alacritty, and most modern emulators
- 24bit — an older synonym; some apps accept either
Check what your current session exports:
echo "TERM=$TERM"
echo "COLORTERM=$COLORTERM"
If COLORTERM is unset and your emulator does support true color, set it in your shell profile:
# ~/.bashrc or ~/.zshrc — only if your emulator supports true color
export COLORTERM=truecolor
Quick True Color Smoke Test
This one-liner prints a gradient. If you see smooth color transitions, true color is working. If you see banding, it is not.
awk 'BEGIN{
for(c=0;c<256;c++){
printf "\033[48;2;%d;%d;%dm ", c, 100, 200-c;
}
printf "\033[0m\n"
}'
Sixel Graphics
Sixel is a decades-old DEC protocol that encodes bitmap images as character streams. It has seen a major revival because several modern terminals now support it, making inline images available without proprietary extensions.
Which Terminals Support Sixel
- foot — enabled by default
- WezTerm — enabled by default
- mlterm — long-standing sixel leader
- xterm — requires
-ti 340flag ordecTerminalID: 340in.Xresources - Contour — enabled by default
- iTerm2 (macOS) — partial; its own protocol (below) is preferred
- Kitty — does not support sixel; uses its own superior protocol
- GNOME Terminal / VTE-based terminals — no sixel support as of 2024
Detecting Sixel Support at Runtime
The terminal's DA1 (Device Attributes) response includes a 4 parameter if sixel is supported. Query it with:
printf '\033[c'; sleep 0.1; read -s -t 1 -d 'c' response </dev/tty; echo "$response"
Look for ;4; or ;4 at the end in the output. The exact string varies by terminal.
Displaying Sixel Images
Install img2sixel from the libsixel package:
# Debian/Ubuntu
sudo apt install libsixel-bin
# Fedora
sudo dnf install libsixel
# Arch
sudo pacman -S libsixel
img2sixel photo.jpg
For a quick test with Python's timg:
pip install timg
timg image.png
The Kitty Graphics Protocol
Kitty's graphics protocol (APC-based, \033_G...\033\\) transmits image data in chunked base64 payloads with a separate display command. It supports full RGBA, animation, virtual image placement, and Unicode placeholder rendering — capabilities sixel does not have.
Which Terminals Support the Kitty Protocol
- Kitty — reference implementation
- WezTerm — full support
- Konsole (KDE) ≥ 22.08 — partial support
- foot — as of 1.17, partial support
- Ghostty — full support
Checking Support Programmatically
Send a zero-size query chunk and check for an APC response:
printf '\033_Gi=1,s=1,v=1,a=q,t=d,f=24;AAAA\033\\'; sleep 0.1
read -s -t 1 response </dev/tty
echo "$response"
An OK in the response confirms support. No response or an error means unsupported.
Displaying Images with the Kitty Protocol
The kitten icat helper is the simplest path inside Kitty itself:
kitten icat photo.jpg
For a protocol-agnostic tool that falls back gracefully, use timg or chafa:
# Arch
sudo pacman -S chafa
# Debian/Ubuntu
sudo apt install chafa
# Fedora
sudo dnf install chafa
# chafa auto-detects the best protocol available
chafa photo.jpg
iTerm2 Inline Image Protocol
iTerm2 (macOS) uses an OSC 1337 escape sequence to transmit base64-encoded image data. It is simpler than Kitty's protocol but widely supported by macOS tooling.
Outside of macOS, WezTerm also supports this protocol. No mainstream Linux-native terminal does as a primary feature.
Displaying Images via iTerm2 Protocol
The official imgcat script wraps the encoding:
# Install via Homebrew on macOS
brew install iterm2-utilities
imgcat photo.jpg
Or manually from the iTerm2 repository:
curl -Lo imgcat https://iterm2.com/utilities/imgcat
chmod +x imgcat
./imgcat photo.jpg
Emulator Capability Reference
| Terminal | True Color | Sixel | Kitty Protocol | iTerm2 Protocol |
|---|---|---|---|---|
| Kitty | Yes | No | Yes (native) | No |
| WezTerm | Yes | Yes | Yes | Yes |
| foot | Yes | Yes | Partial (1.17+) | No |
| Ghostty | Yes | No | Yes | No |
| Alacritty | Yes | No | No | No |
| GNOME Terminal | Yes | No | No | No |
| Konsole | Yes | Yes (limited) | Partial | No |
| xterm | Yes | Yes (opt-in) | No | No |
| iTerm2 | Yes | Partial | No | Yes (native) |
| mlterm | Yes | Yes | No | No |
Tmux and Multiplexer Considerations
Tmux wraps the outer terminal and sets its own TERM. This breaks graphics protocols by default because tmux does not pass APC or DCS sequences through.
- For true color inside tmux, add to
~/.tmux.conf:
set -g default-terminal "tmux-256color"
set -ga terminal-overrides ",*256col*:Tc"
- For sixel passthrough (tmux ≥ 3.3a):
set -g allow-passthrough on
- For Kitty graphics passthrough (tmux ≥ 3.3a with Kitty as the outer terminal):
set -g allow-passthrough all
Zellij handles graphics passthrough more transparently than tmux and is worth considering if inline images are a primary use case.
Verification
Run the following to get a concise capability summary of your current session:
printf 'TERM: %s\nCOLORTERM: %s\n' "$TERM" "$COLORTERM"
# Check terminfo for 24-bit color flag
tput colors
tput colors should return 256 or higher. It will not return 16777216 even with true color — true color is indicated by COLORTERM, not terminfo, due to historical limitations in the terminfo spec. The RGB terminfo capability was added in ncurses 6.1 and can be checked with:
tput -T "$TERM" RGB 2>/dev/null && echo "terminfo RGB: yes" || echo "terminfo RGB: no"
Troubleshooting
- Colors look wrong in SSH sessions: The remote shell inherits
TERMfrom the SSH client, butCOLORTERMis not forwarded by default. AddSendEnv COLORTERMto your local~/.ssh/configandAcceptEnv COLORTERMto the remote/etc/ssh/sshd_config. - Images not displaying in tmux: Confirm
allow-passthrough onis set and you have tmux ≥ 3.3a. Check withtmux -V. - Sixel works in xterm but not other apps: Some apps check the DA1 response; others rely solely on environment variables. Set
TERM=xterm-256colorand ensure xterm was launched with-ti 340. - kitten icat fails outside Kitty:
icatrequires either native Kitty graphics protocol support or a fallback to sixel. Usechafafor a portable alternative. - TERM set to a value with no terminfo entry: Run
infocmp "$TERM". If it errors, install the missing entry or fall back toxterm-256color. Kitty ships its own terminfo; install it on remote servers withkitten sshor manually copy~/.terminfo.
Frequently asked questions
- Why does COLORTERM exist if TERM already describes the terminal?
- The terminfo database was designed when 24-bit color was not anticipated, so there was no clean way to signal true color support through it. COLORTERM became an informal but widely-adopted out-of-band variable to fill that gap. The terminfo RGB capability was added in ncurses 6.1 but adoption has been slow, so most apps still check both.
- Can I use the Kitty graphics protocol over SSH?
- Yes, but image data must be transmitted over the terminal connection, which is slow for large images. Kitty's `kitten ssh` helper copies the terminfo entry to the remote host and handles most setup. On any terminal that supports the protocol, the escape sequences pass through SSH transparently as long as the outer terminal handles APC sequences.
- Why doesn't Alacritty support sixel or Kitty graphics?
- Alacritty's maintainers have historically declined to implement graphics protocols, focusing on performance and correctness of text rendering. The project stance has softened slightly but neither protocol is implemented as of 2024. Use WezTerm, Kitty, or foot if inline images are important to you.
- Is there a single tool that handles all three image protocols transparently?
- chafa comes closest: it detects the best available protocol (Kitty, sixel, iTerm2, or Unicode block fallback) at runtime and uses it automatically. timg does the same. Neither requires you to know which protocol your terminal supports in advance.
- How do I make Kitty's terminfo entry available on remote servers?
- The cleanest method is `kitten ssh user@host`, which copies your local terminfo entries automatically. Alternatively, copy ~/.terminfo to the remote server manually, or run `infocmp kitty | ssh user@host tic -x -` to compile it directly on the remote machine.
Related guides
Bash Arrays and Associative Arrays
Master bash indexed and associative arrays: declaration, element access, looping, mapfile, namerefs, and practical patterns for real scripting work.
Bash Functions and Variable Scoping
Master Bash function scoping with local variables, source-based libraries, correct use of return codes, and array passing techniques including namerefs.
Bash Loops: for, while and until
Learn all three Bash loop types — for, while, and until — with practical, copy-paste examples covering file iteration, counting, polling, and safe line reading.
Bash Scripting for Beginners
Learn Bash scripting from scratch: shebang lines, variables, conditionals, loops, and arguments, plus a real backup script to tie it all together.