Skip to content

Instantly share code, notes, and snippets.

@davemo
Last active May 7, 2026 22:02
Show Gist options
  • Select an option

  • Save davemo/953cfb5b9fc6ac0a6a3e8b7f89f9991c to your computer and use it in GitHub Desktop.

Select an option

Save davemo/953cfb5b9fc6ac0a6a3e8b7f89f9991c to your computer and use it in GitHub Desktop.
Test Double theme for pi

Test Double pi theme + header

A pi TUI theme inspired by Test Double's green/purple/orange palette, plus an optional startup header extension with an ASCII Test Double logo.

Install theme

mkdir -p ~/.pi/agent/themes
curl -L https://gist.githubusercontent.com/davemo/953cfb5b9fc6ac0a6a3e8b7f89f9991c/raw/test-double.json \
  -o ~/.pi/agent/themes/test-double.json

Then select test-double from /settings, or set it in your pi settings:

{
  "theme": "test-double"
}

Install startup header

mkdir -p ~/.pi/agent/extensions
curl -L https://gist.githubusercontent.com/davemo/953cfb5b9fc6ac0a6a3e8b7f89f9991c/raw/test-double-header.ts \
  -o ~/.pi/agent/extensions/test-double-header.ts

Restart pi, or run /reload if pi is already open. The header extension replaces the built-in startup header. Run /builtin-header to restore the default header for the current session.

Pi hot-reloads custom themes, so edits to ~/.pi/agent/themes/test-double.json should show up immediately. Extensions reload via /reload.

import type { ExtensionAPI, Theme } from "@earendil-works/pi-coding-agent";
const TD_LOGO = [
" ▄ ▄███ ▄███▄ ▄▄█▄▄",
" ▄████ ▄███▄ ██▀███ ██▀▀██ ███▀██",
" ▄██▀██ ▄██▀██ ███ ██▀ ▄█▀ ▄██ ██▀ ▄██",
" ██▀▄██ ▄██ ██▀ ███ ██ ██ ██▀ ▄██ ██",
"▄▄ ▄██▄██ ▄▄▄██████ ███ ██ ██▀ ██▀ ██ ██▀",
"▀▀▀█████████ ▄▄▄▄ ▄▄ ▀▀▀█████████▀ ███▄█▀ ▄▄▄▄▄ ▄▄▄ ▄▄ ██ ██▀ ▄██ ██▀ ▄▄▄",
" ███▀ ███▀██ ▄███ ███▀ ▄███████▀ ▄████████████ ██▀ ▄███████▄ ██████ ███▀██▄",
" ███ ███ ▄██ ▄███▄ ███ ███▀ ████ ▄██▀ ██▄ ███ ███ ███▀ ██ █████ ███ ▄██",
" ██ ▄█████▀ ▄██▀██ ███ ███ ███ ███ ██▀ ███ ▄██▀ ███ ██▀ ████ █████▀ ▄█",
" ███▄ ▄▄████▄ ▄▄███ ███▄▄████▄ ▄▄████ ███▄▄████▄ ▄██ ██▄▄████▄▄██▄▄▄███▄█████ ▄████▄ ▄▄██▀",
" ▀████▀ ▀█████▀▀██████▀▀ ▀█████▀ ▀████▀▀███▀▀▀████▀ ████▀▀███▀ ▀██████▀▀ ▀████▀ ▀█████▀",
];
function center(line: string, width: number): string {
const trimmed = line.replace(/\s+$/, "");
if (trimmed.length >= width) return trimmed.slice(0, width);
return " ".repeat(Math.floor((width - trimmed.length) / 2)) + trimmed;
}
function renderHeader(theme: Theme, width: number): string[] {
const logo = width < 28 ? ["td"] : TD_LOGO;
const styledLogo = logo.map((line) => theme.fg("text", center(line, width)));
const subtitle = center("test double pi", width);
return [
"",
...styledLogo,
theme.fg("accent", subtitle),
"",
];
}
export default function (pi: ExtensionAPI) {
pi.on("session_start", (_event, ctx) => {
if (!ctx.hasUI) return;
ctx.ui.setHeader((_tui, theme) => ({
render(width: number) {
return renderHeader(theme, width);
},
invalidate() {},
}));
});
pi.registerCommand("builtin-header", {
description: "Restore the built-in pi startup header",
handler: async (_args, ctx) => {
ctx.ui.setHeader(undefined);
ctx.ui.notify("Built-in pi header restored", "info");
},
});
}
{
"$schema": "https://raw.githubusercontent.com/earendil-works/pi-mono/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
"name": "test-double",
"vars": {
"tdGreen": "#75FE04",
"tdGreenSoft": "#BBFF82",
"tdPurple": "#4D0AED",
"tdPurpleLight": "#A580F9",
"tdPurplePale": "#9368FA",
"tdOrange": "#D63C00",
"tdOffWhite": "#F0F0F0",
"tdDark": "#131413",
"tdBlack": "#050505",
"gray": "#758696",
"dimGray": "#5D6C7B",
"darkGray": "#373737",
"selectedBg": "#25145A",
"userMsgBg": "#1C102D",
"customMsgBg": "#201738",
"toolPendingBg": "#15131B",
"toolSuccessBg": "#111A10",
"toolErrorBg": "#24110C"
},
"colors": {
"accent": "tdGreen",
"border": "tdPurplePale",
"borderAccent": "tdGreen",
"borderMuted": "darkGray",
"success": "tdGreen",
"error": "tdOrange",
"warning": "tdGreenSoft",
"muted": "gray",
"dim": "dimGray",
"text": "tdOffWhite",
"thinkingText": "gray",
"selectedBg": "selectedBg",
"userMessageBg": "userMsgBg",
"userMessageText": "tdOffWhite",
"customMessageBg": "customMsgBg",
"customMessageText": "tdOffWhite",
"customMessageLabel": "tdPurpleLight",
"toolPendingBg": "toolPendingBg",
"toolSuccessBg": "toolSuccessBg",
"toolErrorBg": "toolErrorBg",
"toolTitle": "tdGreen",
"toolOutput": "tdOffWhite",
"mdHeading": "tdGreen",
"mdLink": "tdPurpleLight",
"mdLinkUrl": "dimGray",
"mdCode": "tdGreenSoft",
"mdCodeBlock": "tdOffWhite",
"mdCodeBlockBorder": "tdPurplePale",
"mdQuote": "gray",
"mdQuoteBorder": "tdPurple",
"mdHr": "darkGray",
"mdListBullet": "tdGreen",
"toolDiffAdded": "tdGreen",
"toolDiffRemoved": "tdOrange",
"toolDiffContext": "gray",
"syntaxComment": "#758696",
"syntaxKeyword": "tdPurpleLight",
"syntaxFunction": "tdGreenSoft",
"syntaxVariable": "tdOffWhite",
"syntaxString": "tdGreen",
"syntaxNumber": "#FFB07A",
"syntaxType": "tdPurplePale",
"syntaxOperator": "tdGreen",
"syntaxPunctuation": "gray",
"thinkingOff": "darkGray",
"thinkingMinimal": "dimGray",
"thinkingLow": "tdPurple",
"thinkingMedium": "tdPurplePale",
"thinkingHigh": "tdPurpleLight",
"thinkingXhigh": "tdGreen",
"bashMode": "tdOrange"
},
"export": {
"pageBg": "#0E0F0E",
"cardBg": "#17131F",
"infoBg": "#25145A"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment