How Omarchy’s Template System Works for Theme Generation: A Deep Dive into the Palette-to-Config Pipeline

Omarchy generates themed configuration files through a three-stage pipeline: resolving semantic color palettes from colors.toml, rendering *.tpl templates with sed-based substitution including color mixing and gradients, and applying shell-specific overrides.

Omarchy is the declarative desktop environment from Basecamp that automates Linux desktop theming. At the heart of its customization engine lies a sophisticated template system that transforms abstract color definitions into concrete configuration files for Hyprland, terminals, GTK, and shell components.

Overview of the Three-Stage Theme Pipeline

The template rendering process is orchestrated by the omarchy-theme-set command, which prepares a clean staging directory at ~/.local/state/omarchy/current/next-theme. According to the implementation in bin/omarchy-theme-set-templates, the system processes themes through three distinct phases: palette resolution, template rendering, and shell-specific overrides.

Stage 1: Palette Resolution with omarchy-theme-color

The foundation of every theme begins with a colors.toml file defining semantic palette keys like background, foreground, accent, red, and blue.

Parsing and Deriving Colors

The script bin/omarchy-theme-color handles the heavy lifting of palette normalization:

  • Legacy alias resolution: Converts older color key names to current semantic equivalents
  • Missing shade derivation: Automatically calculates intermediate colors when specific shades are undefined
  • Mode information injection: Adds metadata about the theme's light or dark mode characteristics

This resolved palette serves as the variable lookup table for all subsequent template processing.

Stage 2: Template Rendering Engine

The command omarchy-theme-set-templates drives the core transformation logic. It scans for *.tpl files in two locations: the built-in default/themed/ directory and the user directory at ~/.config/omarchy/themed/.

Simple Colour Placeholders

The add_template_value function creates sed substitution rules for basic color references. Templates use double-curly syntax:

foreground = "{{ foreground }}"
background = "{{ background }}"
cursor     = "{{ cursor }}"

When colors.toml defines foreground = "#a9b1d6", the engine replaces the placeholder with that exact hex value in the rendered output.

Extended Color Formats

For each semantic color, the system generates three variants automatically:

  • {{ accent }} – Full hex value (e.g., #7aa2f7)
  • {{ accent_strip }} – Hex without hash (e.g., 7aa2f7)
  • {{ accent_rgb }} – Decimal RGB tuple (e.g., 122, 162, 247)

Colour Mixing with mix_color

The add_mix_values function and mix_color helper enable fluid color interpolation using the syntax:

selection_background       = "{{ mix background foreground 15% }}"
selection_background_strip = "{{ mix_strip background foreground 15% }}"
selection_background_rgb   = "{{ mix_rgb background foreground 15% }}"

This blends 15% of the foreground color over the background color, outputting the result in three different formats for various application requirements.

Gradient Helpers for Hyprland

The add_gradient_function_values function processes advanced gradient syntax for window managers. It invokes hypr_gradient_value, gradient_start_value, and shell_gradient_value depending on the template context:

local active_border_color = {{ hypr_gradient hyprland_active_border accent }}

If colors.toml contains hyprland_active_border = "rgba(33ccffee) rgba(00ff99ee) 45deg", the rendered Lua becomes:

local active_border_color = { colors = { "rgba(33ccffee)", "rgba(00ff99ee)" }, angle = 45 }

When the key is missing, the system falls back to the accent color, generating a solid color definition instead.

Template Precedence: User Overrides

The rendering order is critical: user templates are processed first, then built-in templates from default/themed/. This precedence ensures that a user-created ~/.config/omarchy/themed/gtk.css.tpl completely overrides the default template, allowing deep customization without modifying core files.

The command also respects existing files in the staging directory—it never overwrites files that may have been copied from theme-specific folders during the initial setup phase.

Stage 3: Shell-Specific Overrides

After generic template rendering completes, the apply_shell_section_overrides function processes per-section configuration files. These take the form shell.<section>.toml (e.g., shell.lock.toml) found in the theme directory.

The function merges these overrides into the main shell.toml by stripping the original section header and inserting the new body content. This allows themes to customize specific shell behavior—such as lock screen appearance—without duplicating the entire shell configuration.

Triggering the Complete Workflow

The entry point omarchy-theme-set <name> coordinates the entire process:

  1. Creates a clean staging directory at ~/.local/state/omarchy/current/next-theme
  2. Copies raw theme files into the staging area
  3. Executes omarchy-theme-set-templates (only when colors.toml exists)
  4. Promotes the staging directory to the active theme location

This workflow is documented in docs/theming.md within the basecamp/omarchy repository.

Practical Template Syntax Reference

The following patterns demonstrate the full capabilities of the template engine:

Basic color substitution in terminal.toml.tpl:

foreground = "{{ foreground }}"
background = "{{ background }}"

Proportional color mixing:

selection_bg = "{{ mix background foreground 15% }}"

Hyprland gradient generation:

local border = {{ hypr_gradient hyprland_active_border accent }}

User override example:

Creating ~/.config/omarchy/themed/gtk.css.tpl with custom CSS referencing {{ accent }} ensures your version takes precedence over default/themed/gtk.css.tpl.

Summary

  • The bin/omarchy-theme-color script resolves colors.toml into a complete semantic palette with derived shades and mode metadata.
  • bin/omarchy-theme-set-templates renders *.tpl files using sed substitution, supporting simple placeholders, mix_color blending, and Hyprland gradient generation via add_gradient_function_values.
  • User templates in ~/.config/omarchy/themed/ override built-in templates from default/themed/ due to processing order.
  • apply_shell_section_overrides merges shell.<section>.toml files into the final shell configuration.
  • The workflow is triggered by omarchy-theme-set, which stages files in ~/.local/state/omarchy/current/next-theme before activation.

Frequently Asked Questions

How do I override a built-in template with my own version?

Create a file with the same name in ~/.config/omarchy/themed/. The omarchy-theme-set-templates command processes user templates before built-in ones, so your version takes precedence. For example, placing a custom gtk.css.tpl in your user directory will override the default theme's GTK styling.

What syntax do I use to blend two colors in a template?

Use the {{ mix ... }} syntax with the format: {{ mix background foreground 15% }}. The engine supports three variants: mix for standard hex output, mix_strip for hex without the hash character, and mix_rgb for decimal RGB values. The percentage argument controls the opacity of the second color over the first.

How does the Hyprland gradient helper function work?

The {{ hypr_gradient ... }} placeholder, processed by hypr_gradient_value, parses gradient definitions from colors.toml and outputs Lua table syntax. If you define hyprland_active_border = "rgba(33ccffee) rgba(00ff99ee) 45deg", it generates a table with colors array and angle property. If the specified key is missing, it falls back to the solid color specified as the second argument.

Where are the rendered configuration files stored?

The active theme files are staged in ~/.local/state/omarchy/current/next-theme during generation, then promoted to the active location. User-specific template sources belong in ~/.config/omarchy/themed/, while built-in templates reside in default/themed/ within the Omarchy installation directory.

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 →