Docs Principles

Design Philosophy

Why this path first: then the four principles, and the extension / theme package patterns.

Core principles

Extend Pi, never fork · On demand · Know how it works · Eval first (no measurement, no adoption).

Background & Motivation

Why Pi

Coding agents keep shipping. Chasing each new one mostly spends you on yet another round of feature tryouts, still stuck at “I can use it.” The gap opens when you pick one open-source agent and go deep: read how it works, change it yourself, iterate with it, and turn “I can use it” into “I get it.” Pi is restrained and open; that is the right base for this path.

Restraint. If you have used coding agents for a while, you know the discomfort: more features, fuller context, rising token bills and latency, yet day to day you only really need a handful of capabilities. Worse, you barely control what gets stuffed into context. Pi’s author wrote that restraint into the design (What I learned building an opinionated and minimal coding agent): system prompt + tool definitions under ~1000 tokens, four default tools (read / write / edit / bash). The official README lists what Pi does not do: No MCP, No sub-agents, No plan mode, No built-in to-dos, No permission popups, No background bash. Every item has the same exit: build it with extensions, or install a package.

Extensibility. A lean default is not a weak platform. Pi positions itself as “a minimal terminal coding harness,” and is “aggressively extensible so it doesn't have to dictate your workflow.” Tools, commands, event hooks, UI, providers, and themes are all open to extensions, with an explicit promise of “without having to fork and modify pi internals.” You do not have to patch the kernel or wait on upstream to shape the workflow you want. A small, readable core plus a nearly unbounded Extension API is how you actually own your toolchain.

Why not just use oh-my-pi

oh-my-pi (omp) ships many excellent capabilities on top of Pi, is batteries-included, and is piex’s primary feature source. A natural question: if omp already packages “it just works,” why not use it?

The answer is the path it chose:

  • Fork, not extension. omp is a fork of pi (“fork of pi-mono, batteries included”). It maintains a dedicated porting playbook to backport upstream, plus ~55k lines of Rust core and a Bun-only runtime. Follow a fork, and upgrade cadence plus architectural decisions stop being yours.
  • Everything bundled. omp ships 32 tools and a large surface by default, much of it unused day to day. That is “heavy” again: tokens burn, while you do not get to trim the context.

Why PieX

So PieX takes a third path: do not fork Pi; use only the official Extension API to turn proven agent capabilities into independent, optional, measurable packages. Install what you need, remove what you do not; use them deeply in daily work, iterate continuously, and shape a toolchain that actually fits you.

Core Design Principles

PieX rests on four principles.

1. Extend Pi fully—never fork

100% Extension API. No fork of Pi, no edits to Pi internals. Capabilities use the standard surfaces:

CapabilityHow
Override built-in toolspi.registerTool({ name: "edit", ... })
Register new toolspi.registerTool({ name: "debug", ... })
Hook tool callspi.on("tool_call", ...)
Hook tool resultspi.on("tool_result", ...)
Register commandspi.registerCommand("review", ...)
Inject contextpi.on("before_agent_start", ...)
Session cleanuppi.on("session_shutdown", ...)
Persist statepi.appendEntry("state-key", ...)
Footer / Widgetctx.ui.setStatus(...), ctx.ui.setWidget(...)
Interactive UIctx.ui.select(...), ctx.ui.editor(...)
Shortcutspi.registerShortcut(Key.shift("p"), ...)

This is the philosophical gap vs omp: omp forks and batteries-includes, shipping every “good” feature into its own kernel and choosing for the user. piex owns no kernel; it only extends, and leaves trade-offs to the user. Consequently piex needs no upstream backport and tracks official Pi evolution.

Each piex package is a standalone npm package, not embedded in Pi. Pi upgrades do not break piex (extension API is backward-compatible); piex upgrades independently via pi update with its own versioning, upgrading with Pi rather than against it.

2. On demand, switch freely

Packages are independent and dependency-free across each other: install, remove, and compose at will. Pay tokens only for what you use:

bash
pi install npm:@piex-dev/hashline   # hashline edit
pi install npm:@piex-dev/dap        # DAP debug
pi install npm:@piex-dev/plan       # plan mode
pi remove npm:@piex-dev/plan        # uninstall anytime

3. Know how it works—ownership

Borrow proven designs from oh-my-pi, Claude Code, OpenCode, and peers; understand the underlying mechanics; reintroduce them as Pi extensions on demand. Every feature is chosen, understood, and owned, turning “using tools” into “understanding tools.” Each package documents provenance:

PackageOriginImplementation
hashlineoh-my-pi hashline@oh-my-pi/hashline + Pi adapter + Node.js polyfill
dapoh-my-pi DAPPorted from omp (Bun → Node.js)
lspoh-my-pi LSPported from omp + OpenCode post-edit diagnostics loop
planPi official exampleEnhanced from plan-mode example
reviewoh-my-pi /reviewSlim port from omp
theme-dark-terminalopencode-themesStatic theme JSON via pi.themes

4. Eval first

If an extension’s effect cannot be measured, do not adopt it. For behavior-changing packages (hashline, dap, lsp, plan, review): the repo ships a Dockerized eval framework (eval/) comparing pi (bare) / pi + piex / omp on Aider Polyglot and SWE-bench Lite, with metrics including resolve_rate, avg_tokens, avg_time, est_cost, and attribution metrics (edit_accuracy, debug_success, plan_follow_rate). Results will be published continuously. Themes and login providers that do not change agent behavior are out of scope for this rule. See Evaluation Plan.

Goals

  • Build a coding-agent toolchain on Pi that fits you: every feature chosen, understood, and owned.
  • Understand the implementation of each capability, and raise product taste through continuous iteration.

Architecture Patterns

Extension package pattern

Every package follows the same shape:

text
<name>/
├── package.json          # npm package with "pi" manifest
├── README.md             # package docs
└── extensions/
    └── <name>.ts         # pi extension entry: export default function(pi)
    └── ...helpers.ts

"pi": { "extensions": ["./extensions"] } in package.json tells Pi where to discover extension files.

Extension load flow

text
pi starts
  ├── resolve settings.json → discover piex packages
  ├── read package.json → find extensions/
  ├── jiti loads .ts files
  └── call export default function(pi)
      ├── pi.registerTool(...)
      ├── pi.registerCommand(...)
      └── pi.on("event", ...)

Extension entry signature

typescript
// sync (typical)
export default function myExtension(pi: ExtensionAPI) { ... }

// async (e.g. fetch remote config on init)
export default async function myExtension(pi: ExtensionAPI) { ... }

Theme package pattern

Theme packages have no TypeScript extension code; they ship static JSON. Pi accepts a themes/ convention directory or an explicit pi.themes file list. Prefer the convention for /settings preview and runtime load:

json
{
  "pi": { "themes": ["./themes"] }
}
text
<name>/
├── package.json          # "pi": { "themes": ["./themes"] }
├── README.md
└── 
    └── <name>.json       # pi theme JSON (51 color tokens)

Install path notes:

  • Global settings (~/.pi/agent/settings.json): local package paths must be absolute, or /reload resolves relative paths against the settings file location and the theme disappears. Example:

``bash pi install /abspath-to-piex/themes/dark-terminal ``

  • Project settings (.pi/settings.json): relative paths are fine and team-shareable:

``bash pi install -l ./themes/dark-terminal ``

Theme JSON includes name (unique), optional vars, and colors (51 required tokens). Pi loads themes at startup; switch via /settings.

Source Markdown: docs/design.md