Ghostty & cmux¶
Ghostty's Kitty graphics support also makes it suitable for terminal-browser, including inside Herdr. Playwright CLI's headless mode works independently of terminal graphics.
Ghostty is a fast, native terminal emulator. cmux is a lightweight macOS terminal built on Ghostty for managing AI coding agents. Both read the same config file.
Installation and profiles¶
- macOS:
cask "ghostty"is in the GUI Brewfile underinstallBrewApps. - Linux desktop:
gui_apps_linuxinstalls missing Ghostty on x64/arm64. It prefers an existing apt candidate (Ubuntu 26.04+ ships one), uses the upstream-listedmkasberg/ghostty-ubuntuPPA on Ubuntu 24.04, and otherwise falls back to the upstream-listed classic Snap. The PPA is a community build; Noble's GTK baseline is supported up to Ghostty 1.3.1. No Ubuntu PPA is added to Debian. Snap is the compatibility fallback for older GTK, not the first choice for a daily-use terminal. - Server: GUI tag selection does not install Ghostty. Run it on the client and connect over SSH.
- noRoot / 32-bit: automatic Linux installation is skipped with a hint; existing manually installed binaries are preserved. No default terminal is changed, and Alacritty continues to be available.
Apply is install-only. macOS upgrades use just upgrade-brew; apt installations
follow explicit system package maintenance, and Snap follows its normal refresh
schedule. There is no extra Ghostty updater. Package sources:
Ghostty installation guide,
Ubuntu PPA,
classic Snap.
Alacritty comparison¶
| Setting | Ghostty decision |
|---|---|
| Hack Nerd Font Mono, 14pt | Shared; bold/italic variants selected from the family automatically |
| 10px window padding | Shared numeric X/Y value of 10; actual scaling follows each terminal |
| 0.7 opacity + blur | Keep Ghostty's opaque default for readability; optional recipe below |
| Shift/Ctrl+Enter, Ctrl+digits | Use native negotiated Kitty/xterm extended keys; do not force Alacritty's byte strings |
| Ctrl+/ | Native legacy encoding already supplies 0x1f; modern apps can negotiate an unambiguous key |
TERM=xterm-256color |
Keep native xterm-ghostty, with SSH terminfo support |
| Option as Alt | Keep Ghostty's existing left-only policy; Right Option remains available for compose |
| Linux Ctrl+Shift+T / N | Keep Ghostty's native tab / window actions; Alacritty maps both to windows because it has no tabs |
Ghostty's legacy modified-Enter encoding can be xterm CSI 27;…~, while Kitty
mode uses CSI-u. Applications/multiplexers negotiate and decode these protocols;
the bytes need not be identical to Alacritty's explicit overrides. Existing tmux
root bindings still consume Ctrl+digits for window selection.
For the Alacritty transparency look, the equivalent optional settings are:
Blur depends on the compositor (macOS / supported Linux compositors such as KWin); it is not guaranteed under GNOME. This file also affects cmux. See the Ghostty option reference.
Managed config¶
This repo manages ~/.config/ghostty/config (via dot_config/ghostty/config). cmux reads this file first (before ~/Library/Application Support/com.mitchellh.ghostty/config).
Key settings:
font-family = Hack Nerd Font Mono,font-size = 14,window-padding-x/y = 10— aligns typography and spacing with Alacritty.-
shell-integration-features = ssh-env,ssh-terminfo— enables the interactive SSH helpers described below while retaining the other default features. -
macos-option-as-alt = left— Left Option sends Meta/Esc+ so tmuxM-keybindings work (theme switchingM-c/M-t, layoutsM-1..M-5, fine resizeM-h/j/k/l). Right Option retains macOS compose behavior for accents and special characters. font-feature = -calt, -liga, -dlig— Disables ligatures for code readability. The key is singular;font-featuresfails Ghostty validation withunknown field.
Validate the managed source with ghostty +validate-config --config-file=dot_config/ghostty/config, and the installed config with ghostty +validate-config. Ghostty can reload configuration with Cmd+Shift+, on macOS; restart cmux to pick up changes to the shared file.
Without macos-option-as-alt, macOS Option produces Unicode compose characters (e.g. Option+c → ç) instead of Esc+c, silently breaking all tmux Meta bindings. Alacritty and iTerm2 have their own equivalent settings (window.option_as_alt and Profiles > Keys > Left Option Key > Esc+ respectively).
xterm-ghostty terminfo on remote hosts¶
When you SSH into a fresh remote, $TERM=xterm-ghostty but the remote has no matching terminfo entry. Symptoms: broken line-drawing, garbled prompts, clear/tput failures, Neovim rendering glitches. This is especially visible on the first cmux/tmux SSH into a new box.
Option 1 — Ghostty built-in (recommended for interactive shells)¶
Already enabled in the managed ~/.config/ghostty/config:
ssh-terminfo: auto-installsxterm-ghosttyon the remote the first time yousshfrom an interactive shell with Ghostty shell integration loaded.ssh-env: forwardsCOLORTERM,TERM_PROGRAM,TERM_PROGRAM_VERSIONviaSendEnv, and falls back toTERM=xterm-256colorwhere needed. The remotesshd_configneeds a matchingAcceptEnvline for the forwarded vars to take effect.
Limitations: only triggers from interactive shells with the Ghostty wrapper active. It does not cover ssh invoked inside tmux/cmux panes, from scripts, or from wrapper tools (rsync, aws, gcloud, …). For those, use the manual helper below.
Option 2 — manual helper (works everywhere)¶
A shared-shell function ghostty-ssh-terminfo is defined in dot_config/shell/10_aliases.sh.
What it does:
- Validates local
infocmpand thexterm-ghosttyentry exist. - Pipes
infocmp -x xterm-ghosttyinto a single SSH call (no double password/MFA prompt). - On the remote: probes for
tic, creates~/.terminfo, and runsTERMINFO="$HOME/.terminfo" tic -x -— so no root/sudo needed. - Suppresses only the harmless
older tic versions may treat the description field as an aliaswarning (emitted by ncurses < 6.3). Real errors still surface and set a non-zero exit.
Example:
# First time connecting a new box from cmux/tmux
ghostty-ssh-terminfo remote
# → Installed xterm-ghostty terminfo on remote (in ~/.terminfo)
# Verify
ssh remote 'infocmp xterm-ghostty >/dev/null && echo ok'
Snap nvtop on a remote host¶
The Snap build of nvtop changes HOME to ~/snap/nvtop/<revision>, so it
cannot find the Ghostty entry installed in the user's ~/.terminfo. It then
reports Error opening terminal: xterm-ghostty, even though infocmp succeeds
outside the Snap. The shared-shell nvtop function copies that entry to
~/snap/nvtop/common/.terminfo and sets TERMINFO for the Snap invocation.
The common directory survives Snap revisions. Other terminal types and native
nvtop use their normal configuration. Open a new shell after applying this
change, or source ~/.config/shell/10_aliases.sh in the current shell.
Smoke-test against localhost¶
Yes — if sshd is running locally you can validate the function without touching a real remote:
# Enable sshd (Linux)
sudo systemctl start ssh
# or macOS: System Settings → General → Sharing → Remote Login
ghostty-ssh-terminfo localhost
Caveats:
localhostalready has your own$HOME, so this effectively writes to the same~/.terminfoyour local shell reads. Useful as a wiring/error-path smoke test, not as a representative "fresh remote" check.- If you already have the entry locally (which you do, otherwise
infocmp -x xterm-ghosttywould fail), the install is a no-op overwrite — still exercises the full pipeline end-to-end. - For a cleaner test, point at a container or a VM where
xterm-ghosttyis definitely missing.
Why the warning appears (and can't be fully fixed client-side)¶
The |-separated long description in Ghostty's terminfo is interpreted as an extra alias by tic / ncurses prior to 6.3. The entry still installs correctly; the warning is cosmetic. The only real fix is upgrading ncurses on the remote.
Image preview (yazi)¶
Ghostty and cmux speak the Kitty graphics protocol, so yazi renders crisp inline images (not chafa ascii-art) for png / jpg / pdf / video previews — no config needed, yazi auto-detects the terminal.
Gotcha: a very large image (a wide plot, a hi-DPI screenshot) can show Image size exceeds limit
in the preview pane. That's yazi's image decode bound, not a Ghostty/cmux cap — this repo raises
[tasks] image_bound in dot_config/yazi/yazi.toml; run yazi --clear-cache and restart yazi to pick
it up. Detail + the terminal support matrix:
yazi-previews.md → Large images /
which terminal gets crisp images.
Inside tmux, image passthrough needs allow-passthrough on (set in dot_config/tmux/common.conf.tmpl).