> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formae.io/llms.txt
> Use this file to discover all available pages before exploring further.

# CLI themes

> Select a built-in CLI theme, choose a light or dark appearance, and author your own theme as a TOML file.

The formae CLI is themeable. A theme controls the colors, glyphs, spinner,
progress bar, and a few behavioral touches used across every interactive screen
(the apply/destroy preview, the live status view, and `formae inventory`).
Themes ship as TOML files: formae has built-in themes compiled into the binary,
and you can drop your own into a directory to add or override one.

## Selecting a theme

Set `cli.theme` in your profile (see [Configuration](/documentation/reference/configuration)):

```pkl theme={"languages":{"custom":["/languages/pkl.json"]}}
cli {
    theme = "rich"
}
```

The value is the name of a built-in theme, or the filename (without `.toml`) of a
theme in `~/.config/formae/themes/`. An unknown name prints a warning that lists
every available theme (the built-ins plus any of your own in
`~/.config/formae/themes/`) and falls back to `quiet`.

### Available themes

formae ships with the following themes:

| Theme              | Description                                                                                                                                                                                                              |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `quiet` (default)  | Restrained. Operations render in a single neutral color — the glyph and the word (for example `+ create`) carry the meaning, not the color. Best when you want a calm, low-color terminal.                               |
| `rich`             | Per-operation colors: create is green, update is blue, delete is olive, replace is orange. Resource labels are accent-colored, the pre-execution confirmation bar is colored by severity, and the logo wordmark is blue. |
| `colorblind`       | A colorblind-safe palette built around a blue/orange pairing rather than red-versus-green, so operation and status states stay distinguishable without relying on those hues.                                            |
| `nord`             | Nord: arctic blues on a cool, dark base.                                                                                                                                                                                 |
| `gruvbox`          | Gruvbox: warm, retro earth tones.                                                                                                                                                                                        |
| `tokyo-night`      | Tokyo Night: deep blue night with neon accents.                                                                                                                                                                          |
| `rose-pine`        | Rosé Pine: muted rose and pine on a soho base.                                                                                                                                                                           |
| `catppuccin-latte` | Catppuccin Latte: soft pastels on a light background.                                                                                                                                                                    |
| `omarchy`          | Derives its palette live from your active [Omarchy](https://omarchy.org) desktop theme and follows OS theme switches. See [Omarchy](#omarchy) below.                                                                     |

The `nord`, `gruvbox`, `tokyo-night`, `rose-pine`, and `catppuccin-latte` themes
reuse `quiet`'s restrained behavior and change only the palette, so glyphs and
layout stay neutral while each operation is tinted from the scheme.

<Note>
  `theme = "formae"` is accepted as an alias for `quiet` so existing configurations
  keep working.
</Note>

Every theme is self-contained, so you can `extends` any of them from your own
theme (see [Inheritance](#inheritance)) to start from its palette and change
glyphs or behavior.

<Note>
  The palettes of the color-scheme themes are derived from the corresponding
  [Omarchy](https://omarchy.org) themes and, in turn, the upstream color schemes:
  [Nord](https://www.nordtheme.com),
  [Gruvbox](https://github.com/morhetz/gruvbox),
  [Tokyo Night](https://github.com/enkia/tokyo-night-vscode-theme),
  [Rosé Pine](https://rosepinetheme.com), and
  [Catppuccin](https://catppuccin.com). All credit for the color work belongs to
  their authors.
</Note>

## Light and dark appearance

Every theme color has both a light and a dark variant. `cli.appearance` chooses
which side is used, independently of the theme:

```pkl theme={"languages":{"custom":["/languages/pkl.json"]}}
cli {
    theme = "rich"
    appearance = "auto"   // "light" | "dark" | "auto"
}
```

* `auto` (default) detects the terminal background.
* `light` / `dark` force the corresponding variant. Use this when auto-detection
  is unreliable — for example inside `tmux`, over SSH, or in a terminal that does
  not report its background color.

The appearance is resolved with the following precedence, highest first:

1. The `FORMAE_APPEARANCE` environment variable (`light` or `dark`) — a one-off
   override that beats the config.
2. `cli.appearance` in the profile, when it is not `auto`.
3. Auto-detection of the terminal background.

```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
FORMAE_APPEARANCE=light formae inventory
```

## Omarchy

On an [Omarchy](https://omarchy.org) desktop, `cli.theme = "omarchy"` makes the
CLI follow your active desktop theme instead of using a fixed palette.

```pkl theme={"languages":{"custom":["/languages/pkl.json"]}}
cli {
    theme = "omarchy"
    appearance = "auto"
}
```

**Where the colors come from.** formae reads your active Omarchy theme's
`colors.toml` (at `~/.config/omarchy/current/theme/colors.toml`) and maps its
values onto formae's semantic palette — `accent` becomes the primary accent and
the logo wordmark, the 16 ANSI colors (`color0`–`color15`) fill the per-operation
and state colors, `background`/`foreground` set surfaces and text, and so on.
Sparse themes fall back per key, so every color slot stays populated. If no
Omarchy theme is present (or its `colors.toml` can't be read), formae warns once
and falls back to the `quiet` theme.

**Light and dark.** With `appearance = "auto"`, an Omarchy theme's own light/dark
declaration is preferred over terminal auto-detection, so a light Omarchy theme
renders formae's light variant and a dark one its dark variant. Setting
`appearance` to `light` or `dark` explicitly still overrides this.

**Live-follow.** Switching your desktop theme while a long-running view is open —
`formae inventory` or the `status` watch — recolors it **in place**, without
restarting the command. formae watches the Omarchy `current/theme` symlink and
re-resolves the theme when your desktop swaps it (the atomic switch that
`omarchy-theme-set` performs), as well as an in-place edit to `colors.toml`.
One-shot commands aren't watched; they pick up the current theme each time they
run.

## Authoring a theme

A custom theme is a TOML file in `~/.config/formae/themes/`. The filename is the
theme name: `~/.config/formae/themes/midnight.toml` is selected with
`cli.theme = "midnight"`. A theme in that directory whose name matches a built-in
shadows the built-in.

The quickest way to start is to copy a built-in theme's structure and change what
you need. A theme has a set of appearance *planes* (`[palette]`, `[glyphs]`,
`[progress]`, `[spinner]`) and a few behavior toggles (`[confirmation_bar]`,
`[header]`, `[rows]`).

### Colors

Every `[palette]` value is either a single hex string used for both appearances,
or a table with explicit `light` and `dark` variants:

```toml theme={"languages":{"custom":["/languages/pkl.json"]}}
[palette]
text_primary   = { light = "#1A1A1A", dark = "#E8E8E8" }
warning        = "#B5B55B"   # same in both appearances
```

`cli.appearance` selects which side of the two-variant colors is used at render
time.

### Inheritance

A theme may declare `extends = "<base>"` to start from another theme and override
only the keys that differ. Inheritance is one level deep — a base that itself
declares `extends` is an error. The built-in themes are self-contained (they do
not use `extends`); inheritance is a convenience for your own themes.

```toml theme={"languages":{"custom":["/languages/pkl.json"]}}
name    = "midnight"
extends = "quiet"

[palette]
primary_accent = { light = "#5E60CE", dark = "#9D4EDD" }
```

A user theme that is missing keys the base does not supply is reported and falls
back to `quiet`, so a theme always renders something complete.

### Palette keys

| Key                                                                         | Used for                                                                            |
| --------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `base`, `surface`                                                           | Panel and elevated-surface backgrounds                                              |
| `text_primary`                                                              | Active, high-emphasis text                                                          |
| `text_secondary`                                                            | Labels and metadata                                                                 |
| `text_subtle`                                                               | Hints and disabled text                                                             |
| `border`                                                                    | Panel borders                                                                       |
| `selection`                                                                 | The cursor-row highlight band                                                       |
| `primary_accent`                                                            | IDs, links, interactive elements                                                    |
| `secondary_accent`                                                          | Brand and callouts (progress fill, section headers)                                 |
| `error`, `error_subtle`, `error_bright`                                     | Failures; dimmed and cursor-row variants                                            |
| `warning`                                                                   | Drift and warnings                                                                  |
| `unmanaged`                                                                 | The `⚠ unmanaged` marker in `formae inventory`                                      |
| `done`, `in_progress`, `pending`                                            | Brightness-based state colors                                                       |
| `op_create`, `op_update`, `op_delete`, `op_replace`, `op_detach`, `op_keep` | Per-operation colors                                                                |
| `logo_wordmark`                                                             | When set, colors the "formae" letters of the logo; the propeller stays brand orange |

### Glyphs

The `[glyphs]` plane maps each semantic symbol to a character. Decorative
separators and panel borders are fixed chrome and are not themeable.

| Group               | Keys                                                                                                       |
| ------------------- | ---------------------------------------------------------------------------------------------------------- |
| Operations          | `op_create`, `op_update`, `op_delete`, `op_replace`, `op_detach`, `op_keep`                                |
| Status              | `status_done`, `status_failed`, `status_pending`, `status_inprogress`, `status_skipped`, `status_canceled` |
| Acknowledgements    | `ack_done`, `ack_skip`, `ack_warn`, `ack_fail`                                                             |
| Tree and disclosure | `tree_branch`, `tree_last`, `expand_open`, `expand_closed`                                                 |
| Miscellaneous       | `checkbox_on`, `checkbox_off`, `transition`                                                                |

<Note>
  Keep glyphs to single-width characters. Some symbols (such as `…`, `✗`, `⚠`)
  are East-Asian-ambiguous and render double-width in certain terminals, which can
  misalign side-by-side panels.
</Note>

### Progress and spinner

```toml theme={"languages":{"custom":["/languages/pkl.json"]}}
[progress]
fill_done       = "█"
fill_inprogress = "▓"
fill_pending    = "░"
animation       = "pulse"    # pulse | blink | static

[spinner]
frames      = ["⠋", "⠙", "⠹", "⠸"]   # explicit frames…
# preset    = "braille"                # …or a preset (frames wins if both are set)
interval_ms = 100
static_frame = "⠋"                     # used for non-animated / static rendering
```

### Behavior toggles

```toml theme={"languages":{"custom":["/languages/pkl.json"]}}
[confirmation_bar]
color = "brand"      # brand | severity

[header]
highlight = "brighten"   # brighten | background

[rows]
label_accent     = false   # color the label column with primary_accent
delete_whole_row = false   # tint the entire row with op_delete on deletes
```

| Setting                  | Values                   | Effect                                                                                                                                                                                           |
| ------------------------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `confirmation_bar.color` | `brand`, `severity`      | `brand` always uses `secondary_accent`; `severity` colors the pre-execution confirmation bar by the most severe operation (delete or replace → `error`, else update → `op_update`, else `done`). |
| `header.highlight`       | `brighten`, `background` | How the navigated/sorted column header is emphasized: `brighten` uses a bright foreground; `background` adds a highlight band.                                                                   |
| `rows.label_accent`      | `true`, `false`          | Render the label column in `primary_accent` (a distinct identifier) instead of the same color as the other columns.                                                                              |
| `rows.delete_whole_row`  | `true`, `false`          | Tint an entire delete row in `op_delete` so destructive changes stand out.                                                                                                                       |

### Minimal example

```toml theme={"languages":{"custom":["/languages/pkl.json"]}}
name = "midnight"

[palette]
primary_accent = { light = "#5E60CE", dark = "#9D4EDD" }
op_create      = { light = "#2A9D8F", dark = "#4ADE80" }
op_delete      = { light = "#D64545", dark = "#F87171" }

[glyphs]
op_create = "+"
op_delete = "-"

[progress]
fill_done       = "█"
fill_inprogress = "▓"
fill_pending    = "░"
animation       = "pulse"

[spinner]
frames      = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧"]
interval_ms = 100
static_frame = "⠋"

[confirmation_bar]
color = "brand"

[header]
highlight = "brighten"

[rows]
label_accent     = false
delete_whole_row = false
```

Save this as `~/.config/formae/themes/midnight.toml`, then select it:

```pkl theme={"languages":{"custom":["/languages/pkl.json"]}}
cli {
    theme = "midnight"
}
```
