# How to Add Custom Themes to the pi‑AI Interface: A Complete Guide

> Learn to add custom themes to the pi-AI interface by creating JSON files for palettes and overrides. Customize your pi-mono experience today!

- Repository: [Mario Zechner/pi-mono](https://github.com/badlogic/pi-mono)
- Tags: how-to-guide
- Published: 2026-02-16

---

**To add custom themes to the pi‑AI interface, create a JSON file in `$HOME/.pi/themes/` defining a `palette` and component-specific overrides, then select it via `Ctrl+T` or the `--theme` flag.**

The pi‑AI interactive coding agent in the `badlogic/pi-mono` repository supports user-defined visual themes through JSON configuration files. By placing properly structured theme files in a specific directory, you can override the built-in color schemes and instantly apply your custom branding or preferred color palette.

## Where pi‑AI Looks for Custom Themes

The application discovers user themes by calling `getCustomThemesDir()` defined in [[`packages/coding-agent/src/config.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/config.ts)](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/config.ts). By default, this function returns:

```text
$HOME/.pi/themes

```

Any file ending in `.json` placed inside this directory is automatically scanned at startup and made available in the theme selector.

## Creating a Custom Theme JSON File

To add custom themes to the pi‑AI interface, you must provide a JSON object that follows the schema defined in [[`packages/coding-agent/src/modes/interactive/theme/theme.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/modes/interactive/theme/theme.ts)](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/modes/interactive/theme/theme.ts). The core functions `loadThemeJson`, `loadThemeFromPath`, and `loadTheme` parse this structure at runtime.

### The Theme JSON Schema

A valid theme file requires at minimum:

- **`palette`**: An object mapping symbolic color names (e.g., `background`, `foreground`, `accent`) to ANSI color codes or 24‑bit hex strings (`#rrggbb`).
- **Component overrides** (optional): Objects named after UI components (`editor`, `markdown`, `selectList`, etc.) that reference palette keys to customize specific elements.

Only the keys you provide override the defaults; missing values are inherited from the built‑in dark theme.

### Minimal Theme Example

Create a file at `$HOME/.pi/themes/my-dark.json`:

```json
{
  "palette": {
    "background": "#1e1e1e",
    "foreground": "#d4d4d4",
    "accent": "#569cd6",
    "error": "#f44747",
    "warning": "#ff8800",
    "info": "#9cdcfe"
  },
  "editor": {
    "cursorColor": "accent",
    "selectionBg": "#264f78",
    "lineNumberFg": "#858585"
  },
  "markdown": {
    "heading": "accent",
    "codeBlockBorder": "info",
    "quote": "warning"
  }
}

```

The filename without the extension becomes the theme name displayed in the UI (`my-dark`).

## Activating and Hot‑Reloading Custom Themes

Once you add custom themes to the pi‑AI interface, you can activate them through two methods:

1. **Interactive selector**: Press `Ctrl+T`, navigate to **Theme**, and select your custom theme from the list.
2. **Command line**: Launch pi‑AI with the `--theme=my-dark` flag to apply the theme immediately on startup.

### Hot-Reload During Development

The theme system watches custom theme files for changes. When you modify the active theme JSON while pi‑AI is running, the watcher triggers `setGlobalTheme(loadTheme(name))` (implemented in [`theme.ts`](https://github.com/badlogic/pi-mono/blob/main/theme.ts)), reloading the file instantly without requiring a restart. This provides immediate visual feedback while you fine-tune color values.

## Key Source Files and Implementation Details

Understanding these files helps when you need to debug or extend theme functionality:

| File | Purpose | Link |
|------|---------|------|
| [`packages/coding-agent/src/config.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/config.ts) | Defines `getCustomThemesDir()` which resolves the `$HOME/.pi/themes` path. | [View source](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/config.ts) |
| [`packages/coding-agent/src/modes/interactive/theme/theme.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/modes/interactive/theme/theme.ts) | Core loader functions (`loadThemeJson`, `loadThemeFromPath`, `loadTheme`) and hot-reload logic via `setGlobalTheme()`. | [View source](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/modes/interactive/theme/theme.ts) |
| [`packages/coding-agent/docs/themes.md`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/themes.md) | Human-readable documentation of the full theme JSON schema and palette conventions. | [View docs](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/themes.md) |
| [`packages/tui/test/test-themes.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/tui/test/test-themes.ts) | Reference implementations showing the complete shape of built-in theme objects. | [View tests](https://github.com/badlogic/pi-mono/blob/main/packages/tui/test/test-themes.ts) |

## Summary

- **Location**: Place theme JSON files in `$HOME/.pi/themes/` (returned by `getCustomThemesDir()` in [`config.ts`](https://github.com/badlogic/pi-mono/blob/main/config.ts)).
- **Format**: Define a `palette` object with color mappings and optional component overrides following the schema in [`theme.ts`](https://github.com/badlogic/pi-mono/blob/main/theme.ts).
- **Activation**: Select via `Ctrl+T` → Theme, or launch with `--theme=<filename>`.
- **Development**: Edit files while running to trigger hot-reload through `setGlobalTheme(loadTheme(name))`.

## Frequently Asked Questions

### Where does pi‑AI store custom themes on disk?

By default, pi‑AI looks for custom themes in `$HOME/.pi/themes`. This path is determined by the `getCustomThemesDir()` function located in [`packages/coding-agent/src/config.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/config.ts). You can create this directory manually if it does not exist.

### What is the minimum required structure for a theme JSON file?

At minimum, a theme file must contain a `palette` object mapping symbolic names like `background`, `foreground`, and `accent` to color values (hex codes or ANSI values). All other properties are optional; missing component-specific keys inherit from the built-in dark theme. The full schema is defined in [`packages/coding-agent/src/modes/interactive/theme/theme.ts`](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/src/modes/interactive/theme/theme.ts).

### Do I need to restart pi‑AI after editing a custom theme?

No. The theme system watches custom files for changes and automatically reloads the active theme by calling `setGlobalTheme(loadTheme(name))` as implemented in [`theme.ts`](https://github.com/badlogic/pi-mono/blob/main/theme.ts). This hot-reload functionality provides immediate visual feedback while you adjust colors.

### Can I distribute themes via the command line?

Yes. You can activate any custom theme at startup by passing the `--theme=<name>` flag, where `<name>` matches the JSON filename without the extension. This is useful for scripting or sharing consistent environments across different machines.