A macOS background service that monitors system theme changes (light/dark mode) and executes custom scripts in response.
- Real-time monitoring of macOS theme changes using native APIs
- Zero CPU usage when idle (event-driven)
- Execute custom shell scripts when switching to light/dark themes
- Execute Lua scripts with built-in API for theme handling
- Quiet mode for background operation
- Environment variables passed to scripts
- IPC server for integration with other applications (e.g., Neovim)
cargo build --release
cp target/release/theme-switcher /usr/local/bin/theme-switchertheme-switcher --ipctheme-switcher --light-script ./light_theme.sh --dark-script ./dark_theme.shtheme-switcher --quiet --light-script ./light_theme.sh --dark-script ./dark_theme.shtheme-switcher --any-script ./theme_changed.shtheme-switcher --lua-light ./light.lua --lua-dark ./dark.lua
# Or run a single Lua script on any change
theme-switcher --lua-any ./theme_change.lua# Use default config location: ~/.config/theme-switcher/config.toml
theme-switcher
# Or specify a custom config file
theme-switcher --config ~/my-theme-config.tomlShell scripts receive the following environment variables:
THEME_SWITCHER_THEME: Current theme (lightordark)THEME_SWITCHER_THEME_UPPER: Current theme in uppercase (LIGHTorDARK)
Lua scripts have access to global variables and a theme_switcher module:
THEME: Current theme string ("light"or"dark")THEME_UPPER: Current theme in uppercase ("LIGHT"or"DARK")IS_DARK: Boolean indicating if dark theme is activeIS_LIGHT: Boolean indicating if light theme is active
theme_switcher.execute(cmd): Execute a shell command and return results- Returns a table with:
stdout,stderr,success
- Returns a table with:
theme_switcher.log(msg): Log an informational messagetheme_switcher.log_error(msg): Log an error messagetheme_switcher.current_theme: Current theme stringtheme_switcher.is_dark: Boolean for dark themetheme_switcher.is_light: Boolean for light theme
Theme-switcher supports TOML configuration files for managing multiple scripts:
[general]
quiet = false # Run in quiet mode
# log_file = "/path/to/logfile.log" # Optional log file
[scripts]
# Shell scripts - can specify multiple scripts per event
light = ["~/scripts/light1.sh", "~/scripts/light2.sh"]
dark = ["~/scripts/dark1.sh", "~/scripts/dark2.sh"]
any = ["~/scripts/any-change.sh"]
[lua_scripts]
# Lua scripts - can specify multiple scripts per event
light = ["~/scripts/light.lua"]
dark = ["~/scripts/dark.lua"]
any = ["~/scripts/theme-change.lua"]See the examples/ directory for:
- Shell scripts for basic theme changes
- Lua scripts for:
- Changing VS Code themes
- Updating terminal colors (iTerm2, Terminal.app)
- Sending system notifications
- Complex configuration file updates
- Integration scripts:
zellij_theme.sh/zellij_theme.lua- Zellij terminal multiplexerclaude_code_theme.sh/claude_code_theme.lua- Claude Code editor
- TOML configuration examples:
theme-switcher.toml- Full example with commentsminimal-config.toml- Simple configurationadvanced-config.toml- Complex multi-app setupnvim-config.lua- Neovim plugin configuration
This repository also functions as a Neovim plugin that automatically syncs your editor theme with the system theme.
-
Start theme-switcher with IPC enabled:
theme-switcher --ipc
-
Install the plugin using lazy.nvim:
{ 'ThisIsMani/theme-switcher', config = function() require('theme-switcher').setup({ schemes = { light = "tokyonight-day", dark = "tokyonight-night" } }) end }
See NEOVIM.md for detailed setup instructions.
To run theme-switcher as a macOS LaunchAgent:
- Create a plist file at
~/Library/LaunchAgents/com.yourdomain.theme-switcher.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.yourdomain.theme-switcher</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/theme-switcher</string>
<string>--config</string>
<string>/Users/yourusername/.config/theme-switcher/config.toml</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>- Load the service:
launchctl load ~/Library/LaunchAgents/com.yourdomain.theme-switcher.plistgit clone https://github.com/yourusername/theme-switcher
cd theme-switcher
cargo build --releaseMIT