Work with the themectl theme management system. Use this skill when modifying themes, adding new themes, updating theme colors, fixing theme-related issues, or testing theme changes...
Manage the cross-platform theme system for NixOS and Darwin.
| Task | Command |
|---|---|
| Show current theme | themectl status |
| Apply a theme | themectl apply <theme-name> |
| Cycle to next theme | themectl cycle --direction next |
| Cycle wallpapers | themectl cycle-background |
| Run health checks | themectl doctor |
| Show hotkeys | themectl hotkeys |
| Toggle macOS BSP/native | themectl macos-mode --mode bsp |
For CLI changes, run themectl directly from source:
# Enter dev shell (has all dependencies)
nix develop --impure
# Run from source
cd scripts/themectl
python -m themectl status
python -m themectl apply tokyo-night
# Or use uv for faster iteration
uv run themectl status
Theme definitions are in Nix, so changes require a rebuild:
# Fast local build (no deploy)
nix build .#darwinConfigurations.halcyon.system --impure
# Activate locally
sudo ./result/sw/bin/darwin-rebuild switch --flake .#halcyon
# Test the theme
themectl apply <theme-name>
cd scripts/themectl
uv run pytest
uv run pytest -v tests/test_cli.py::test_specific_test
| Path | Purpose |
|---|---|
modules/themes/definitions/*.nix |
Individual theme color palettes |
modules/themes/lib.nix |
Theme library functions, metadata builder |
modules/themes/default.nix |
Main theme module |
Each theme in modules/themes/definitions/<name>.nix contains:
{
name = "theme-name";
displayName = "Theme Name";
kind = "dark"; # or "light" — drives OS light/dark mode + editor background
# Terminal colors
alacritty = { primary = { background = "#..."; foreground = "#..."; }; ... };
kitty = { background = "#..."; foreground = "#..."; color0 = "#..."; ... };
ghostty = { theme = "..."; background = "#..."; palette = [ "0=#..." ... ]; };
# Editor themes
nvim = { colorscheme = "..."; };
vscode = { theme = "..."; extension = "publisher.name"; };
cursor = { theme = "..."; extension = "publisher.name"; }; # Optional
# Desktop colors
hyprland = { activeBorder = "..."; inactiveBorder = "..."; };
waybar = { foreground = "#..."; background = "#..."; };
walker = { ... };
# Application colors
tmux = { statusBackground = "#..."; ... };
btop = { main_bg = "#..."; ... };
mako = { ... };
# Wallpapers (filenames in wallpapers/<theme>/)
wallpapers = [ "0-file.jpg" "1-file.jpg" ];
}
| Path | Purpose |
|---|---|
scripts/themectl/themectl/cli.py |
Main CLI entry point, commands |
scripts/themectl/themectl/hooks.py |
App reload logic (neovim, ghostty, tmux, etc.) |
scripts/themectl/themectl/themes.py |
Theme class, metadata parsing |
scripts/themectl/themectl/assets.py |
Asset generation (alacritty, starship configs) |
scripts/themectl/themectl/config.py |
Configuration loading |
scripts/themectl/tests/ |
Test suite |
| Path | Purpose |
|---|---|
modules/home-manager/editor/neovim.nix |
Neovim config, colorscheme plugins |
modules/home-manager/editor/nvim-colors/*.lua |
Custom colorschemes (e.g., matte-black) |
| Path | Purpose |
|---|---|
packages/vscode-extensions/default.nix |
Custom-packaged theme extensions |
modules/home-manager/darwin/cursor-extensions.nix |
Extension installation module |
| Path | Purpose |
|---|---|
modules/themes/wallpapers/<theme>/ |
Theme wallpapers |
external/omarchy/ |
Upstream omarchy submodule (source for sync) |
| Path | Purpose |
|---|---|
~/.config/themes/.current |
Current theme name |
~/.config/themes/.current-background |
Current wallpaper index |
~/.config/alacritty/alacritty.toml |
Generated alacritty config |
~/.config/ghostty/config |
Generated ghostty config |
~/.config/nvim/lua/plugins/theme.lua |
Mutable neovim theme config |
Current themes (check modules/themes/definitions/):
tokyo-night - Default, blue/purplecatppuccin - Mocha variant, pastelcatppuccin-latte - Light variantgruvbox - Warm retronord - Arctic bluerose-pine - Muted roseeverforest - Green forestkanagawa - Japanese wavematte-black - Minimal dark (custom nvim colorscheme)osaka-jade - Green/jade Tokyo Night variantristretto - Monokai coffeeflexoki-light - Warm light themehooks.py)themectl apply runs these in order after updating symlinks/state:
VSCode → Cursor → Neovim → tmux → Alacritty → Hyprland → Wallpaper →
System appearance → Ghostty (config rewrite) → cmux reload → Ghostty (app reload) → btop.
update_system_appearance): reads theme.is_light
(from kind) and flips macOS light/dark via System Events
appearance preferences (skips if already matching). On Linux it sets
org.gnome.desktop.interface color-scheme when gsettings exists.reload_cmux, macOS only): cmux embeds libghostty and reads
~/.config/ghostty/config for terminal colors; cmux reload-config
refreshes terminals in place. cmux's own chrome (sidebar/tabs) uses
appearanceMode = system, so it follows the System appearance hook. Do not
use cmux themes set — it writes an override that stops cmux reading the
Ghostty config themectl manages.cmuxOnly (only processes spawned inside cmux
may connect), which rejects themectl when launched from skhd or another
terminal with "Access denied". halcyon's ~/.config/cmux/cmux.json
(user-owned, not Nix-managed) sets
automation.socketControlMode = "password" with a random
socketPassword; the CLI falls back to that saved password automatically,
so no env var is needed. cmux hot-reloads cmux.json on save.ghostty +reload-config CLI action; the app is
reloaded with Cmd+Shift+, via AppleScript on macOS.THEME_DISABLE_EDITOR_AUTOMATION=1 disables every AppleScript-based hook
(editors, wallpaper, appearance, Ghostty keystroke).Create theme definition:
cp modules/themes/definitions/tokyo-night.nix modules/themes/definitions/my-theme.nix
# Edit with your colors; set kind = "light" for light palettes
Add wallpapers (optional):
mkdir -p modules/themes/wallpapers/my-theme
cp /path/to/wallpaper.jpg modules/themes/wallpapers/my-theme/0-wallpaper.jpg
Add neovim colorscheme (if custom):
neovim.nix colorschemes list)nvim-colors/my-theme.luaAdd VSCode extension (if not in marketplace):
packages/vscode-extensions/default.nixcursor-extensions.nixBuild and test:
nix build .#darwinConfigurations.halcyon.system --impure
sudo ./result/sw/bin/darwin-rebuild switch --flake .#halcyon
themectl apply my-theme
name, displayName)nix build for syntax errorsneovim.nix colorschemes list with lazy = falsenvim-colors/ and added to gitthemeToColorscheme tablevscode.extension and cursor.extension in theme definitionkind in the theme definition; themectl apply prints
"Set macOS appearance to light|dark" or "already app.appearance is
system (check cmux settings path / defaults read com.cmuxterm.app appearanceMode)cmux themes should show Source: ~/.config/ghostty/configautomation.socketControlMode to password in ~/.config/cmux/cmux.json
(see Runtime Reload Hooks above)modules/themes/wallpapers/<theme>/wallpapers array in theme definition matches filenamesdesktoppr must be installed