Configuration
Print the active path instead of assuming it:
theme-agent config pathTypical locations are:
- Linux:
~/.config/theme-agent/config.toml - macOS:
~/Library/Application Support/theme-agent/config.toml - Windows:
%APPDATA%\theme-agent\config.toml
A missing file uses defaults. Saving through the CLI validates the configuration and creates parent directories.
Complete example
Section titled “Complete example”mode = "auto" # light | dark | system | sun | autofallback = "light" # light | dark
[location] # optional except for explicit sun modelatitude = 51.5072longitude = -0.1276
[sun]elevation = -0.833 # valid range: -18 through 18
[theme]light = "catppuccin-latte"dark = "catppuccin-mocha"
[neovim]enabled = true
[hooks]on_light = ["notify-send", "Theme", "light"]on_dark = ["notify-send", "Theme", "dark"]on_start = ["theme-apply", "{theme}"]timeout_secs = 120 # per command; a hung hook is killed and counted as failed
[notifications]hook_failure = true # desktop notification when hooks start failingThe CLI directly edits mode, fallback, and location:
theme-agent config set mode autotheme-agent config set fallback darktheme-agent config set location 51.5072 -0.1276A running daemon watches the file and live-reloads valid changes. A successful reload emits config_changed.
Validation
Section titled “Validation”Latitude must be in [-90, 90], longitude in [-180, 180], and sun elevation in [-18, 18]. Explicit sun mode also requires a location. Invalid configuration is rejected rather than partially applied.
See Modes and scheduling for how system, sun, and fallback inputs resolve.
Hook timing and arguments
Section titled “Hook timing and arguments”on_lightandon_darkrun only when the effective theme transitions. They do not run merely because the daemon starts.on_startruns once after initial resolution, even if no transition occurred. Use it to reconcile tools at login.- In an
on_startargv element,{theme}expands to the currentlightordarkvalue. - Every hook is a complete argv array. Element zero is the executable; the remaining elements are its arguments.
- Hooks run directly without a shell.
$VAR, pipes, globs, and other shell interpolation are not supported. - A leading
~or~/is expanded in every argv element, including the executable. - Transition hooks (
on_light/on_dark) run off the daemon event loop, but theme-application sequences are serialized so overlapping transitions cannot finish out of order. - A
theme_changedevent is published only after the selected transition hook and enabled dependent integrations have finished. Consumers can therefore read files written by the hook without racing it. on_startis different: startup reconciliation completes before IPC is exposed and beforedaemon_readyis broadcast, so an initial status/read cannot observe stale external theme files.- A launch or non-zero hook failure is logged; dependent integrations are skipped, but the resolved transition is still broadcast after the failed sequence completes.
- Hook output (stdout + stderr) is captured: success is logged at
infowith its duration, failure atwarnwith the exit status and the last 20 lines (≤ 4 KiB) of output. A command running longer thanhooks.timeout_secs(default 120, minimum 1) is killed with any processes it started and counts as a failure.
For example:
[hooks]on_light = ["~/.local/bin/theme-apply", "--light"]on_dark = ["~/.local/bin/theme-apply", "--dark"]on_start = ["~/.local/bin/theme-apply", "--theme", "{theme}"]Failures, retries, and the daemon log
Section titled “Failures, retries, and the daemon log”Each hook run’s result appears in theme-agent status as Last apply: (for example dark FAILED 2026-10-17 19:40 (transition): exit 1: No active theme selected) and in status --json as last_apply with theme, trigger (transition, start, retry, manual), ok, at, attempt, and detail. Only the theme hook decides ok; integration failures are logged only.
If the hook fails while its theme is still effective, the daemon retries the same hook after 30 s, 2 min, 5 min, 15 min, 30 min, then hourly, shown as Next retry: / next_retry. Deadlines are wall-clock based, so a retry missed during sleep runs soon after wake. A new transition, a success, or theme-agent reapply replaces the pending retry.
The first failure of a streak raises a desktop notification (osascript on macOS, notify-send on Linux when installed, none on Windows); set [notifications] hook_failure = false to disable it. Run theme-agent reapply to retry immediately.
theme-agent daemon also logs to a file, rotated at startup past 1 MiB (one daemon.log.1 kept): ~/Library/Logs/theme-agent/daemon.log on macOS, $XDG_STATE_HOME/theme-agent/daemon.log (default ~/.local/state/…) on Linux, %LOCALAPPDATA%\theme-agent\logs\daemon.log on Windows. THEME_AGENT_LOG_FILE overrides the path.
Currently serialized but unused fields
Section titled “Currently serialized but unused fields”theme.light, theme.dark, and neovim.enabled are part of the serialized schema, but the Rust daemon and bundled Lua plugin do not currently consume them. The plugin uses its own colorschemes and behavior options. Do not rely on these TOML fields to change a client until explicit plumbing is added.