@mjakl/pi-dark-or-light

Auto-switch pi between light and dark themes using hierarchical detection

Package details

extension

Install @mjakl/pi-dark-or-light from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@mjakl/pi-dark-or-light
Package
@mjakl/pi-dark-or-light
Version
1.0.0
Published
Mar 7, 2026
Downloads
19/mo · 4/wk
Author
mjakl
License
MIT
Types
extension
Size
17.9 KB
Dependencies
0 dependencies · 1 peer
Pi manifest JSON
{
  "extensions": [
    "./src/index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

pi-dark-or-light

pi-dark-or-light is a pi extension that automatically chooses a dark or light theme for pi.

It is meant for people who want pi to follow the appearance of their system or terminal without hard-coding a single theme value in settings.json.

What it does

  • Detects whether your environment is currently dark or light
  • Applies the matching pi theme when a UI session starts
  • Only runs in UI sessions; it does not do anything in headless/non-UI runs
  • Re-checks every 5 seconds, so appearance changes can be picked up while pi is running
  • Lets you map detected dark / light modes to either pi's built-in themes or your own custom theme names
  • Re-applies the detected theme even if pi persists a top-level theme setting internally

In short: this extension decides dark vs light, and you can optionally decide which actual theme name should be used for each mode.

When the extension is active

This extension manages the theme whenever it is loaded in a UI session.

If pi or another workflow writes a top-level theme into settings.json, this extension still keeps applying the detected dark/light result on startup and during polling.

Installation

Option 1: Install from npm (recommended)

pi install npm:@mjakl/pi-dark-or-light

Option 2: Install via git

pi install git:github.com/mjakl/pi-dark-or-light

Option 3: Install from a local checkout

pi install /path/to/pi-dark-or-light

Option 4: Development or one-off testing

pi -e /path/to/pi-dark-or-light/src/index.ts

Package name: @mjakl/pi-dark-or-light

Quick start

  1. Install the extension.
  2. Optionally add a dark-or-light mapping.

Minimal setup:

{
  "dark-or-light": {
    "dark": "dark",
    "light": "light"
  }
}

Example with custom themes:

{
  "dark-or-light": {
    "dark": "tokyo-night",
    "light": "github-light"
  }
}

If you do not configure a mapping, the extension uses pi's built-in dark and light themes.

For details on pi themes themselves, including built-in and custom theme setup, see pi's own themes documentation.

Configuration

The extension reads settings from the same places pi normally uses:

  • Global: ~/.pi/agent/settings.json
  • Project: .pi/settings.json

Project settings override global settings.

For the extension-specific config, use either:

  • dark-or-light (recommended)
  • darkOrLight (also accepted)

Supported config

{
  "dark-or-light": {
    "dark": "theme-name-for-dark-mode",
    "light": "theme-name-for-light-mode",
    "default": "dark"
  }
}

All keys are optional.

  • dark: theme name to use when detection resolves to dark mode
  • light: theme name to use when detection resolves to light mode
  • default: fallback mode to use when no detector returns an answer; allowed values are dark and light

For example, this is valid too:

{
  "dark-or-light": {
    "dark": "tokyo-night"
  }
}

In that case:

  • detected dark -> tokyo-night
  • detected light -> built-in light

You can also change the final fallback mode. For example:

{
  "dark-or-light": {
    "default": "light",
    "light": "github-light"
  }
}

In that case, if no detector succeeds, the extension chooses light, which then maps to github-light.

Merge behavior

Global and project dark-or-light settings are merged field-by-field, with project settings overriding global ones.

Use the same key spelling in both files if you rely on merging. In other words, do not mix dark-or-light in one file with darkOrLight in the other.

Example:

Global settings:

{
  "dark-or-light": {
    "dark": "tokyo-night",
    "light": "github-light"
  }
}

Project settings:

{
  "dark-or-light": {
    "dark": "gruvbox-dark"
  }
}

Result for that project:

  • dark -> gruvbox-dark
  • light -> github-light

If a mapped theme cannot be loaded

If you map dark or light to a custom theme name and pi cannot apply it, the extension falls back to the built-in dark or light theme for that detected mode.

Detection order and heuristics

The extension uses a fixed detector chain. The first detector that returns a clear answer wins.

Overall order:

  1. macOS native appearance
  2. Windows native appearance
  3. tmux client theme
  4. DARK_MODE environment variable
  5. COLORFGBG heuristic
  6. Fallback to configured default mode (default: dark)

Detectors that do not apply on the current platform are skipped.

How it decides on each operating system

macOS

On macOS, the extension first asks the OS directly:

  • Runs osascript
  • Queries System Events for the current dark mode setting
  • true -> dark
  • false -> light

If that does not return a usable answer, it falls through to the shared terminal-based detectors below.

macOS order:

  1. Native macOS appearance via osascript
  2. tmux #{client_theme}
  3. DARK_MODE
  4. COLORFGBG
  5. Fallback to configured default mode (default: dark)

Windows

On Windows, the extension first checks the user theme setting in the registry:

  • Reads HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize
  • Uses AppsUseLightTheme
  • 0 -> dark
  • 1 -> light

If that fails, it falls through to the shared terminal-based detectors below.

Windows order:

  1. Native Windows appearance via AppsUseLightTheme
  2. tmux #{client_theme}
  3. DARK_MODE
  4. COLORFGBG
  5. Fallback to configured default mode (default: dark)

Linux and other Unix-like systems

There is currently no desktop-environment-specific Linux detector in this extension.

That is intentional: Linux appearance settings vary a lot across GNOME, KDE, sway, Hyprland, remote shells, containers, and headless sessions. Instead of guessing, the extension uses terminal-oriented signals that are more portable.

Linux / other Unix order:

  1. tmux #{client_theme}
  2. DARK_MODE
  3. COLORFGBG
  4. Fallback to configured default mode (default: dark)

Shared detectors

tmux

If pi is running inside tmux, the extension tries:

tmux display-message -p #{client_theme}

Accepted values are normalized case-insensitively:

  • dark
  • light
  • 1 / true -> dark
  • 0 / false -> light

This detector is only attempted when the environment suggests pi is running in tmux (TMUX is set or TERM_PROGRAM=tmux).

DARK_MODE

If the DARK_MODE environment variable is set, the extension accepts these values:

  • dark, 1, true -> dark
  • light, 0, false -> light

This is useful when you want to force the result from a shell profile, wrapper script, launcher, or platform-specific automation.

COLORFGBG

If no stronger detector succeeds, the extension uses COLORFGBG, similar to pi's built-in heuristic.

It parses the second ;-separated field of COLORFGBG. In the common two-part form, that field is the background color index.

  • parses the second ;-separated field
  • if that color index is < 8, it chooses dark
  • otherwise it chooses light

Examples:

  • COLORFGBG=15;0 -> second field 0 -> dark
  • COLORFGBG=0;15 -> second field 15 -> light

If your terminal emits a more unusual multi-part COLORFGBG value, this detector may not apply and the extension will continue down the chain.

Final fallback

If none of the detectors above produce an answer, the extension falls back to the configured dark-or-light.default mode.

Default if unset:

  • dark

Allowed values for dark-or-light.default:

  • dark
  • light

Behavior summary

  • Applies a theme on UI session start
  • Polls every 5 seconds for changes
  • Ignores detector failures and keeps going down the chain
  • Uses project settings over global settings
  • Merges dark-or-light config between global and project settings when both use the same config key spelling

Recommended setup

If you want pi to follow your environment automatically:

  1. Configure dark-or-light if you want custom theme names
  2. Let the extension choose the current mode from OS/terminal signals

If you want a fixed theme instead, disable or remove this extension.

Acknowledgements

This extension was influenced by pi's own macOS theme example:

License

MIT