# Kun's Pi Agent Config

> Source: <https://blog.kunchenguid.com/p/kuns-pi-agent-config>
> Published: 2026-08-01 19:11:24+00:00

# Kun's Pi Agent Config

### Minimal, practical, and elegant

It’s the 67th time I got asked how I’ve configured my Pi agent - it’s time to write it down and share! This is not going to be “here’s 100 fancy tricks you can do with Pi”. This is “here’s what I actually use and can’t live without.”

## When and why do I use Pi

I use Pi heavily for any model that’s not Claude, because Anthropic banned 3rd party harnesses from using their subscription quota. There are some workarounds, but none is perfect - so for Claude I’m stuck with Claude Code. For any other LLM, I pretty much only use Pi at this point, barring some exceptions.

I pick Pi because it’s provider-neutral, minimal, and deeply customizable. I believe this is how agent harnesses should be, because the AI models are constantly advancing, and the harness needs to be flexible enough to evolve with them.

## Main settings

`~/.pi/agent/settings.json`

```
{
  "images": {
    "blockImages": false
  },
  "terminal": {
    "showImages": false
  },
  "hideThinkingBlock": true,
  "quietStartup": true,
  "theme": "rose-pine-moon",
  "steeringMode": "all",
  "followUpMode": "all",
  "collapseChangelog": true,
  "packages": [
    "npm:pi-web-access@0.14.0",
    "npm:@ryan_nookpi/pi-extension-codex-fast-mode@0.2.6",
    "git:github.com/algal/pi-openai-server-compaction@c6d593087709e9481223dc6c6c2269b371b5e055"
  ]
}
```

Some of these are personal preferences, but a few important ones -

`hideThinkingBlock`

helps create a less noisy terminal. I don’t find any value in watching what the LLM is thinking in its own head.`steeringMode=all`

is a no-brainer because if I sent multiple steering prompts I of course want all of them to go out asap.`followUpMode=all`

is important to me because I like to keep queuing follow up prompts when the model is working. Having all of the queued prompts sent all at once is a lot more efficient than letting them go out one by one.

## 3rd party extensions

You can see from the settings file above I only have a few 3rd party extensions. I’ll quickly explain what they are and why I use them here.

`pi-web-access`

is a no-brainer because the stock Pi is so minimal that it doesn’t even have the ability to search and browse web content.`pi-extension-codex-fast-mode`

is what allows me to activate fast mode when using gpt models. It’s a very simple extension that just has an on/off toggle to control whether requests to Codex backend activates fast mode. Fast mode uses 2x tokens for 2.5x speed, so use it with the tradeoff in mind.`pi-openai-server-compaction`

makes Pi use OpenAI’s secret sauce “server side compaction” whenever the context window is too long and needs to be compacted. The server side compaction is what Codex uses by default, and is what makes Codex so good at long running tasks despite gpt models have a short context window there.

## Model overrides

`~/.pi/agent/models.json`

```
{
  "providers": {
    "openai-codex": {
      "modelOverrides": {
        "gpt-5.6-luna": {
          "contextWindow": 272000
        },
        "gpt-5.6-sol": {
          "contextWindow": 272000
        },
        "gpt-5.6-terra": {
          "contextWindow": 272000
        }
      }
    }
  }
}
```

