ActiveTerminal tooling · 2026

Terminal tooling · two delivery paths

Ghostty × Yazi theme sync

Yazi inherits a terminal's ANSI colors, but several of its most visible surfaces ignore or misuse them. I built two complementary tools around the same transformation: a runtime plugin for zero-maintenance syncing and a packaged CLI for static, inspectable flavor files.

My role

Independent project · design, implementation, and packaging

Terminal tooling
Source
Ghostty's resolved active palette
Delivery
Runtime plugin or static flavor
Automation
Yazi, launchd, or systemd
01

The last mile of terminal theming

Yazi follows the terminal palette for much of its interface, then breaks the illusion in two places: reverse-video hover bars can become neon blocks, and syntect code previews use a separate theme that does not follow the terminal at all.

Hand-authored flavors solve that for popular themes. These tools solve it for whatever Ghostty is actually running, including built-in themes, custom themes, and included configuration.

02

Let Ghostty resolve Ghostty

Both implementations call `ghostty +show-config` and parse the resolved colors rather than duplicating Ghostty's theme lookup and include rules. One stable input contract covers every theme source Ghostty already understands.

The transformation changes only the Yazi surfaces that fail to follow the palette well. It leaves the rest of the preset alone and builds a TextMate theme from the same colors for code previews.

03

One engine, two operational choices

The Lua plugin applies colors directly to Yazi's live theme on every launch and refreshes a cached TextMate file before the first preview. It is the set-and-forget path.

The Python CLI writes a complete `flavor.toml` and `tmtheme.xml` that can be read, diffed, and versioned. It also installs an event-driven launchd or systemd watcher, making it a better fit for declarative dotfiles and static configuration.

04

Verify the runtime boundary

The implementation does not assume every Yazi theme surface behaves the same way. Live theme-object mutations affect the current UI, while the asynchronous preview path requires a stable theme file. The split design follows that observed boundary and keeps the pure parsing and rendering modules testable without launching Yazi.

Engineering choices

The decisions that shaped it.

The implementation details matter because each one closes a specific failure mode or keeps an important boundary visible.

01

Consume resolved configuration

Ghostty remains responsible for themes and includes; the tools translate its final palette instead of reimplementing its configuration model.

02

Offer two explicit tradeoffs

The plugin optimizes for automatic live behavior, while the CLI optimizes for static files and declarative machine setup.

03

Share colors, respect different runtimes

Yazi's live interface and syntect preview engine receive the same palette through the mechanisms each one actually observes.

Where it landed

Two public, tested distribution paths for the same theme engine: a native Yazi plugin installed with its package manager and a Python CLI published on PyPI.

Next case study

Focused Claude Code plugins

Keep reading