Pi Mono: The Minimalist Kernel
Pi is a coding agent that deliberately ships without MCP, without sub-agents, and without permission gates. Instead, it provides a razor-sharp tool core, tree-structured JSONL sessions, a differential-rendering TUI, and an extension system that lets you build everything else yourself — including Pi Packages, shareable bundles installable via npm or git.
What is Pi Mono?
Pi Mono (@mariozechner/pi-coding-agent, version
0.73.0) is a TypeScript-based coding agent CLI
created by Mario Zechner (badlogic). It lives in a
monorepo with five current packages, all at the same version and under
the MIT license:
| Package | Name | What it does |
|---|---|---|
coding-agent |
@mariozechner/pi-coding-agent |
The core CLI — tool definitions, mode entry points, extension loading |
ai |
@mariozechner/pi-ai |
Unified multi-provider LLM API — 26 providers, 10 API implementations |
agent |
@mariozechner/pi-agent-core |
Agent runtime — agent loop, transcript management, event system |
tui |
@mariozechner/pi-tui |
Differential terminal UI engine — only redraws changed cells |
web-ui |
@mariozechner/pi-web-ui |
Web components (Lit) — chat panel, artifacts, sandboxed iframes, JS REPL |
The current packages/ directory is agent,
ai, coding-agent, tui, and
web-ui. Older references to mom and
pods no longer match the fresh repo snapshot.
The project is hosted at pi.dev (domain donated by
exe.dev) and its logo lives at shittycodingagent.ai — a
self-deprecating branding choice that signals the project's
no-nonsense attitude.
Deliberately missing features
The README is explicit about what Pi does not include:
- No MCP — The author argues CLI tools + skills are sufficient. Extensions can add MCP.
- No sub-agents — Spawn separate pi instances via tmux, or build your own with extensions.
- No permission popups — Run in a container, or build your own confirmation flow with extensions.
- No plan mode — Plans are expected to be written to files.
- No built-in todos — They confuse models per the author.
- No background bash — Use tmux for persistent processes.
This philosophical stance makes Pi fundamentally different from Claude Code, OpenHands, and DeerFlow. It is not trying to be an operating system or a framework — it is a focused tool with a clear opinion about what a coding agent should be.
The Four Run Modes
Interactive TUI
The default mode. A full terminal UI with streaming messages, tool execution display, session navigation, model selector, and settings dialogs. Built on a custom differential rendering engine that only redraws changed terminal cells at 60fps throttle (16ms min). Supports Kitty graphics protocol for images and hardware cursor via APC escape sequences for IME positioning.
Print Mode
Single-shot mode for scripting. Feed it a prompt, get a response. Useful for CI pipelines, automated code reviews, and batch processing. No TUI overhead — just stdout.
RPC Mode
JSONL-based protocol for embedding pi in other applications. Stdin/stdout communication with structured JSON messages — similar to how VS Code extensions communicate with language servers. Ideal for IDE integration.
SDK Mode
Embed pi as a library in other Node.js applications. Import the SDK directly and control the agent programmatically — useful for building custom integrations or wrapping pi in another product.
Tool System: JSON Function Calling with TypeBox
Pi uses JSON Schema-based function calling, not XML
wrappers or raw CLI parsing. Tools are defined using
TypeBox schemas (@sinclair/typebox),
providing type-safe parameter validation at runtime. Tool arguments
are validated using AJV — if validation fails, the
error is returned to the LLM as an isError: true tool
result, allowing the model to retry without human intervention.
The core tool set includes 7 tools, split into two groups:
| Tool | Category | Details |
|---|---|---|
read |
Coding | Read file with configurable max lines/bytes, truncation notices |
bash |
Coding | Shell execution with streaming output, process tree killing, 10MB stdout/stderr cap, temp file fallback for overflow |
edit |
Coding | Precise text replacement with multiple disjoint edits per call, fuzzy matching, uniqueness validation, reverse-order application |
write |
Coding | Write entire files, auto-create parent directories, file mutation queue for concurrent safety |
grep |
Read-only | Regex content search across files |
find |
Read-only | File path search by name or pattern |
ls |
Read-only | Directory listing |
The default tool set is read,
bash, edit, write (4 tools). In
read-only mode, it switches to read, grep,
find, ls.
The Edit Tool: Precision Engineering
Pi's edit tool is one of the most carefully designed
components in any coding agent. It does not use
unified diff patches or whole-file rewrites. Instead:
How edits work
-
Multiple disjoint edits per call: The model can
specify several
oldText/newTextpairs in a single tool call. -
Non-overlapping validation: Each
oldTextis matched against the original file, not incrementally. All edits are validated to ensure they don't overlap. - Reverse-order application: Edits are applied from bottom to top of the file, maintaining stable line offsets as changes accumulate.
-
Exact matching first: The tool tries to find an
exact string match for each
oldText. - Fuzzy matching fallback: If exact matching fails, it normalizes trailing whitespace, Unicode quotes (smart quotes), Unicode dashes, and special spaces before trying again.
-
Uniqueness validation: Each
oldTextmust appear exactly once in the file. If it appears zero or multiple times, the edit is rejected with a clear error. - Line ending preservation: Detects CRLF vs LF and restores original line endings after edits.
- BOM handling: Strips byte-order marks before matching, then prepends them back on write.
After applying edits, Pi generates a custom diff with line numbers and 4 lines of context for display in the TUI.
File mutation queue
Pi serializes write/edit operations targeting the same file using
per-file promise chains (file-mutation-queue.ts).
This prevents race conditions when the LLM attempts concurrent
edits to the same file — a subtle bug that plagues many other
agents.
Bash Tool: Streaming with Safety
Pi's bash tool has several notable features:
-
Pluggable backend:
BashOperationsinterface allows swapping the execution backend. Default useschild_process.spawn()with the user's shell. -
Detached process trees: Commands spawn as detached
processes. On abort or timeout, the entire process tree is killed
via
killProcessTree(), not just the shell. -
Streaming output: Output streams via
onUpdatecallback for real-time TUI updates. -
Rolling buffer: Keeps recent output in memory (up
to
DEFAULT_MAX_BYTES * 2), trimming old chunks. -
Temp file fallback: When output exceeds the buffer
(10MB each for stdout/stderr), it writes to
/tmp/pi-bash-*.logand tells the model where to find the full output. -
ANSI stripping: User-initiated bash
(
!command) strips ANSI codes and sanitizes binary output. -
Extension hooks: Extensions can intercept commands
via
BashSpawnHook, modifying the command, cwd, or environment before execution. An optionalcommandPrefixcan be prepended to every command.
Session Management: Tree-Structured JSONL (v3)
Pi's session system is one of its most distinctive features. Sessions are stored as JSONL files with tree structure, enabling branching without file proliferation. The current session format version is v3.
{"type": "message", "id": "abc123", "parentId": null, "role": "user", "content": "..."}
{"type": "message", "id": "def456", "parentId": "abc123", "role": "assistant", ...}
{"type": "toolResult", "id": "ghi789", "parentId": "def456", "toolName": "bash", ...}
{"type": "thinking_level_change", "id": "...", "parentId": "...", "level": "high"}
{"type": "model_change", "id": "...", "parentId": "...", "model": "anthropic/claude-sonnet-4-5"}
{"type": "compaction", "id": "jkl012", "parentId": "abc123", "summary": "...", "firstKeptEntryId": "xyz", "tokensBefore": 120000}
{"type": "branch_summary", "id": "mno345", "parentId": "abc123", ...}
{"type": "label", "id": "...", "parentId": "...", "label": "bookmark-name"}
Each entry has an id and parentId, creating
a tree within a single file. Entry types include:
message, thinking_level_change,
model_change, compaction,
branch_summary, custom,
custom_message, label, and
session_info.
This enables:
- In-place branching: Jump to any point in the conversation and fork without creating new files.
-
/treecommand: Navigate the session tree with search, fold/unfold, and branch jumping. -
/forkcommand: Create a new session file from the current branch point. -
Compaction: Auto-triggers when context approaches
limits. Uses the LLM to summarize old messages while preserving
recent ones. Compaction entries track
firstKeptEntryIdfor tree traversal. - Labels/bookmarks: Mark important points in the tree for quick navigation.
Sessions auto-save to ~/.pi/agent/sessions/ organized by
working directory. Commands like pi -c (continue most
recent), pi -r (resume from list), and
--session <path>
provide flexible session control.
Agent Runtime: Parallel Tool Execution & Steering
The agent runtime in packages/agent/src/ is where the
core agentic loop lives. The Agent class wraps
agentLoop() and agentLoopContinue() with
sophisticated state management:
Key runtime features
-
Parallel tool execution (default): Tools run
concurrently. Configurable as
"parallel"or"sequential". -
Steering messages:
steer()queues messages delivered after the current turn — real-time interruption without breaking the loop. -
Follow-up messages:
followUp()queues messages delivered only after the agent stops — different delivery semantics from steering. -
PendingMessageQueue: Two delivery modes —
one-at-a-timevsall— for fine-grained control over message delivery timing. -
Event subscription: Comprehensive event system
with listener promises awaited in order. Events include:
agent_start,agent_end,tool_call,tool_result,message_start,message_update,message_end,turn_start,turn_end,session_start,session_compact,session_tree,model_select,context,user_bash,input,before_provider_request. - beforeToolCall / afterToolCall hooks: Extensions can intercept and modify tool execution.
-
Abort handling:
abort()andwaitForIdle()for lifecycle control. Failed runs produce assistant messages withstopReason: "error"or"aborted".
Model Support: 26 Providers Across 10 APIs
Pi's current README describes
26 built-in providers exposed through the unified
@mariozechner/pi-ai layer. The important detail is not
just breadth, but the split between subscription-backed logins and a
large API-key matrix.
Subscription-backed logins
- Anthropic Claude Pro/Max
- OpenAI ChatGPT Plus/Pro (Codex)
- GitHub Copilot
API-key providers
Anthropic, OpenAI, Azure OpenAI, DeepSeek, Google Gemini, Google Vertex, Amazon Bedrock, Mistral, Groq, Cerebras, Cloudflare AI Gateway, Cloudflare Workers AI, xAI, OpenRouter, Vercel AI Gateway, ZAI, OpenCode Zen, OpenCode Go, Hugging Face, Fireworks, Kimi For Coding, MiniMax, Xiaomi MiMo, and three Xiaomi MiMo token-plan endpoints.
Only 10 API implementations sit underneath that list. Most providers reuse compatible OpenAI-, Anthropic-, or Google-style transports, which is why Pi can stay minimalist while still supporting a huge provider catalog.
Model Resolution System
The ModelRegistry manages built-in and custom models.
Resolution supports:
- Exact match by ID
-
Canonical
provider/modelIdformat - Fuzzy or partial matching by ID or name
-
Glob patterns for scoping (
claude-*,gpt-4o) -
Thinking level suffix shorthand
(
model:high) - Alias preference over dated versions
- Ambiguity rejection when the same ID exists on multiple providers
-
Custom models via
~/.pi/agent/models.json -
Dynamic providers — extensions can call
pi.registerProvider()at runtime
Auth Storage
Credentials are stored at ~/.pi/agent/auth.json with
0o600 permissions (owner read/write only). The file
uses proper-lockfile with retry logic for multi-instance
safety — if you run two pi instances simultaneously, they won't
corrupt each other's auth state.
Extension System: Build Everything Else
Pi's extension system is where the real power lies. Extensions are
loaded at runtime using jiti (TypeScript runtime
executor — a custom fork @mariozechner/jiti with
virtualModules
support for compiled Bun binaries), and they can hook into virtually
every aspect of the agent.
// Example extension: Permission gate for dangerous commands
export default function(pi: ExtensionAPI) {
pi.on("tool_call", async (event, ctx) => {
if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
const ok = await ctx.ui.confirm("Dangerous!", "Allow rm -rf?");
if (!ok) return { block: true, reason: "Blocked by user" };
}
});
}
The ExtensionAPI provides:
-
pi.on(event, handler)— Subscribe to 20+ lifecycle events -
pi.registerTool(tool)— Register LLM-callable tools with TypeBox schemas -
pi.registerCommand(name, options)— Register slash commands -
pi.registerShortcut(keyId, options)— Register keyboard shortcuts -
pi.registerFlag(name, options)— Register CLI flags -
pi.registerMessageRenderer(type, renderer)— Custom message rendering -
pi.exec(command, args, options)— Execute shell commands -
pi.registerProvider(name, config)— Register custom LLM providers pi.events— EventBus for custom event patterns- Custom editors, widgets, status lines, headers, footers
Extension Discovery Order
-
Project-local:
cwd/.pi/extensions/ - Global:
~/.pi/agent/extensions/ -
Explicitly configured: Via settings or
-eflag - Pi Packages: Discovered from installed packages
No recursion beyond one level — extensions are intentionally flat and discoverable.
Event Categories
| Category | Example Events | What Extensions Can Do |
|---|---|---|
| Resource | resources_discover |
Inject custom resources (context files, etc.) |
| Session |
session_start,
session_before_compact, session_tree
|
Modify session state, fork, navigate |
| Agent |
before_provider_request,
message_end, agent_start
|
Observe/modify agent behavior |
| Tool |
tool_call, tool_result,
beforeToolCall
|
Block, modify, or augment tool execution |
| Model | model_select |
Override model selection |
| Input | input |
Transform or handle user input |
| Turn | turn_start, turn_end |
Per-turn telemetry, timing |
| Message |
message_start, message_update,
message_end
|
Stream interception, custom rendering |
Pi Packages (Pip): Shareable Bundles
One of Pi's most distinctive features is its package system. Pi Packages (sometimes called "Pip") are shareable bundles installable via npm or git:
pi install npm:@foo/pi-tools
pi install git:github.com/user/repo
Packages declare their contents via a pi key in
package.json. They can contain:
- Extensions — TypeScript modules that hook into the agent
- Skills — Markdown-based tool definitions
- Prompts — Pre-built prompt templates
- Themes — TUI visual customization
Auto-discovery scans extensions/, skills/,
prompts/, and themes/ directories within
installed packages. This creates a genuine ecosystem — you don't need
to write code to extend Pi, you can just install a package.
Skills: Markdown-Based Tool Definitions
Pi supports Agent Skills — markdown files following
the Agent Skills standard at agentskills.io. Skills are
essentially self-contained tool definitions with instructions that the
agent can discover and use.
Instead of MCP servers, Pi expects you to build CLI tools with READMEs (or Skills) and extensions. The philosophy is that the overhead of MCP is unnecessary when a well-structured CLI tool plus its documentation provides the same capability.
Context Files: Auto-Loaded Project Knowledge
Pi automatically loads AGENTS.md and
CLAUDE.md
files from the current working directory up through parent
directories, plus a global location. This means the agent picks up
project-specific conventions, coding standards, and instructions
without any explicit configuration.
TUI: Differential Rendering
The terminal UI in packages/tui/ is not just another
blessed/inquirer wrapper. It implements a custom
differential rendering engine:
-
Tracks
previousLinesandpreviousWidth/previousHeight - Only writes changed lines to the terminal — not full redraws
- Minimum render interval of 16ms (~60fps throttle)
- Overlay stack with focus management, percentage/absolute positioning, anchors
- Hardware cursor support via APC escape sequence for IME positioning
- Kitty graphics protocol for terminal image rendering
-
Component-based architecture (
Componentinterface withrender(),handleInput(),invalidate()) - Input listener chain with consume/transform support
-
Optional
koffi(FFI) dependency for clipboard integration
Web UI: Lit Components, Artifacts, and JS REPL
The @mariozechner/pi-web-ui package (built with
Lit and @mariozechner/mini-lit) provides
a complete web-based agent interface:
Components
ChatPanel— Main chat interfaceAgentInterface— Full agent interface-
MessageList,MessageEditor,Input -
Message types:
UserMessage,AssistantMessage,ToolMessage,AbortedMessage,ArtifactMessage
Artifact System
Pi has a full artifact rendering system with types for:
HtmlArtifact— Rendered HTML in sandboxed iframeImageArtifact— Image displaySvgArtifact— SVG displayMarkdownArtifact— Rendered MarkdownTextArtifact— Plain text-
ArtifactElement/ArtifactPill— UI components
Sandboxed Runtime
SandboxedIframe with runtime providers:
-
ArtifactsRuntimeProvider— Read-only and read-write modes ConsoleRuntimeProvider— Console.log capture-
AttachmentsRuntimeProvider— File attachment handling FileDownloadRuntimeProvider— Downloadable files
JavaScript REPL
Pi includes a javascriptReplTool that renders an
interactive JavaScript REPL in the web UI for tool results. This is
unique among coding agents — most just show text output.
Document Extraction
The extractDocumentTool handles PDFs, DOCX, and XLSX
files via pdfjs-dist, docx-preview, and
xlsx — allowing the agent to read complex document
formats.
Storage
IndexedDB backend with stores for sessions, settings, custom providers, and provider keys.
Error Handling and Recovery
Pi's error handling is multi-layered:
Error recovery mechanisms
-
Tool-level errors: Thrown errors in tool
execute()are caught by the agent loop and reported to the LLM asisError: truetool results, allowing the model to retry. -
Abort signals: All tools support
AbortSignal. Abort is handled gracefully — tools clean up resources, close temp files, and return partial results. - Auto-retry: The session has auto-retry for compaction failures. When context overflow triggers compaction, if compaction fails, the system recovers and retries.
-
Extension error isolation: Extension handlers are
wrapped in try/catch. Errors emit via
emitError()to registered listeners but do not crash the agent. - Process tree cleanup: Bash tool kills entire process trees on abort/timeout, preventing orphaned processes.
How Pi Compares to Other Agents
| Feature | Pi Mono | Claude Code | Crush | Qwen Code |
|---|---|---|---|---|
| Primary Language | TypeScript | TypeScript (Bun) | Go | TypeScript |
| Tool Protocol | JSON Function Calling (TypeBox) | MCP (JSON-RPC) | JSON Function Calling | JSON Function Calling |
| MCP Support | ❌ Deliberately absent (extensions can add) | ✅ Native, core feature | ✅ Instruction injection | ✅ Lifecycle management |
| Sub-Agents | ❌ Via extensions/Pi Packages only | ✅ Built-in | ❌ Not present | ✅ Built-in |
| Permissions | ❌ Via extensions only | ✅ Built-in system | ✅ Built-in | ✅ Built-in |
| Session Format | Tree-structured JSONL (v3) | Proprietary | Proprietary | Proprietary |
| File Editing | Precise text replacement (multi-edit) | Diffs | Diffs | Diffs |
| Extensibility | Extensions + Skills + Pi Packages | Limited | Limited | Extensions |
| Model Count | 26 providers (10 APIs) | Anthropic only | Multiple | Multiple |
| Run Modes | 4 (TUI, Print, RPC, SDK) | TUI | TUI | TUI |
| TUI Rendering | Differential (changed cells only) | React/Ink | Custom Go TUI | Ink |
| Web UI | ✅ Lit components, artifacts, JS REPL | ❌ | ❌ | ❌ |
| Package System | ✅ Pi Packages (npm/git) | ❌ | ❌ | ❌ |
| License | MIT | Proprietary | MIT | Apache 2.0 |
Strengths and Weaknesses
Strengths
- Minimalist philosophy: Ships only what is necessary, everything else is opt-in via extensions, skills, or Pi Packages.
- Tree-structured sessions: Unique branching/forking within single JSONL files with v3 format, labels, and compaction tracking.
- Four run modes: Interactive TUI, print, RPC, and SDK — the most flexible deployment options in this set.
- Precise text editing: Non-overlapping edits with fuzzy matching, uniqueness validation, and multi-edit per call.
- 26 model providers: Genuinely provider-agnostic across 10 API implementations, from Anthropic to Bedrock to Xiaomi MiMo.
- Differential TUI: Only redraws changed cells at 60fps — the most efficient terminal rendering in this set.
- Pi Packages: Shareable bundles installable via npm/git create a genuine extension ecosystem.
- Parallel tool execution: Tools run concurrently by default, with sequential option.
- Steering/followup queues: Real-time message interruption without breaking the agent loop.
- Open source (MIT): Fully auditable code, no proprietary components.
- Web UI with artifacts: Full artifact system with sandboxed iframes, JS REPL, and document extraction.
- File mutation queue: Per-file locking prevents concurrent write conflicts.
- Auth with file locking: Multi-instance safe credential storage.
Weaknesses
- No built-in permissions: Must build your own or run in a container — not ideal for production out-of-the-box.
- No MCP: Deliberate choice, but means interoperability with MCP servers requires custom extensions.
- No sub-agents: Cannot delegate work to child agents natively.
- Only 7 core tools: Minimal built-in tool set compared to Claude Code's 40+ or Wintermolt's 16+.
- Smaller ecosystem: Fewer pre-built extensions and packages compared to Claude Code or OpenHands.
- Learning curve: Extension-first approach means more upfront work to reach feature parity with other agents.
- Node.js dependency: Requires Node.js 20+ (or Bun), unlike Go or Zig agents that compile to native binaries.
Key Files to Read
| Component | Path | What to Look For |
|---|---|---|
| Tool definitions | packages/coding-agent/src/core/tools/*.ts |
TypeBox schemas, execute/render methods |
| Edit diff logic |
packages/coding-agent/src/core/tools/edit-diff.ts
|
Non-overlapping edits, fuzzy matching, reverse-order application |
| Bash execution |
packages/coding-agent/src/core/tools/bash.ts
|
Streaming, rolling buffer, process tree killing, temp file fallback |
| File mutation queue |
packages/coding-agent/src/core/tools/file-mutation-queue.ts
|
Per-file locking for concurrent safety |
| Agent loop | packages/agent/src/agent-loop.ts |
Parallel execution, steering/followup queues, event system |
| Model registry |
packages/ai/src/providers/models.generated.ts
|
14,278 lines of auto-generated model definitions |
| Model resolver |
packages/coding-agent/src/core/model-resolver.ts
|
Glob patterns, alias resolution, thinking levels, ambiguity rejection |
| Extension types |
packages/coding-agent/src/core/extensions/types.ts
|
20+ event definitions, ExtensionAPI interface |
| Extension runner |
packages/coding-agent/src/core/extensions/runner.ts
|
Extension lifecycle management |
| Agent session |
packages/coding-agent/src/core/agent-session.ts
|
JSONL tree structure, compaction, fork, v3 format |
| TUI rendering | packages/tui/src/tui.ts |
Differential rendering, 16ms throttle, Kitty graphics |
| Interactive mode |
packages/coding-agent/src/modes/interactive/interactive-mode.ts
|
TUI setup, component wiring |
| RPC mode |
packages/coding-agent/src/modes/rpc/rpc-mode.ts
|
JSONL protocol implementation |
| Auth storage | packages/coding-agent/src/core/auth.ts |
File locking, 0o600 permissions, multi-instance safety |
| Web UI artifacts | packages/web-ui/src/tools/artifacts/ |
HtmlArtifact, ImageArtifact, sandboxed iframes, runtime providers |
| JS REPL |
packages/web-ui/src/tools/javascript-repl.ts
|
Interactive JavaScript REPL for web UI |
Fresh Repo Snapshot
The fresh repo snapshot makes Pi's direction clearer than older versions of this page did: keep the core small, grow the provider surface, and let extensions or packages own the rest.
Version 0.73.0
The current CLI package is
@mariozechner/pi-coding-agent at
0.73.0, not the older 0.66.x line this page
previously described.
26 providers
Provider breadth has grown materially. The README now lists 26 built-in providers across subscriptions and API keys, while still routing through only 10 underlying API implementations.
Five-package monorepo
The current packages/ directory is leaner than older
summaries: agent, ai,
coding-agent, tui, and
web-ui are the live packages in this checkout.
Prompt and tool compatibility work
Recent Pi work adds prompt-template depth, provider expansion, OAuth flows, and cross-agent tool-name normalization rather than bolting on MCP or a built-in subagent framework.
Final Verdict
Who is Pi Mono for?
Pi Mono is for developers who want a clean, minimalist coding agent that they can extend to match their exact workflow. It is the anti-Claude-Code: instead of shipping with every feature baked in, it ships a razor-sharp kernel and expects you to build the rest.
If you value simplicity, extensibility, and open-source transparency, Pi is compelling. The differential TUI, tree-structured sessions, parallel tool execution, and Pi Packages system show genuine engineering depth beneath the minimalist surface.
If you want out-of-the-box permissions, MCP interoperability, and sub-agent delegation, you will need to build those yourself — or choose Claude Code, OpenHands, or DeerFlow instead.
The extension system is powerful enough to recreate any missing feature. The question is not whether Pi can do something — it is whether you want to build it yourself. For many developers, that is exactly the point.