This is an interesting one. OpenAI’s gpt models actually can support longer context requests, but whenever the request goes above 272k input tokens, it will double the cost. See [https://developers.openai.com/api/docs/pricing](https://developers.openai.com/api/docs/pricing) for details.

The settings above makes Pi set the context window length for those models at 272k, so whenever the request becomes larger than that, it will do compaction and dial it back down. This helps avoid draining our quota or API cost more quickly than we want.

## Color theme

`~/.pi/agent/themes/rose-pine-moon.json`

```
{
  "$schema": "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
  "name": "rose-pine-moon",
  "vars": {
    "base": "#232136",
    "surface": "#2a273f",
    "overlay": "#393552",
    "muted": "#6e6a86",
    "subtle": "#908caa",
    "text": "#e0def4",
    "love": "#eb6f92",
    "gold": "#f6c177",
    "rose": "#ea9a97",
    "pine": "#3e8fb0",
    "foam": "#9ccfd8",
    "iris": "#c4a7e7",
    "highlightLow": "#2a283e",
    "highlightMed": "#44415a",
    "highlightHigh": "#56526e"
  },
  "colors": {
    "accent": "iris",
    "border": "overlay",
    "borderAccent": "iris",
    "borderMuted": "muted",
    "success": "foam",
    "error": "love",
    "warning": "gold",
    "muted": "subtle",
    "dim": "muted",
    "text": "text",
    "thinkingText": "subtle",
    "selectedBg": "highlightMed",
    "userMessageBg": "surface",
    "userMessageText": "text",
    "customMessageBg": "surface",
    "customMessageText": "text",
    "customMessageLabel": "iris",
    "toolPendingBg": "highlightLow",
    "toolSuccessBg": "surface",
    "toolErrorBg": "surface",
    "toolTitle": "foam",
    "toolOutput": "text",
    "mdHeading": "iris",
    "mdLink": "foam",
    "mdLinkUrl": "subtle",
    "mdCode": "rose",
    "mdCodeBlock": "text",
    "mdCodeBlockBorder": "overlay",
    "mdQuote": "subtle",
    "mdQuoteBorder": "foam",
    "mdHr": "overlay",
    "mdListBullet": "iris",
    "toolDiffAdded": "foam",
    "toolDiffRemoved": "love",
    "toolDiffContext": "subtle",
    "syntaxComment": "muted",
    "syntaxKeyword": "iris",
    "syntaxFunction": "foam",
    "syntaxVariable": "text",
    "syntaxString": "gold",
    "syntaxNumber": "rose",
    "syntaxType": "pine",
    "syntaxOperator": "iris",
    "syntaxPunctuation": "subtle",
    "thinkingOff": "muted",
    "thinkingMinimal": "pine",
    "thinkingLow": "foam",
    "thinkingMedium": "iris",
    "thinkingHigh": "rose",
    "thinkingXhigh": "love",
    "thinkingMax": "gold",
    "bashMode": "gold"
  }
}
```

`rose-pine-moon`

is totally a personal choice. What you should know is that you can just talk to Pi and ask it to make you any theme you want. Point it at an official color theme you like, and it’ll do it for you.

## Terminal title

`.pi/agent/extensions/terminal-status-title.js`

``` js
const DEFAULT_TITLE = "π";
const PREFIX = "π";
const MAX_TITLE_LENGTH = 40;
const SPINNER_INTERVAL_MS = 120;
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];

function truncateTitle(title) {
  if (title.length <= MAX_TITLE_LENGTH) return title;
  return title.slice(0, MAX_TITLE_LENGTH - 3) + "...";
}

function basename(path) {
  if (!path) return DEFAULT_TITLE;

  const trimmed = path.replace(/[\\/]+$/, "");
  if (!trimmed) return DEFAULT_TITLE;

  return trimmed.split(/[\\/]/).pop() || DEFAULT_TITLE;
}

function getSessionName(pi) {
  const name = pi.getSessionName?.();
  return typeof name === "string" ? name.trim() : "";
}

function getRawTitle(pi, ctx) {
  return getSessionName(pi) || basename(ctx.cwd);
}

function isSpinningStatus(status) {
  return status === "working";
}

function statusIndicator(status, spinnerFrame) {
  if (isSpinningStatus(status)) {
    if (SPINNER_FRAMES.length === 0) return "◉";
    return SPINNER_FRAMES[spinnerFrame % SPINNER_FRAMES.length];
  }

  if (status === "done") return "✓";
  if (status === "error") return "✗";
  return "○";
}

function formatTitle(pi, ctx, status, spinnerFrame) {
  const rawTitle = getRawTitle(pi, ctx);
  const suffix = rawTitle === DEFAULT_TITLE ? DEFAULT_TITLE : `${PREFIX} | ${truncateTitle(rawTitle)}`;

  return `${statusIndicator(status, spinnerFrame)} | ${suffix}`;
}

export default function terminalStatusTitle(pi) {
  let status = "idle";
  let spinnerFrame = 0;
  let spinnerInterval;
  let deferredWrite;
  let lastCtx;

  function clearDeferredWrite() {
    if (!deferredWrite) return;

    clearTimeout(deferredWrite);
    deferredWrite = undefined;
  }

  function writeTitle(ctx = lastCtx) {
    if (!ctx?.hasUI) return;

    lastCtx = ctx;
    ctx.ui.setTitle(formatTitle(pi, ctx, status, spinnerFrame));
  }

  function stopSpinner() {
    if (!spinnerInterval) return;

    clearInterval(spinnerInterval);
    spinnerInterval = undefined;
    spinnerFrame = 0;
  }

  function startSpinner(ctx) {
    if (!ctx?.hasUI || spinnerInterval) return;

    spinnerFrame = 0;
    spinnerInterval = setInterval(() => {
      if (!isSpinningStatus(status)) {
        stopSpinner();
        return;
      }

      spinnerFrame = (spinnerFrame + 1) % SPINNER_FRAMES.length;
      writeTitle();
    }, SPINNER_INTERVAL_MS);
    spinnerInterval.unref?.();
  }

  function setStatus(nextStatus, ctx) {
    clearDeferredWrite();
    status = nextStatus;
    lastCtx = ctx;

    if (isSpinningStatus(status)) {
      startSpinner(ctx);
    } else {
      stopSpinner();
    }

    writeTitle(ctx);
  }

  function scheduleWrite(ctx) {
    clearDeferredWrite();
    deferredWrite = setTimeout(() => {
      deferredWrite = undefined;
      writeTitle(ctx);
    }, 0);
    deferredWrite.unref?.();
  }

  pi.on("session_start", async (_event, ctx) => {
    setStatus("idle", ctx);
    scheduleWrite(ctx);
  });

  pi.on("agent_start", async (_event, ctx) => {
    setStatus("working", ctx);
  });

  pi.on("agent_settled", async (_event, ctx) => {
    setStatus("done", ctx);
  });

  pi.on("session_shutdown", async () => {
    clearDeferredWrite();
    stopSpinner();
  });
}
```

This is a custom extension built to print live agent status as terminal title. With this extension, if I spin up many terminal tabs of Pi agents, I can easily see which agent is working or waiting for my input.

## Published config

All the config above is shared in my public dotfiles repo - [https://github.com/kunchenguid/dotfiles](https://github.com/kunchenguid/dotfiles). Feel free to copy/fork or do whatever you like with it.

And there’s a little bonus hides in here - [https://github.com/kunchenguid/dotfiles/tree/main/home/.pi/agent/extensions/calm](https://github.com/kunchenguid/dotfiles/tree/main/home/.pi/agent/extensions/calm). This is another custom extension that adds a “/calm” command in your Pi, which allows you to toggle on/off a calm mode.

When calm mode is on, it hides all tool calls from the agent, making the terminal extremely clean and peaceful. It also replaces the “Thinking” indicator with a little boat that sails on calm seas.

That’s everything - no fancy skills or workflows. Just the minimum to give me the core primitives I need, help me achieve good efficiency, and remove distractions.
