A few weeks ago I gave another internal talk, this time about Pi, a coding agent harness I've been using to experiment. If the Claude Code post was about squeezing a very complete tool, this one is almost the opposite: the smallest possible tool, and everything you can learn precisely because it hides nothing.
Heads-up: this is experimental territory, not a recommendation for your daily workflow. Pi is powerful and dangerous in equal measure, and part of the fun of this post is giving you a template so you can play with it without shooting yourself in the foot.
What Pi is
Pi is the agent harness that actually sits at the core of OpenClaw. It's minimal to the extreme: four tools — read, write, bash and ls — and with that, a model can do anything on a computer. No plan mode, no MCPs, no sub-agents, no Jira integration, no connection to your GitHub repo. Above all, there's no permissions system and no guardrails: you ask it for something and it goes and does it, doing whatever is needed to get it done, including installing global dependencies or writing bash scripts.
My favorite metaphor: Pi is to agent harnesses what vim is to IDEs. It's the bare minimum, and you can add whatever you want on top. Just like you can build your own IDE on top of vim, you can build your own Claude Code on top of Pi.
Minimal as it is, it's not without opinions. It has three very specific traits that make it interesting:
- Transparency. The model's entire thought process, every tool call, every command and its output are visible in the session output.
- Session export. It generates an HTML file with the complete session that you can share.
- Tree navigation. You can jump to any point, resume the session from there, and open a new branch in the session tree.
Why transparency matters so much
This is what really hooked me. When you work with Claude Code and spawn sub-agents, all you see is "working…" and then a result; with the new versions you can jump into the sub-agent's session, but all of that is lost once the agent finishes its work. With Pi you see exactly what the model is doing at every step. If you want sub-agents, you ask pi to create them using pi, in tmux or as background processes — and you can save those sessions too.
The HTML export lets you review everything with a small UI: a sidebar with navigation where you can filter to only the user prompts, see everything with or without tool calls, and jump to any point. (Claude's export, by comparison, is the bare console text.)
What's that good for in practice? Learning how a model behaves given a specific prompt. Whether the model gets something wrong or tries several times, whether it starts "reading" files it shouldn't, whether it misinterprets your prompt (you also see the full "thinking" output).
I ran the same task — replacing some percentages with bars in a dashboard — with Claude using Opus and with Pi using an open-source model, and comparing the two sessions side by side was the most instructive part of the whole experiment: where it needs an example, where it forgets to write tests (both forgot, by the way).
Running it safely
Pi runs in YOLO mode by default. No permission prompts, no questions, it does what it thinks it needs to do. Installing it globally on your machine is very risky and totally inadvisable — one bad prompt or one hallucination and you have the agent running bash with your credentials and your whole filesystem within reach.
One solution is to put it in a Docker container. For the agent, the whole world is that empty container with a project folder and nothing else. It doesn't see your environment variables (only the ones you pass), doesn't see your system, and can't touch the network unless you explicitly allow it. The risk of it doing something destructive drops massively.
You can use this Dockerfile as a template: it installs pi globally, copies your provider extension if you use LiteLLM or ollama, and gets everything ready to run as an unprivileged user.
FROM node:24-bookworm-slim
# Basic tools + pi installed globally
RUN apt-get update && apt-get install -y --no-install-recommends git ripgrep fd-find \
&& apt-get clean && rm -rf /var/lib/apt/lists/* \
&& ln -sf /usr/bin/fdfind /usr/local/bin/fd
RUN npm install -g @mariozechner/pi-coding-agent
# Pi config structure under the node user's home
RUN mkdir -p /home/node/.pi/agent/extensions && chown -R node:node /home/node/.pi
# Pass whatever config you want, like your provider extension,
# your settings and the model list
COPY --chown=node:node extensions/ /home/node/.pi/agent/extensions/
COPY --chown=node:node .pi/settings.json /home/node/.pi/agent/settings.json
COPY --chown=node:node .pi/agent/models.json /home/node/.pi/agent/models.json
# Non-root user (UID 1000): no sudo, and files keep your permissions
USER node
WORKDIR /workspace
ENTRYPOINT ["pi"]
Build it with docker build -t pi-agent . and, once you have the image, run it interactively:
docker run -it \
--cap-drop ALL \
--security-opt no-new-privileges \
-e API_KEY=$YOUR_API_KEY \
-v "$(pwd):/workspace" \
pi-agent
-
--cap-drop ALLremoves all Linux capabilities and--security-opt no-new-privilegesprevents privilege escalation inside the container. - In the
Dockerfilethe agent runs as thenodeuser (UID 1000, not root), so it has no sudo and the files it creates have user 1000 permissions — usually the first user on the system, so it probably matches yours. -
-v "$(pwd):/workspace"mounts only the current directory: the only thing the agent can read, edit or execute. - Only the environment variables you pass with
-ereach it, normally nothing more than the API key.
One detail worth mentioning: I put an AGENTS.md in the image telling the agent it's inside an isolated sandbox, that it should not try to inspect the environment (DNS, installed tools, network…) because what it sees doesn't correspond to your real machine, and that it should instead give you instructions so you can check things yourself. Without that, small models start running dig and whois inside the container and confuse themselves.
With an alias you're two keystrokes away:
alias pi='docker run -it --cap-drop ALL --security-opt no-new-privileges -e API_KEY=$YOUR_API_KEY -v "$(pwd):/workspace" pi-agent'
Easy as pi.
Models: from cloud proxies to open source
Pi talks to any OpenAI-compatible provider, and adding one is a few lines in an extension. The structure looks like this (you register a provider with its baseUrl, its key and the model list):
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
export default function (pi: ExtensionAPI) {
pi.registerProvider("My proxy", {
baseUrl: "https://your-litellm-proxy/v1",
apiKey: process.env.API_KEY,
api: "openai-completions",
models: [
{
id: "glm-5",
name: "GLM 5",
input: ["text"],
contextWindow: 200000,
maxTokens: 32768,
reasoning: false,
cost: { input: 1, output: 3.2, cacheRead: 0, cacheWrite: 0 },
},
// ...more models
],
});
}
Pointing at a proxy like LiteLLM you can use both frontier models (Claude and friends) and open-weight ones, which is where the fun part is. Of what I've tried, GLM 5 is the best by far — I'd say it's around Sonnet level — and you can do a lot with it; Minimax 2.5 and Kimi K2.5 also hold up well. I wouldn't use it for everything (you miss the MCPs, integrations, memory, sub-agents…), but running them a couple of times while watching the whole session teaches you a lot about where open models stand today.
Local models with Ollama
Another option is running the model on your own machine, without sending anything anywhere. Pi connects to Ollama just like any other OpenAI-compatible provider (pointing at http://127.0.0.1:11434/v1).
Using an Ollama model for agentic tasks isn't entirely plug-and-play: you need to create a variant with the right configuration using a Modelfile. The key is lowering the temperature and tuning the context window and output tokens. The Gemma4 models have their own recommended parameters for agentic tasks; for qwen I've tested with:
FROM qwen3.5:9b
# Config for coding tasks: low temperature, contained context
PARAMETER temperature 0.1
PARAMETER top_p 0.8
PARAMETER top_k 20
PARAMETER num_ctx 32768
PARAMETER num_predict 4096
# Number of CPUs (leave headroom to keep working)
PARAMETER num_thread 8
To create the model:
ollama pull qwen3.5:9b
ollama create qwen-coding -f Modelfile
On which model to choose, my experience on a Linux box with 32 GB of RAM and no GPU:
- The 9B (Qwen) is the reasonable minimum. It takes over a minute to warm up and is slow, but it handles small tasks and answers questions about the repo.
- The 4B hallucinates out of control: it makes things up and keeps derailing the conversation.
- On a Mac, you can go for 27/30B models, which land somewhere between Haiku and Sonnet in terms of capability.
Pi has one decisive advantage over Claude Code for small models: Claude Code's system prompt is thousands of lines with a ton of tools, and that overwhelms small open models. Pi's minimalism is exactly what lets them work.
There's something special about being offline — on a train or wherever — and still being able to ask your repo questions and get changes made by just asking the agent.
In summary
Pi as a test bench is unbeatable: you see everything the model does, compare behaviors, and can run open-source and local models that wouldn't even start under a heavier harness. If you're interested in understanding how agents work on the inside, instead of just using them, it's well worth setting it up over a weekend. Just make sure: inside a container. If you're interested, I have a small repo with this setup for local models on github.
As always, you can leave comments here or on github or write to me on bluesky. And if you set up your own Pi configuration, I'd love to hear how it goes.

Top comments (0)