How Themes Are Structured and Applied in Omarchy: A Complete Technical Guide
Omarchy's theming system uses a directory-based structure with a colors.toml palette and a runtime generation pipeline that renders templates and applies configuration to the desktop shell.
In Omarchy, the Basecamp-developed open-source desktop environment, themes are not monolithic packages but modular, composable configurations. This article explains exactly how theme files are organized, how the omarchy-theme-set command transforms static palettes into active system configuration, and how you can extend or override themes with your own customizations.
Theme Directory Structure and Core Files
Omarchy themes follow a strict directory convention. The colors.toml file is mandatory—everything else is optional.
System and User Theme Locations
Themes ship in two locations:
- System themes:
/usr/share/omarchy/themes/<name>/(installed from thethemes/<name>/source tree) - User themes:
~/.config/omarchy/themes/<name>/
User themes overlay system themes, allowing you to override specific files without forking the entire theme.
Required and Optional Theme Files
| File | Purpose |
|---|---|
colors.toml |
Required. Defines the complete color palette |
shell.toml |
Optional hand-written shell configuration |
hyprland.lua |
Optional Hyprland window manager overrides |
icons.theme |
Optional icon theme specification |
keyboard.rgb |
Optional keyboard RGB lighting profile |
preview.png |
Optional preview image for theme selectors |
As documented in docs/theming.md, hand-written files like shell.toml or hyprland.lua take precedence over generated defaults. This lets theme authors selectively customize behavior while still benefiting from template generation for standard components.
The Theme Generation Pipeline
The omarchy-theme-set <name> command implements a four-stage pipeline for applying themes. Understanding this pipeline is essential for debugging theme issues or creating custom themes.
Stage 1: Staging Area Creation
The command creates a clean directory at ~/.local/state/omarchy/current/next-theme:
STAGE="$HOME/.local/state/omarchy/current/next-theme"
mkdir -p "$STAGE"
Stage 2: File Population and Overlay
First-party files copy from the system location, then user customizations overlay on top:
# Copy base theme
cp -a "/usr/share/omarchy/themes/$THEME/." "$STAGE/"
# Overlay user customizations if present
[[ -d "$HOME/.config/omarchy/themes/$THEME" ]] && \
cp -a "$HOME/.config/omarchy/themes/$THEME/." "$STAGE/"
This overlay pattern means a user theme only needs to contain files that differ from the system theme.
Stage 3: Template Rendering
The omarchy-theme-set-templates command processes all .tpl files in default/themed/:
# Only runs if colors.toml exists in the staged theme
[[ -f "$STAGE/colors.toml" ]] && omarchy-theme-set-templates "$STAGE"
Template files like shell.toml.tpl and hyprland.lua.tpl receive values from colors.toml and render to their non-.tpl counterparts. The source files remain in default/themed/*.tpl and are not modified.
Stage 4: Atomic Activation and Hooks
The staged theme moves into place, metadata records the theme name, and post-theme actions execute:
CURRENT="$HOME/.local/state/omarchy/current/theme"
# Atomic replacement
mv "$STAGE" "$CURRENT"
echo "$THEME" >"$HOME/.local/state/omarchy/current/theme.name"
# Execute hooks and restart/retint commands
# (internal dispatch via omarchy-theme-set)
Template Rendering and Precedence Rules
The template system in Omarchy prioritizes explicit configuration over generated defaults.
How Templates Work
Templates in default/themed/*.tpl use the palette defined in colors.toml. For example, a template might reference {{accent}} or {{background}} and receive the corresponding hex values.
Precedence Hierarchy
When multiple sources define the same configuration:
- Highest: Hand-written files in the theme directory (
shell.toml,hyprland.lua) - Middle: Generated files from template rendering
- Lowest: Default values built into applications
This hierarchy, documented in docs/theming.md lines 31-34, ensures that theme authors retain fine-grained control where needed while avoiding repetitive boilerplate.
Gradient Support and Special Keys
Omarchy's theme system supports both solid colors and Hyprland-style gradients for specific keys.
The hyprland_active_border key demonstrates this flexibility. A theme may define:
# Solid color fallback
accent = "#7aa2f7"
# Or explicit gradient
hyprland_active_border = "rgba(7aa2f7ee) rgba(bb9af7ee) 45deg"
If hyprland_active_border is absent, the system automatically falls back to the accent color. This pattern, described in docs/theming.md lines 137-153, allows themes to opt into advanced visual effects without requiring gradient definitions for every property.
Hooks and Post-Theme Actions
After theme activation, Omarchy notifies dependent components through two mechanisms.
User-Defined Hooks
Scripts matching ~/.config/omarchy/hooks/theme-set* execute with the theme name as $1:
#!/bin/bash
# ~/.config/omarchy/hooks/theme-set-notify
theme_name="$1"
notify-send "Theme changed" "Now using: $theme_name"
System Post-Theme Commands
The bin/omarchy-theme-set script maintains a post_theme_commands list that restarts or retints applications needing to observe color changes. This includes:
- Terminal emulators
- Status bars
- Background tools
The exact commands depend on the Omarchy version and installed components.
Runtime State and Active Theme Location
The directory ~/.local/state/omarchy/current/ serves as the single source of truth for the running theme:
| Path | Contents |
|---|---|
~/.local/state/omarchy/current/theme/ |
Fully resolved theme files (generated + hand-written) |
~/.local/state/omarchy/current/theme.name |
Plain text name of active theme |
~/.local/state/omarchy/current/next-theme/ |
Temporary staging area during theme switch |
As noted in docs/update-process.md lines 26-29, applications and shell components read from this runtime directory rather than directly from /usr/share/omarchy/themes/ or ~/.config/omarchy/themes/.
Practical Commands for Theme Management
# List all available themes (built-in and user)
omarchy theme list
# Apply a theme by exact name
omarchy theme set "Tokyo Night"
# Preview color ramp without installing
omarchy dev theme-preview "Tokyo Night"
The omarchy-theme-set binary underlies these commands. Direct invocation is possible but requires valid theme name validation that the omarchy CLI wrapper provides.
Key Implementation Files
| File | Role |
|---|---|
docs/theming.md |
Authoritative theme format and pipeline documentation |
bin/omarchy-theme-set |
Entry point for theme validation, staging, rendering, activation, and hooks |
install/user/theme.sh |
User-side helper creating symlinks for theme-aware applications |
default/themed/*.tpl |
Template files rendered with colors.toml values |
themes/<name>/colors.toml |
System theme color palettes |
Summary
- Themes require
colors.tomlas the mandatory palette definition, with optional hand-written overrides for specific components. - The
omarchy-theme-setpipeline stages, overlays, renders templates, and atomically activates themes to~/.local/state/omarchy/current/. - User themes in
~/.config/omarchy/themes/overlay system themes without requiring full copies. - Hand-written files win over generated templates, which win over application defaults.
- Hooks and post-theme commands notify the shell and applications of color changes after activation.
Frequently Asked Questions
What is the minimum required file for an Omarchy theme?
A valid Omarchy theme requires only colors.toml containing the color palette. All other files—shell.toml, hyprland.lua, icons, and preview images—are optional. The omarchy-theme-set command will generate default configurations from templates using the palette values.
How do I override a built-in theme without modifying system files?
Create a directory at ~/.config/omarchy/themes/<name>/ matching the system theme name, then place only the files you want to override. The overlay system in bin/omarchy-theme-set copies your files on top of the system theme during staging. Your changes persist across Omarchy updates.
Why does my theme change not apply immediately to some applications?
Applications must explicitly observe the ~/.local/state/omarchy/current/ directory or respond to the post-theme hook mechanism. The post_theme_commands list in bin/omarchy-theme-set handles restarts for known applications; others may need custom hook scripts in ~/.config/omarchy/hooks/theme-set*.
Can I use gradients instead of solid colors for window borders?
Yes. Define hyprland_active_border as a Hyprland-style gradient string in colors.toml (for example, rgba(7aa2f7ee) rgba(bb9af7ee) 45deg). If this key is absent, Omarchy automatically falls back to the accent color as a solid border.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →