Pi: The Open-Source AI Coding Agent You Can Actually Customize
Most AI coding agents make a deal with you: accept our opinions, our workflows, our permission dialogs, and our curated set of providers, and in return we’ll get you productive fast. That deal works — until it doesn’t. Until you need a provider the tool doesn’t support, or a workflow it can’t accommodate, or you want to embed agent capabilities into your own product without dragging along someone else’s entire opinionated stack.
Pi (badlogic/pi-mono) takes the opposite bet. It’s a TypeScript monorepo that ships a full-stack toolkit for building, running, and deploying AI coding agents — and its most interesting design decisions are the things it deliberately leaves out. No MCP. No sub-agents. No permission popups. No plan mode. Not because the author couldn’t build them, but because the architecture is designed so you can add exactly what you need and nothing more.
If you’ve ever felt constrained by Claude Code’s provider lock-in, frustrated by Aider’s single-purpose scope, or underwhelmed by what Vercel’s AI SDK offers for production agent workflows, Pi is worth a serious look.
What Is Pi and Why Does It Exist?
Pi is an open-source TypeScript monorepo published under the GitHub handle badlogic/pi-mono. At its most visible layer, it’s an interactive terminal-based coding agent. But that description undersells it significantly — Pi is better understood as a composable platform for building AI agent tooling, where the interactive coding agent is just one application that happens to be built on top of it.
The project’s core philosophy is radical extensibility over built-in features. In a market crowded with agents that compete on feature checklists — who has the most MCP integrations, the most sophisticated plan mode, the most polished permission UX — Pi stakes out a different position: ship the minimum viable runtime, make every layer independently useful, and let developers compose the behavior they actually want.
This matters for a few reasons. First, opinionated tools accumulate opinions fast. What starts as a sensible default becomes a constraint the moment your requirements diverge from the author’s assumptions. Second, most AI coding agents are effectively black boxes with extension hooks bolted on as an afterthought. Pi inverts that: the extension model is the architecture, not a feature added later.
The project is built and maintained by Mario Zechner (badlogic), a developer known for work on libGDX and other open-source projects. The packages are published under the @mariozechner npm scope, and the repo is structured as an npm workspace monorepo — a deliberate choice that keeps each package independently consumable.
A Layered Architecture Built for Flexibility
Pi’s monorepo enforces a strict dependency hierarchy that flows in one direction:
pi-ai → pi-agent-core → pi-coding-agent → pi-tui / pi-web-ui
Each layer depends only on layers below it, and each package is independently useful. You don’t have to adopt the full stack to get value from Pi. Want just the unified LLM streaming API? Pull in @mariozechner/pi-ai and ignore everything else. Building a terminal tool that needs a polished multi-line editor with autocomplete? @mariozechner/pi-tui is a standalone package. Need a full agent runtime you can embed programmatically in your own application? @mariozechner/pi-coding-agent exposes an SDK mode for exactly that.
The toolchain choices reflect a focus on developer experience and build performance. The project uses TypeScript ESM modules throughout, npm workspaces for monorepo management, Biome 2.3 for linting and formatting (replacing the traditional ESLint + Prettier combination with a single fast tool), and tsgo — the experimental Go-based TypeScript type checker — for significantly faster type checking across the workspace.
These aren’t just tooling preferences. They signal that Pi is designed for developers who care about the quality of their development environment, not just the end-user experience of the agent itself.
20+ LLM Providers, One Unified API
The @mariozechner/pi-ai package is arguably Pi’s most immediately useful standalone component. It provides a single normalized streaming interface across more than twenty LLM providers:
- Anthropic (Claude family)
- OpenAI (GPT family)
- Google (Gemini family)
- Mistral, Groq, Cerebras, xAI
- AWS Bedrock, Azure OpenAI
- OpenRouter and a curated model registry of additional providers
What makes this more than a thin wrapper is the OAuth-based subscription support. Pi can authenticate using your existing Claude Pro/Max subscription, ChatGPT Plus, GitHub Copilot, or Gemini CLI credentials — meaning you can use the models you’re already paying for without managing separate API keys for every service.

