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:

  1. System themes: /usr/share/omarchy/themes/<name>/ (installed from the themes/<name>/ source tree)
  2. 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:

  1. Highest: Hand-written files in the theme directory (shell.toml, hyprland.lua)
  2. Middle: Generated files from template rendering
  3. 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.toml as the mandatory palette definition, with optional hand-written overrides for specific components.
  • The omarchy-theme-set pipeline 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →