osstmux-ide is open source, built at Prototyper.Learn more
tmux-ide

Theming & Config

The one config file — ~/.tmux-ide/config.json — that colors every surface and binds every key

Theming & config

tmux-ide has one global config file: ~/.tmux-ide/config.json (override the path with the TMUX_IDE_CONFIG environment variable). It holds the keymap, the theme, and the behavior toggles for notifications, restore, updates, and worktrees.

The theme tokens are semantic, not per-surface: a single theme block colors the tmux chrome (status bar, pane chips, actions menu, cheat sheet) and the TUI widgets. Re-theming the whole product is a one-file edit plus a re-adopt.

Every field is optional. A missing or malformed file falls back to the built-in defaults, and any individual field that's missing or mistyped falls back to its own default — the parser never throws. Config is read once per process, so changes take effect on the next launch (a re-adopt spawns fresh processes).

You can edit it interactively with the config panel (prefix v / ⌥,) or tmux-ide popup config.

Full default

{
  "keys": {
    "popup": "M-p",
    "home": "M-h",
    "cheatsheet": "M-k",
    "menu": "M-m",
    "sidebar": "M-b",
    "panels": { "explorer": "M-e", "changes": "M-g", "config": "M-," }
  },
  "theme": {
    "accent": "colour75",
    "muted": "colour240",
    "fg": "colour250",
    "status": {
      "blocked": "colour203",
      "working": "colour221",
      "done": "colour111",
      "idle": "colour114",
      "unknown": "colour244"
    },
    "glyphs": { "active": "●", "inactive": "○" }
  },
  "updater": { "tickMs": 2000, "snapshotEvery": 15 },
  "notifications": { "toast": true, "macos": false },
  "restore": { "resumeAgents": false },
  "updates": { "check": true },
  "welcome": { "show": true },
  "worktrees": { "dir": "" }
}

keys

Each entry is the root-table Alt fast-path for a surface, as a tmux key name (M- is Meta/⌥). tmux-ide also binds a prefix twin for every surface — the reliable path that works under every keyboard protocol — derived from these same entries, so you configure both by editing one value.

FieldAlt defaultPrefix twinOpens
homeM-hprefix hHome cockpit from anywhere
popupM-pprefix jSession switcher
cheatsheetM-kprefix kCheat sheet
menuM-mprefix uActions menu
sidebarM-bprefix bSidebar nav column
panels.explorerM-eprefix eFile explorer panel
panels.changesM-gprefix gGit changes panel
panels.configM-,prefix vConfig editor panel

The Alt binds can be swallowed while an agent pane has focus (agents may switch the terminal's key encoding via the kitty keyboard protocol); tmux-ide registers kitty-encoded fallbacks, but coverage varies by terminal. The prefix twins are immune by construction — see The dock & keys.

theme

Semantic tokens, applied to both the tmux chrome and the widgets. Values are tmux colors (colourN or #rrggbb).

FieldDefaultMeaning
accentcolour75Primary / brand accent
mutedcolour240Dim / secondary text
fgcolour250Default foreground
status.blockedcolour203Blocked agent
status.workingcolour221Working agent
status.donecolour111Done agent
status.idlecolour114Idle agent
status.unknowncolour244No signal
glyphs.activeFilled state glyph
glyphs.inactiveHollow state glyph

TUI-owned surfaces

The full-screen TUI owns its chrome instead of inheriting whatever colours a child program happens to leave in the terminal. New and migrated surfaces use a theme pipeline with three boundaries:

  1. @tmux-ide/contracts defines renderer-neutral roles for canvas, panels, headers, text strength, borders, status, selection, density, shape, motion, typography and focus.
  2. The OpenTUI host projects those roles to RGBA once and follows the renderer's light/dark mode when theme.mode is system.
  3. Each migrated product surface consumes a named recipe such as sidebar, application-bar, bottom-dock or command-palette. Components choose a role by purpose rather than carrying a private palette.

Navigation labels use the sidebar recipe's readable text rung, selection labels use selectionText, and tertiary metadata alone uses muted. Critical foreground/background pairs are contrast-checked at the OpenTUI projection boundary. A low-contrast custom value falls back through the owned text ladder instead of making navigation disappear.

The built-in muted greys deliberately use stable extended xterm-256 entries, not ANSI base slot 8. Base slots are terminal-profile aliases and can be nearly black even when the source RGB looked grey. Mirrored tmux pane contents are the exception: their ANSI colours belong to the program running in that pane and remain untouched.

updater

The chrome tick loop and snapshot cadence.

FieldDefaultMeaning
tickMs2000Milliseconds between ticks
snapshotEvery15Write a restore snapshot every N ticks

notifications

FieldDefaultMeaning
toasttrueIn-tmux toast on blocked / done
macosfalseAlso post a native macOS notification

See Notifications & events.

restore

FieldDefaultMeaning
resumeAgentsfalseRevive Claude conversations on restore (--resume-agents)

See Restore & resume.

updates

FieldDefaultMeaning
checktrueCheck for a newer tmux-ide version

welcome

FieldDefaultMeaning
showtrueAllow the first-run welcome card. Set false to suppress it

worktrees

FieldDefaultMeaning
dir""Base dir for worktree checkouts. Empty → sibling <repo>-worktrees; a relative path resolves against the repo

See Worktrees.

Desktop design system

The desktop app has its own token layer, separate from the tmux chrome above: sfora's oklch zinc system. Colour, elevation and shape are authored in one place — the token block in apps/desktop-renderer/src/styles.css — and every component reads a semantic role rather than a value.

Two layers. The system (--sf-*) holds the zinc ladder, the shadow ladder and the accents. The mapping re-points the roles the shell consumes (--tmux-ide-*, --desktop-*) at that system, which is why changing the product's identity does not touch a single component.

The architecture is planes, not pages

Depth is the identity. Four planes, back to front:

PlaneLightDarkIn tmux-ide
Sidebar96.3%12%The fleet sidebar, titlebar, dock
Content, inset98.7%14.05%The canvas the windows live on
Grey section96.76%27.41%Grouped and section surfaces
White item100%16.8%Window cards, dialogs, popovers

All zinc-hued — hue 286, whisper chroma. Never a blue-grey, never a warm one.

Elevation is a ring, not a blur

Structure comes from the plane plus a crisp 1px ring, not from borders everywhere. The visible edge is what makes a card read against the plane behind it; a near-zero ring dissolves into the canvas, and on a floating surface the ring draws the silhouette sharper than any border colour can. In dark mode the ring flips to a lit top edge, which reads as a card's white border against a darker canvas.

Six named tokens carry every surface — --sf-shadow-surface (resting cards), -field (inputs), -overlay (dialogs, menus, palette), -tooltip, -panel (floating toolbars), -inset-track (inset wells). There are no ad-hoc shadows in the renderer. Hairline borders survive only as genuine dividers, at --paper-hairline, which resolves to one device pixel — 0.5px on retina.

Colour means one thing each

Primary is metallic zinc, not blue: buttons and primary actions are --sf-primary. This is the single most look-defining value in the system.

Three blues, deliberately distinct, and never interchangeable:

  • the lit-blue gradient (--sf-accent-blue--sf-accent-blue-dark) is the selected nav or fleet row, and nothing else;
  • anchor #6187fe is focus rings and text selection, and nothing else. It ships no P3 variant, so it stays sRGB;
  • --sf-app-blue is reserved for macOS-system-adjacent affordances and is deliberately unused.

Semantics are never decorative: --sf-valid is agent work and success, --sf-invalid is errors and blocked, --sf-warning is attention and staleness. Status glyphs, chips, readiness rungs and degraded surfaces draw from these and nothing else. Section accents (blue, green, amber, purple) are for identity — eyebrows and section marks — and are never used for status.

Two rungs are derived rather than transcribed, both forced by contrast: light-mode -ink twins for the semantic tones (#00c454 is 2.23:1 on white and #f6c30f is 1.58:1 — neither can carry 11px text or a 6px status dot, which needs 3:1 as a non-text component), and a metadata text rung, because sfora's tertiary rung is 3.55:1 on the sidebar plane and this product spends it on text that must be read. All 112 ink-on-plane pairs clear their floor in both modes.

Type and shape

The Board-UI composite ramp — headline 16/22, body 14/20, body-2 13/18, caption-1 12/16 at +0.15px, caption-2 11/15 at +0.2px — drawn in the system face (-apple-system, SF on macOS) rather than bundling Inter. That is a deliberate deviation from sfora: the ramp carries the look, SF is metrically close, and the native face is what stops the app reading as a web page in a window. Chrome sits mostly at body-2 and caption-1, like a real Mac app; terminals keep their mono stack.

Radii follow sfora's ladder: controls at 8px, cards and nav rows on the 10px 2lg step.

High contrast

The system steps aside when the OS asks for more contrast: the mapping is scoped to [data-increased-contrast="false"], and in high-contrast mode the theme resolver owns the focus, selection, attention and danger colours. The trade-off is that user and project theme overrides only reach those roles while high contrast is on.

On this page