The most architecturally interesting capability is cross-provider mid-conversation handoffs. Within a single Context object, you can switch from Claude to GPT-5 to Gemini partway through a conversation. Provider-specific features like Anthropic’s thinking blocks are automatically transformed into tagged text representations that other providers can consume coherently. This isn’t just a convenience feature — it enables genuinely useful workflows, like using a fast cheap model for boilerplate generation and switching to a more capable model when the task gets complex, all within the same session.
Tool calls are validated using TypeBox schemas with AJV, which gives you compile-time type safety on tool definitions and runtime validation of tool call arguments. And because streaming responses need to drive real-time UI updates, Pi implements progressive partial JSON parsing — tool call arguments are parsed and surfaced incrementally as they stream in, rather than waiting for the complete response.
The Coding Agent: Intentionally Minimal, Infinitely Extensible
The @mariozechner/pi-coding-agent package ships without MCP, sub-agents, plan mode, background bash execution, or permission popups. If you’re coming from Claude Code or Cursor, this might initially read as a list of missing features. It’s better understood as a list of design constraints that keep the core clean.
Every one of those capabilities can be added via Pi’s extension API — but as first-class TypeScript code that you own, not as configuration flags or plugin manifests. Extensions can:
- Register entirely new tools or replace built-in ones
- Add custom UI widgets to the terminal interface
- Intercept lifecycle events (before/after tool calls, on context compaction, on session branch)
- Inject custom prompt templates and system prompts
- Run arbitrary code at any point in the agent loop — including, apparently, running Doom in the terminal while waiting for a response
Pi Packages are the distribution unit for these customizations. A Pi Package bundles tools, extensions, themes, and prompt templates into a single artifact that can be published to npm or installed directly from a git URL. They follow the Agent Skills standard, which means Pi Packages are interoperable with other tools that implement the same standard — your customizations aren’t locked into Pi’s ecosystem.
The agent supports five operation modes:
- Interactive: Full terminal UI for human-in-the-loop coding sessions
- Print: Non-interactive single-pass output, useful for scripting
- JSON: Structured output mode for downstream processing
- RPC: Exposes the agent over a local RPC interface for external control
- SDK: Programmatic embedding — instantiate the agent directly in your own TypeScript application
The SDK mode in particular is what makes Pi genuinely useful as a platform rather than just a CLI tool. You can embed a fully functional coding agent into your own product, customize its tools and behavior, and control its lifecycle — without forking anything.
Session Branching and Context Management
Pi’s session storage model is more sophisticated than the flat conversation logs most agents use. Sessions are stored as JSONL files where every entry carries an id and a parentId, forming a tree structure rather than a linear sequence. This enables in-place conversation branching without duplicating files — a branch is just a new entry pointing to a different parent.
The /tree command surfaces this structure in the terminal UI, letting you navigate the full conversation tree and switch between branches. In practice, this means you can explore different approaches to a problem — “try the refactor this way, now try it that way” — and switch back to any earlier branch point without losing any history.
Context window management is handled through automatic context compaction. As a conversation approaches the model’s context limit, Pi summarizes older messages and compresses them into a more compact representation. Critically, the full original history is always preserved in the JSONL file — compaction affects only the context sent to the model, not the stored record. This means you can always reconstruct or re-examine the complete conversation, even after aggressive compaction.
A Terminal UI Framework Built from Scratch
Rather than building on top of Ink or Blessed — the two dominant Node.js terminal UI libraries — Pi ships its own terminal UI framework: @mariozechner/pi-tui. This is a significant engineering investment, and the reasons for it are visible in the implementation details.
Pi-tui uses a differential rendering engine with CSI 2026 synchronized output. CSI 2026 is a terminal protocol extension that batches screen updates into synchronized frames, eliminating the flickering that plagues most terminal UIs during rapid updates. Combined with three distinct rendering strategies — full render on first display, full re-render on terminal width change, and delta updates for normal state changes — the result is a terminal UI that feels genuinely responsive rather than jittery.

The built-in component library covers the full range of what a sophisticated coding agent needs:
- A multi-line editor with autocomplete — not a single-line input field
- A markdown renderer with syntax highlighting for displaying model responses
- Inline image rendering via Kitty and iTerm2 protocols, for models that return visual output
- Select lists, settings panels, and overlay components with anchor-based positioning
- IME support for CJK input methods — a detail that signals genuine internationalization consideration rather than ASCII-only assumptions
Because pi-tui is an independent package, you can use it to build your own terminal applications that have nothing to do with AI agents. The engineering work is reusable.
How Pi Compares to Claude Code, Aider, and Vercel AI SDK
Honest comparisons require acknowledging what each tool optimizes for.
vs. Claude Code: Claude Code is polished, deeply integrated with Anthropic’s models, and has a sophisticated permission model. But it’s a single-provider tool with Anthropic’s opinions baked in throughout. Pi supports 20+ providers with cross-provider handoffs, has no built-in permission prompts (add your own if you want them), and offers more sophisticated session branching. If you need multi-provider flexibility or want to own your agent’s behavior completely, Pi has a structural advantage.
vs. Aider: Aider is excellent at what it does — git-integrated code editing with strong diff generation. But it’s a single-purpose tool, not a platform. Git integration in Pi is delegated to extensions, which means it’s addable but not assumed. Pi is the right choice when you need an agent runtime that can do things Aider was never designed for.
vs. Vercel AI SDK: The Vercel AI SDK is a solid foundation for building AI-powered web applications. Pi-ai adds capabilities the Vercel SDK doesn’t have: a curated model registry with cost tracking, OAuth-based subscription flows for consumer AI services, and cross-provider mid-conversation handoffs. If you’re building agent workflows rather than chat interfaces, pi-ai’s additional abstractions earn their weight.
Conclusion: Build the Agent You Actually Want
Pi represents a coherent answer to a real problem: most AI coding agents are built for a specific workflow, and when your workflow diverges, you’re either stuck or forking. Pi’s layered architecture, aggressive extension model, and independently usable packages give you a foundation where customization is the design, not an afterthought.
The deliberate omissions — no MCP, no sub-agents, no permission dialogs by default — are features if you read them correctly. They mean the core stays clean, and everything you add is code you understand and control. The unified multi-provider API with OAuth subscription support and cross-provider handoffs solves a real pain point for teams that don’t want to be locked into a single model vendor. The tree-structured JSONL sessions and automatic context compaction show genuine thought about long-running agent workflows. And the from-scratch terminal UI framework, with its differential rendering and CSI 2026 synchronization, demonstrates that this project takes engineering quality seriously at every layer.
If you’re an intermediate to senior TypeScript developer who’s been using Claude Code or Cursor and hitting their walls, or if you’re building agent tooling and need a composable foundation rather than another opinionated product, Pi deserves a serious evaluation.
Explore the repository, try the CLI, and consider contributing extensions or Pi Packages to the ecosystem. The project is at github.com/badlogic/pi-mono — and given the architecture, your contributions don’t have to be core changes. Build a Pi Package, publish it to npm, and the whole community benefits without anyone needing to merge your opinions into the core.