The Pi coding agent is a minimal, MIT-licensed terminal agent created by Mario Zechner and now developed under Earendil's earendil-works organisation. It enables four tools by default, read, bash, edit and write, asks for no approval before tool calls, and runs local models through built-in llama.cpp router support or a models.json entry for Ollama, LM Studio or vLLM. Run it in a container.
Pi’s README calls it a minimal, extensible harness you can make your own. The core stays small on purpose: features that other agents bake in, such as sub-agents, plan mode and permission prompts, are left to extensions, packages or your own workflow. That design suits developers who want to shape their own tooling, and it means isolation is your job rather than the agent’s.
Versions, defaults and config blocks below come from Pi’s README and documentation in the earendil-works/pi repository and from pi.dev, checked on 14 October 2026 against Pi 1.2.0, released on 12 October. Which model to load is a separate decision, covered in our open-weight coding model shortlist; our harness comparison sets the larger agents side by side.
What the Pi coding agent is
Mario Zechner described Pi in a November 2025 post as his attempt to build a coding tool he fully controlled. It began in his badlogic/pi-mono repository; the code now lives at github.com/earendil-works/pi, the licence file still carries his 2025 copyright under MIT, and pi.dev credits Earendil Inc. and contributors. The repository had about 115,000 GitHub stars on 14 October 2026.
Two dates matter if you follow older tutorials. The npm package moved from @mariozechner/pi-coding-agent, deprecated at version 0.73.1 in May 2026, to @earendil-works/pi-coding-agent. And Pi 1.0, released on 1 October 2026, added MCP and codemode, which changed one of Pi’s best-known design choices.
Pi runs in five ways, all on the same agent and session engine:
| Mode | How to start it | Typical use |
|---|---|---|
| Interactive | pi | The terminal UI, with sessions you can branch with /tree and /fork |
pi -p "prompt" | One-shot tasks and shell pipelines | |
| JSON | pi --mode json "prompt" | A JSONL event stream from a single run |
| RPC | pi --mode rpc | JSONL commands over stdin and stdout from another process |
| SDK | The TypeScript SDK | Embedding Pi in an application; the README cites OpenClaw as an example |
Installing Pi
-
Install with the official script. It pins dependencies and lets
pi updatehandle upgrades:curl -fsSL https://pi.dev/install.sh | shOn Windows:
powershell -c "irm https://pi.dev/install.ps1 | iex" -
Or install from npm, which needs Node.js 22.19 or newer and does not pin transitive dependencies:
npm install -g --ignore-scripts @earendil-works/pi-coding-agentNix users can run
nix profile add github:earendil-works/pi/stable. -
Check the install with
pi --version, then start Pi in the folder you want it to work in. Pi may ask whether you trust the folder before loading project settings, extensions or MCP servers from it.
On native Windows, Pi uses Git Bash for its bash tool and finds it under Program Files or on PATH. A powershell tool can replace it through "defaultTools": ["read", "powershell", "edit", "write"] in ~/.pi/agent/settings.json, or you can run Pi inside WSL with Linux tools.
Built-in tools and what Pi leaves out
Pi enables read, bash, edit and write at startup. It also ships grep, find, ls and, on Windows, powershell, which you switch on with --tools or the defaultTools setting; built-in extensions add codemode and tool_search, inactive until needed. Everything else is a choice pi.dev lists under “What we didn’t build”:
| Feature | In Pi | How to add it |
|---|---|---|
| Sub-agents | Not built in | Spawn Pi in tmux, write an extension (the repo has a subagent example) or install a package |
| Plan mode | Not built in | Write plans to files, or use the plan-mode example extension or a package |
| Permission prompts | None; tools run with your account’s permissions | Run in a container, or add a confirmation extension such as the permission-gate example |
| Built-in to-dos | Not built in | A TODO.md file or an extension |
| Background bash | Not built in | tmux |
| MCP | Built in since Pi 1.0 | pi mcp add, with codemode for composing tool calls |
The MCP row is the one that changed. Zechner’s 2025 post said Pi would not support MCP because servers add heavy context overhead, and argued that once an agent can write and run code, approval prompts offer little real protection. In late September 2026, Earendil’s post “You Said No MCP!” explained the reversal: the protocol had changed, and tools can now be deferred or called from a sandboxed script instead of being loaded into context up front. The stance on prompts has not changed.
Pi agent local LLM setup with Ollama
Pi’s documentation sends Ollama, LM Studio, vLLM and SGLang users to models.json in the agent directory, ~/.pi/agent/models.json unless PI_CODING_AGENT_DIR points elsewhere. The documented Ollama entry:
{
"$schema": "https://pi.dev/schemas/models.schema.json",
"providers": {
"ollama": {
"baseUrl": "http://localhost:11434/v1",
"api": "openai-completions",
"apiKey": "ollama",
"models": [
{ "id": "qwen2.5-coder:7b" }
]
}
}
}
The placeholder key matters: Pi shows a model in /model only once it can resolve credentials, and Ollama ignores the value. To run a current coding model, swap the ID and declare the window. The schema accepts contextWindow and maxTokens on each model:
{ "id": "qwen3-coder:30b", "contextWindow": 65536, "maxTokens": 16384 }
Then set the same context on the Ollama side, because its OpenAI-compatible API cannot change num_ctx per request:
ollama pull qwen3-coder:30b
OLLAMA_CONTEXT_LENGTH=65536 ollama serve
Start pi, open /model, which reloads models.json, and pick the Ollama entry. Compaction is worth checking on small windows. Pi compacts when the context passes the window minus reserveTokens, which defaults to 16,384 tokens held back for the reply, so on a 32K model it summarises at about half the window. Lower compaction.reserveTokens in settings.json, or give the model more context.
As starting points, the Apache 2.0 models Qwen3-Coder-30B-A3B-Instruct, Devstral Small 2 and gpt-oss-20b all come with tool support in Ollama’s library; our coding model guide compares them with larger options, and the VRAM calculator checks what fits.
Pi with llama.cpp, LM Studio and vLLM
The llama.cpp router
Pi integrates directly with llama-server in router mode, which discovers GGUF files in a folder and loads them on demand. Pi’s documentation starts the router like this; note that it passes --port 8080 explicitly, which matters now that llama-server builds from b11521 default to port 9931:
llama-server \
--models-dir ~/models \
--no-models-autoload \
--jinja \
--host 127.0.0.1 \
--port 8080 \
-ngl 999 \
-c 32768
Do not pass -m, --model or -hf, which switch the server to single-model mode. In Pi, run /login llama.cpp and accept the default address, http://127.0.0.1:8080, or set LLAMA_BASE_URL instead. /llama then loads and unloads models, or downloads one from Hugging Face, and /model selects a loaded one. If you start the server with --api-key, give Pi the same key through /login or LLAMA_API_KEY.
LM Studio, vLLM and other OpenAI-compatible servers
These use the same models.json pattern as Ollama. For LM Studio, load the model under a short identifier and point a provider at port 1234:
lms load qwen/qwen3-coder-30b --context-length 65536 --identifier qwen3-coder-30b
{
"$schema": "https://pi.dev/schemas/models.schema.json",
"providers": {
"lmstudio": {
"baseUrl": "http://127.0.0.1:1234/v1",
"api": "openai-completions",
"apiKey": "lmstudio",
"models": [
{ "id": "qwen3-coder-30b", "contextWindow": 65536 }
]
}
}
}
A vLLM server works the same way at its own address, usually port 8000, provided it was started with tool calling enabled. Pi’s docs add a caution: only set compatibility flags in models.json for differences you have verified, not because an endpoint claims OpenAI compatibility. For serving one model to several developers, our comparison of vLLM, Ollama and llama.cpp covers the trade-offs.
Extensions, skills, packages and MCP
Pi’s customisation layers, from lightest to heaviest:
- Prompt templates are Markdown prompts you expand with
/name. - Skills follow the Agent Skills specification: a folder with a
SKILL.mdthat Pi loads only when a task calls for it. Pi also reads~/.agents/skills/and a project’s.agents/skills/. - Extensions are TypeScript modules in
~/.pi/agent/extensions/that register tools, commands, providers, event handlers and terminal UI. They run inside the Pi process with your permissions and can read prompts, files and credentials, so load only code you trust. - Packages bundle the above for npm or git, for example
pi install npm:@example/pi-tools@1.0.0orpi install git:github.com/example/pi-tools@v1. - Themes change the terminal colours.
MCP servers are added from the shell:
pi mcp add filesystem -- npx -y @modelcontextprotocol/server-filesystem .
pi mcp list
User-level servers live in ~/.pi/agent/mcp.json. A project’s .pi/mcp.json is read only after you trust the project, and its format matches other MCP clients, so an existing mcpServers entry from Claude Code or Cursor can be copied across. Pi speaks stdio and streamable HTTP; the older SSE transport is rejected. When a server needs it, Pi switches on codemode, where the model writes a JavaScript script that runs in a QuickJS sandbox without Node APIs, file-system or network access and reaches the outside only through tools. On a local model with a small window, that keeps large tool catalogues out of the prompt.
Pi coding agent vs OpenCode and Claude Code
| Pi | OpenCode | Claude Code | |
|---|---|---|---|
| Licence | MIT | MIT | Proprietary, under Anthropic’s terms |
| Built-in workflow | Four default tools; no sub-agents, plan mode or to-dos | Build and plan agents plus built-in subagents | Subagents, plan mode and several permission modes |
| Default approvals | None before tool calls | Most actions allowed; outside directories and repeated identical calls ask | Auto mode with a safety classifier on supported Claude models, otherwise Manual, which asks before edits, shell commands and network access |
| MCP | Built in since Pi 1.0, with codemode and tool search | Local and remote servers, with OAuth | Supported |
| Local models | llama.cpp router built in; models.json for compatible endpoints | Any OpenAI-compatible server through opencode.json | Only through an Anthropic-format endpoint, which Anthropic does not support for non-Claude models |
| Interfaces | Terminal UI, print, JSON, RPC, TypeScript SDK | Terminal UI, desktop app, IDE extension, opencode run, HTTP server | Terminal, VS Code extension, desktop app, Agent SDK |
| Isolation | None built in; docs cover Docker, Docker Sandboxes, OpenShell and a Gondolin micro-VM extension | None built in; a container image is published | Operating-system sandbox for shell commands on macOS, Linux and WSL 2, off by default |
Pi coding agent vs OpenCode
Both are MIT-licensed and both treat local models as normal providers. The difference is how much arrives built in. OpenCode gives you a planning agent, subagents, an IDE extension and a permission system with allow, ask and deny rules out of the box. Pi gives you a smaller core, model management for llama.cpp from inside the agent, and a TypeScript extension API for building the rest. If you want to configure, pick OpenCode; if you want to program your agent, pick Pi. Our OpenCode local setup guide covers its configuration in detail.
Pi coding agent vs Claude Code
Model access is the dividing line. Claude Code is built around Claude models, and Anthropic supports nothing else; running it on a local model means an Anthropic-format endpoint and no vendor support, as our Claude Code local setup guide explains. Pi has no such boundary. In exchange, Claude Code ships controls that Pi leaves to you: approval modes, managed settings for administrators and a shell sandbox. For a wider view of coding assistants that can run on-premises, see our comparison of on-prem coding tools.
Running Pi safely and offline
Pi’s security page is direct: treat model-generated commands and code as untrusted, because Pi can read, change and run files with the permissions of the account that started it and does not ask before every tool call. Watching the transcript, project trust and reviewing diffs are not a security boundary. Running Pi entirely inside a container, VM or sandbox is, in the docs’ words, usually the strongest practical option.
The plain Docker recipe from Pi’s containerization page builds a small image:
FROM node:24-bookworm-slim
RUN apt-get update \
&& apt-get install -y --no-install-recommends bash ca-certificates git ripgrep \
&& rm -rf /var/lib/apt/lists/*
RUN npm install -g --ignore-scripts @earendil-works/pi-coding-agent
WORKDIR /workspace
ENTRYPOINT ["pi"]
Build it with docker build -t pi-sandbox -f Dockerfile.pi . and run it from your project folder with docker run --rm -it -v "$PWD:/workspace" -v pi-agent-home:/root/.pi/agent pi-sandbox. The named volume keeps the container’s own Pi settings and sessions between runs; the docs warn against mounting your host’s ~/.pi/agent instead, because that hands the container your host credentials. Pi’s own example also passes a provider API key with -e, which a local model does not need. Inside a container, 127.0.0.1 is the container itself, so point models.json at an address of the host that the container can reach. For gVisor, microVMs and the controls a sandbox needs beyond the kernel boundary, see our guide to sandboxing agents that run code.
To keep a local setup quiet on the network:
PI_OFFLINE=1disables automatic network activity, including model catalogue refreshes from pi.dev.PI_SKIP_VERSION_CHECK=1stops the latest-version request to pi.dev."enableInstallTelemetry": falseinsettings.json, orPI_TELEMETRY=0, turns off anonymous install and update reports and selected provider attribution headers. The separateenableAnalyticssetting is off unless you opt in./shareuploads a session to Earendil’s Radius service when Radius authentication is set up, otherwise to a private GitHub gist through the GitHub CLI; sessions can contain file contents and credentials, so review them first.
How VDF AI fits
Pi is built for a developer who wants to own the whole stack, down to the approval logic. That is its appeal, and it is also why it is hard to roll out to hundreds of engineers: every safeguard is an extension someone has to write, review and maintain. VDF AI does not run, host or integrate with Pi.
For organisations that need those safeguards built in rather than assembled, VDF Code is VDF AI’s governed coding assistant. It runs on infrastructure you control, air-gapped if required, and its product page lists model allow and block lists, tool restrictions per repository, approval gates for privileged operations and an audit trail covering prompts, model calls and edits.
Sources
Pi’s repository, documentation and releases, and the pages it is compared with, checked 14 October 2026.
- Pi repository, coding agent README, licence and releases
- pi.dev
- Pi docs: how Pi works, quickstart, usage, CLI, settings and environment variables
- Pi docs: models, llama.cpp, compaction and the models.json schema
- Pi docs: MCP, codemode, extensions, skills and packages
- Pi docs: security, containerization and Windows
- Extension examples
- npm: @earendil-works/pi-coding-agent and the deprecated @mariozechner/pi-coding-agent
- Earendil: Pi 1.0 and You Said No MCP!
- Mario Zechner’s November 2025 post on building Pi
- OpenCode: agents, permissions and MCP servers
- Claude Code: permission modes, sandboxing and LLM gateways
- llama.cpp server README and default port change, PR #30159
- Ollama: OpenAI compatibility and LM Studio CLI: lms load
- Ollama library: qwen3-coder, devstral-small-2, gpt-oss
Running coding agents for a whole engineering organisation? See how VDF Code adds governance on your own infrastructure, or contact our team.