Pi, the Minimal Coding Agent Harness: Extensions, Skills, Sessions and Safety
Why a small terminal coding harness with four tools and a short system prompt can beat feature-heavy agents: install, models, session trees, extensions, skills and sandboxing.
This article is published in English.
Terminal coding agents such as Claude Code, Cursor and OpenCode have become a normal part of many developers' day, especially since OpenAI open-sourced the Codex CLI in April. Pi, a deliberately small coding harness, starts from a complaint about all of them: the tool keeps shifting underneath you.
The complaint isn't about bugs. It's that the harness changes, and the model's behavior changes along with it. Engineers want tools they can rely on. LLMs themselves are unreliable, but at least the surrounding parts can be made deterministic, including the tools, the system prompts and everything injected into them.
Claude Code and Codex put a lot into your context without showing it in the interface, and those hidden additions disrupt a workflow in subtle ways. Releases come once a day or even several times a day. A workflow that runs perfectly at nine in the morning can fall apart by ten and behave completely differently by three, with the model unchanged and only the harness different. New features land nearly every month, among them MCP, subagents, plan mode and background execution, and it gets harder to follow what happens behind the scenes.
Pi's answer is a design rule: if it isn't needed, it doesn't get built. Existing tools inject context out of sight, and users can't see what's going on. That was the motivation.
What inspired the minimalism
Before writing up Pi, its creator, Mario Zechner, looked at the Terminal Bench leaderboard, where a harness named Terminus stood out. It gives the model exactly one tool, an interface to a tmux session. The LLM sends individual keystrokes and reads back the ANSI output from tmux to finish the task. With only that, it nearly always lands in the top three and often takes first place.
This points to a useful intuition. Models are now trained heavily with reinforcement learning, so they already know what a coding harness is and don't need much layered on top. Pi embodies that idea as a minimal yet extensible harness.
What makes Pi different
Pi's distinguishing feature is what it leaves out, features that other coding agents treat as standard. Take MCP: connect to a server and every tool definition floods the context at the start of each session. CLI tools come with READMEs, which are read and run only when needed, so there's no reason to burn context on them constantly.
What it has that others lack
Pi was designed by subtraction, yet it has abilities Claude Code lacks. Extensions and packages are installed with a few commands:
pi install npm:@foo/pi-tools
pi install git:github.com/user/repo
pi config # Enable or disable
The extension mechanism
Extensions are written against an API imported from the Pi package:
import { ExtensionAPI } from "@mariozechner/pi-coding-agent";
An extension can hook into events such as tool calls. One example guards against dangerous shell 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" };
}
});
}
1. Installation
Installing takes one command:
npm install -g --ignore-scripts @earendil-works/pi-coding-agent
An installer script is an alternative:
curl -fsSL https://pi.dev/install.sh | sh
Two ways of authenticating exist. One uses an API key:
# Use an API key
export ANTHROPIC_API_KEY=sk-ant-...
pi
The other reuses a subscription you already have:
# Use an existing subscription
pi
/login # Select a provider
With /login, existing subscriptions such as Anthropic Claude Pro or Max, OpenAI ChatGPT Plus or Pro (Codex) and GitHub Copilot can be used as they are. The learning curve is very low: install it, start talking to it, and it works.
2. Model setup
Pi supports more than 15 LLM providers. The main ones include:
- Anthropic
- OpenAI
- Google Gemini / Vertex
- DeepSeek
- xAI
- OpenRouter
- Amazon Bedrock
- Azure OpenAI
- Groq / Cerebras / Mistral など
Switching models in the middle of a session is perfectly normal:
/model # Model selection screen
Ctrl+L # Same as above
Shift+Tab # Switch thinking level (off–max)
Custom providers can be added in ~/.pi/agent/models.json. Any API compatible with OpenAI, Anthropic or Google works through configuration alone, and router servers such as llama.cpp can serve a local model. Being "not locked to a provider" is one of the advantages Pi stresses most.
3. Session management
Sessions are stored as a tree-structured JSONL file, under ~/.pi/agent/sessions/, with id and parentId fields on every message. Because of that structure, a single file supports all of these operations:
pi -c # Continue the most recent session
pi -r # Select from previous sessions
The /tree command is especially interesting. You can jump back to any point in the conversation and branch from there. The whole history sits in one file, so it's easy to say "I wanted to go the way I did half an hour ago" and actually do it.
/compact summarizes old messages to compress the context. Automatic compaction is on by default, and if the context overflows it recovers and retries by itself.
4. Extensions in depth
Here Pi shows what it's really for. Customization has four layers:
Extensions (TypeScript) → Tools, commands, UI, and event handling
Skills → Procedures/instructions written in Markdown
Prompt Templates → Reusable prompts
Themes → Display themes
Packages from npm or git are managed like this:
pi install npm:@foo/pi-tools
pi install git:github.com/user/repo
pi list
pi update --all
Extensions can do all of the following:
- Add custom tools, including replacements for built-in ones.
- Create custom sub-agents and plan modes.
- Enforce permission gates and path protection.
- Add interface elements such as a status line, header and footer.
- Make git checkpoints or automatic commits.
- Integrate MCP servers.
- Run Doom while you wait, if you like.
The central point is that every feature other agents build into the product, sub-agents, plan mode and permission popups included, can be created as an extension. So the philosophy is to keep the core minimal.
5. Skills
Skills are packages of ability written in Markdown. Following the Agent Skills standard, a folder holding a SKILL.md file makes one skill.
<!-- ~/.pi/agent/skills/my-skill/SKILL.md -->
# My Skill
Use this skill when a user asks about X.
```
```text ## Steps 1. Perform this action. 2. Then perform that action. ```
A skill can be called explicitly with /skill:name, and the agent also loads it on its own when the task fits. The key design choice is that skills enter the context only when needed. Rather than stuffing everything into the system prompt, they unfold on use, and that is how the system prompt stays around a thousand tokens.
6. Pi Web, the browser UI
There's also a browser interface called Pi Web:
npx @agegr/pi-web@latest
Its main features:
- A session workspace to list, resume, rename and delete past conversations by project.
- Two ways to branch: start a new session from a message, or fork inside the current session.
- Project file viewing and Git diff display.
- Git worktree switching.
- Provider login, model, package and skill settings in the browser.
Since it shares ~/.pi/agent settings and session files with the terminal version, moving between browser and terminal is painless.
7. Memory
Memory turns out to be simple. The stance is that Pi doesn't need a separate long-term memory database. Instead there are three mechanisms:
1. The session itself is memory
The entire history is saved as JSONL and can be resumed at any time.
2. AGENTS.md / CLAUDE.md
Write project conventions, instructions, and commands in these files.
They are loaded at startup from global settings and the directory hierarchy.
3. Compaction
Long sessions are compressed by summarizing older parts.
However, the complete history remains in JSONL, so you can go back with /tree.
In other words, what has been done lives in the session, and what you want kept in mind lives in AGENTS.md. Adding memory through an extension is a common derivative use case too.
8. Staying safe
Pi has no built-in sandbox. Read, write, edit and bash operations run with the privileges of whoever launched it, and the same goes for extensions. This is deliberate. A half-built in-process sandbox only offers a seemingly safe boundary, so the official position is to leave real isolation to the OS and to container or VM layers. Untrusted repositories and unattended runs belong in an isolated environment.
One option is to put the entire Pi environment in Docker, the simplest approach:
# 1. Put the entire pi environment in Docker (simplest)
Another is to run Pi on the host and route only tool execution to a local micro-VM:
# 2. Run pi on the host and route only tool execution
# to a local micro-VM (Gondolin)
pi -e ~/.pi/agent/extensions/gondolin
A feature called project trust adds an input guard. It stops repositories from silently overwriting Pi settings or extensions, and by default it asks for confirmation on unverified projects. It doesn't fully prevent prompt injection, though, so keep that in mind when working with unfamiliar code or documents.
9. Writing your own extension
The smallest extension is a single TypeScript file. It registers a tool:
export default function (pi: ExtensionAPI) {
pi.registerTool({
name: "deploy",
// Tool definition (input schema, execution logic)
});
and it can add commands or intercept tool calls:
pi.registerCommand("stats", {
// Custom command definition }); pi.on("tool_call", async (event, ctx) => {
// Intercept tool calls and process them
}); }
Drop the file into ~/.pi/agent/extensions/ for all projects, or into .pi/extensions/ for one project, and it loads automatically when Pi starts. For a one-off test, pi -e ./my-ext.ts does the job. The official repository has plenty of examples: auto-commit, git checkpoints, MCP integration and custom compaction. On Pi, a missing feature is expected. The normal move is to add it yourself or install a package.
What Pi teaches
For anyone building their own agent, Pi's decisions make a useful reference. Skip the all-inclusive package. Start with four tools and a system prompt of around a thousand tokens, and add only what's needed. The design begins with what to remove and not with what to add.