Skip to content

Configuration

Print the active path instead of assuming it:

Terminal window
theme-agent config path

Typical 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.

mode = "auto" # light | dark | system | sun | auto
fallback = "light" # light | dark
[location] # optional except for explicit sun mode
latitude = 51.5072
longitude = -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 failing

The CLI directly edits mode, fallback, and location:

Terminal window
theme-agent config set mode auto
theme-agent config set fallback dark
theme-agent config set location 51.5072 -0.1276

A running daemon watches the file and live-reloads valid changes. A successful reload emits config_changed.

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.

  • on_light and on_dark run only when the effective theme transitions. They do not run merely because the daemon starts.
  • on_start runs once after initial resolution, even if no transition occurred. Use it to reconcile tools at login.
  • In an on_start argv element, {theme} expands to the current light or dark value.
  • 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_changed event 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_start is different: startup reconciliation completes before IPC is exposed and before daemon_ready is 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 info with its duration, failure at warn with the exit status and the last 20 lines (≤ 4 KiB) of output. A command running longer than hooks.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}"]

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.

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.