ghostty config best practices for cmux


cmux reads your existing ~/.config/ghostty/config. you don't write a separate config for it — but there are specific things it cares about, a few gotchas that will silently break things, and one setting that makes the whole notification system work (or not).

here's everything that matters.


how cmux actually reads your config (dual-layer)

cmux has two config layers running at the same time:

layer 1: swift parser (GhosttyConfig.swift) — reads exactly 15 keys. used for UI chrome, sidebar styling, font selection, split dividers, opacity. this is cmux's own parser, independent of Ghostty.

layer 2: libghostty (C library) — reads ALL Ghostty config keys. handles actual terminal rendering, runtime config updates, the full feature set. this is the same engine Ghostty.app uses.

the split matters because layer 1 has quirks (see: font-family below) that layer 2 doesn't.

config file search order

cmux checks all four locations in order. later values override earlier ones:

other
~/.config/ghostty/config                                                   ← first
~/.config/ghostty/config.ghostty
~/Library/Application Support/com.mitchellh.ghostty/config
~/Library/Application Support/com.mitchellh.ghostty/config.ghostty        ← last

the 15 keys cmux's swift parser reads

everything else is handled by libghostty. these are the keys that affect cmux's UI chrome directly:

keydefaultwhat cmux uses it for
font-family"Menlo"sidebar text, UI chrome font
font-size12UI font sizing
themeniltheme file loading + color extraction
working-directorynilinitial directory
scrollback-limit10000scrollback buffer size
background#272822window/chrome background
background-opacity1.0chrome transparency
foreground#fdfff1text color
cursor-color#c0c1b5cursor rendering
cursor-text#8d8e82text under cursor
selection-background#57584fselection highlight
selection-foreground#fdfff1selected text color
palette(none)16-color ANSI palette
unfocused-split-opacity0.7dimming of unfocused splits
unfocused-split-fillnildimming overlay color
split-divider-colornilsplit border color (auto-calculated if nil)

split divider auto-calculation (when split-divider-color is not set):

light backgrounds (luminance > 0.5): darken by 8%

dark backgrounds: darken by 40%

luminance formula: 0.299R + 0.587G + 0.114B


the gotchas

font-family: use exactly one line

this is the single most important compatibility detail.

cmux's swift parser does this on each font-family line:

swift
case "font-family":
    fontFamily = value  // OVERWRITES — takes LAST value

ghostty's C library chains multiple font-family values (first = primary, rest = fallbacks).

so if your config has:

other
font-family = JetBrains Mono    ← ghostty uses this (primary)
font-family = Fira Code         ← ghostty fallback #1
font-family = Hack              ← ghostty fallback #2, cmux uses this!

ghostty renders with JetBrains Mono. cmux's sidebar uses Hack for font calculations. they're different.

fix: use a single `font-family` line.

other
font-family = JetBrains Mono

desktop-notifications: must be true

cmux's entire notification system depends on OSC 9/99/777 escape sequences. the blue rings, sidebar badges, Cmd+Shift+U to jump to latest unread — all of it.

if desktop-notifications = false, cmux never detects when AI agents need your attention.

other
desktop-notifications = true

set it and forget it.

keybind precedence: cmux wins

cmux intercepts keybinds at the AppKit level before they reach libghostty. Cmd+N, Cmd+T, Cmd+1-8, etc. all take precedence over anything in your Ghostty config. you cannot override cmux's shortcuts from ~/.config/ghostty/config.

shell integration layering

cmux has its own .zshenv that restores ZDOTDIR after Ghostty's shell integration injection. if you have HISTFILE path issues or zsh wrapper recursion, this is why.

the flow:

GhosttyKit sets ZDOTDIR to the Ghostty integration directory

cmux .zshenv restores from $GHOSTTY_ZSH_ZDOTDIR or $CMUX_ZSH_ZDOTDIR

your /etc/zshrc and ~/.zprofile load normally

you don't need to do anything here — just know it's happening so you don't fight it.


themes: paired light/dark

cmux supports the same paired theme syntax as Ghostty:

other
theme = light:Catppuccin Latte,dark:Catppuccin Mocha

auto-switches based on NSAppearance (macOS light/dark mode). cmux monitors appearance changes at runtime and invalidates the config cache when you switch.

theme search paths (6 locations, in order):

$GHOSTTY_RESOURCES_DIR/themes/{name}

app bundle: ghostty/themes/{name}

$XDG_DATA_DIRS/ghostty/themes/{name}

/Applications/Ghostty.app/Contents/Resources/ghostty/themes/{name}

~/.config/ghostty/themes/{name}

~/Library/Application Support/com.mitchellh.ghostty/themes/{name}

builtin alias expansion:

Solarized Light also tries iTerm2 Solarized Light

Solarized Dark also tries iTerm2 Solarized Dark

Builtin X prefix is stripped and retried


environment variables cmux sets

useful to know if you're debugging shell behavior:

other
GHOSTTY_RESOURCES_DIR  → bundled Ghostty resources (themes, terminfo)
XDG_DATA_DIRS          → appended for theme search paths
TERM                   → "xterm-ghostty"
TERM_PROGRAM           → "ghostty"

the full config (copy-paste ready)

this works in both Ghostty.app and cmux. every setting verified against the source.

other
# dual-use: ghostty.app + cmux
# [cmux] = read by swift parser for UI chrome
# everything else = handled by libghostty
# [cmux] theme — auto-switches light/dark
theme = light:Catppuccin Latte,dark:Catppuccin Mocha

# [cmux] font — single font-family line (critical)
font-family = JetBrains Mono
font-size = 16

# font styling (C library only — safe to use)
font-style = Medium
font-thicken = true
font-thicken-strength = 200
adjust-cell-height = 2

# cursor
cursor-style = bar
cursor-style-blink = true
cursor-click-to-move = true

# [cmux] background
background-opacity = 1

# [cmux] splits
unfocused-split-opacity = 0.75

# split-divider-color auto-calculated from background luminance if unset
# [cmux] scrollback
scrollback-limit = 20000000

# [cmux] CRITICAL: powers notification rings + sidebar badges
desktop-notifications = true

# shell integration
shell-integration = detect
shell-integration-features = cursor,sudo,title,ssh-env,ssh-terminfo,path
term = xterm-ghostty

# macos
macos-option-as-alt = true
copy-on-select = clipboard
clipboard-write = allow

quick checklist

single font-family line only

desktop-notifications = true (non-negotiable for notifications)

paired theme = light:X,dark:Y for auto light/dark switching

don't try to override cmux shortcuts via ghostty keybinds — they won't apply

if shell behavior is weird around ZDOTDIR, check $GHOSTTY_ZSH_ZDOTDIR — cmux is managing it