{"slug": "working-with-pi-coding-agents", "title": "Working with Pi Coding Agents", "summary": "Pi, a minimal coding agent built by Mario Zechner, has surpassed 70,000 GitHub stars by deliberately omitting features like MCP, sub-agents, and plan mode, instead offering only four core tools (read, write, edit, bash) and extension points. The project was acquired by Earendil Inc., led by Flask creator Armin Ronacher, and now includes a companion cloud platform called Lefos under an open-core MIT license with paid layers. Pi's approach challenges mainstream coding harnesses by prioritizing transparency and user control over feature bloat.", "body_md": "# Working with Pi Coding Agents\n\nThe most interesting thing about Pi isn't any single feature; it's that the project treats \"what we didn't build\" as documentation worth writing, which is rare enough on its own to take seriously.\n\n## # Introduction\n\nMost coding agents compete on how much they do for you. Claude Code manages sub-agents, plan mode, and permission flows out of the box. Cursor wraps an entire IDE around the model. The pitch is always some version of \"more capability, less setup.\" ** Pi** does the opposite, and says so directly in its own documentation: no MCP, no sub-agents, no plan mode, no permission popups, no built-in to-do lists, no background bash. Where other tools list features, Pi's README lists what it refuses to build in.\n\nThat's an unusual thing for a product to lead with, and it's worth testing. So this article does exactly that. I installed Pi in a real environment, confirmed the version against its own changelog, and wrote a working TypeScript extension that I loaded into the live binary.\n\nPrerequisites:\n\n- Node.js 22 or newer, npm, and a terminal\n- An API key for at least one provider (Anthropic, OpenAI, Google, or others) if you want to run real sessions rather than just install and inspect the tool, which is enough to follow along with everything below\n\n## # What Pi Actually Is, and Who's Behind It\n\nPi was built by Mario Zechner, a developer also known for his work on ** libGDX**, who\n\n[published a long, unusually candid essay in November 2025](https://mariozechner.at/posts/2025-11-30-pi-coding-agent/)explaining why he built it. His argument was structural: mainstream coding harnesses inject context you can't see, change their behavior between releases without much warning, and give you limited visibility into what the model actually received. His response was to build the opposite, a small core loop surrounded by extension points, rather than a feature-complete product with a fixed way of working.\n\nThe project picked up serious momentum fast. Armin Ronacher, the creator of Flask and Jinja2, wrote [a technical essay in January 2026](https://www.implicator.ai/pi-is-not-a-claude-code-rival-it-is-a-harness-rebellion/) publicly endorsing Pi as the minimal agent worth building around. Roughly two months later, Ronacher's company, Earendil Inc., acquired the project outright, brought Zechner in as a major stakeholder, and launched a companion cloud platform called ** Lefos** alongside it. The acquisition came with an actual governance document, RFC 0015, which commits Pi's core to staying MIT-licensed while reserving room for paid, Fair Source layers and hosted services built on top — an open-core structure that's common in infrastructure software but worth knowing about upfront if you're deciding whether to build a workflow around it.\n\nAs of this writing, Pi's [GitHub repository](https://github.com/earendil-works/pi/tree/main/packages/coding-agent) has passed 70,000 stars and is still climbing, which is a meaningful number for a tool that markets itself almost entirely on doing less. I confirmed the current release directly rather than trusting a changelog snapshot: after installing it fresh, `pi --version`\n\nreported 0.80.3, matching [the version listed on Pi's own news page](https://pi.dev/news) as the latest release.\n\n## # The Four Tools and What's Deliberately Missing\n\nPi's entire built-in toolset is four tools: `read`\n\n, `write`\n\n, `edit`\n\n, and `bash`\n\n. That's not a starting point that grows into something bigger by default; it's the whole thing. Running `pi --help`\n\nagainst the actual installed binary confirms this directly; the tool describes itself in its own help text as an \"*AI coding assistant with read, bash, edit, write tools*.\"\n\nEverything else that other agents ship natively, Pi treats as something you add. Its own documentation is explicit about the omissions: no MCP support built into the core, no sub-agent orchestration, no plan mode, no permission confirmation popups, no built-in to-do tracking, and no background bash execution. The stated reasoning is about the token cost as much as philosophy. Reports on comparable coding agents put their default system prompts at [7,000 to 10,000 tokens before a user types anything](https://byteiota.com/pi-coding-agent-minimal-harness/), and that cost recurs on every single API call for the life of the session. Pi's system prompt runs under 1,000 tokens by design, and the only things it injects beyond that are your own `AGENTS.md`\n\nfiles — a global one for all your sessions and a project-specific one, both fully visible and editable by you.\n\nThe bet underneath all of this is that frontier models already understand what a coding agent is supposed to do, since they've been reinforcement-learning-trained on agentic tasks extensively, and a smaller prompt leaves the model more of its own context budget for the actual work instead of instructions about how to behave. Whether that bet pays off depends heavily on what you're trying to do with it, which the rest of this article tests directly.\n\n## # Hands-On: Installing It and Running a Real Session\n\nInstalling Pi is a single command. It ships as an npm package under Earendil's scope.\n\n```\n# Recommended install (the --ignore-scripts flag is what Pi's own docs suggest)\nnpm install -g --ignore-scripts @earendil-works/pi-coding-agent\n\n# Or, on macOS/Linux, the standalone installer script\ncurl -fsSL https://pi.dev/install.sh | sh\n```\n\nI ran the npm install command exactly as written above in a clean environment. It completed in about eleven seconds, pulling in 131 packages, and placed a working pi binary on the path. Running `pi --version`\n\nimmediately after returned 0.80.3, confirming the install actually worked rather than silently failing.\n\nAuthentication has two paths. If your provider supports it, running `/login`\n\ninside a Pi session opens an OAuth flow for subscription-based access. Otherwise, set an API key as an environment variable before launching:\n\n```\nexport ANTHROPIC_API_KEY=sk-ant-your-key-here\n# or, for a specific project, pi config set works too:\npi config set ANTHROPIC_API_KEY=sk-ant-your-key-here\n```\n\nWith a key set, starting a session is just:\n\n```\ncd your-project-directory\npi\n```\n\nThat drops you into Pi's terminal interface with the four built-in tools live and whatever `AGENTS.md`\n\nfile exists in that directory loaded as project context. From here, `/model`\n\nswitches providers mid-session (`/model sonnet`\n\n, `/model gpt-5`\n\n, or a local Ollama model), and **Ctrl+P** cycles through favorites without typing the full command. According to [Pi's own documentation](https://pi.dev/docs/latest), the platform supports 15 or more providers directly, including [Anthropic](https://www.anthropic.com/), [OpenAI](https://openai.com/), [Google](https://www.google.com/), [Azure](https://azure.microsoft.com/en-us), [Bedrock](https://aws.amazon.com/bedrock/), [Mistral](https://mistral.ai/), [Groq](https://groq.com/), [Cerebras](https://www.cerebras.ai/), [xAI](https://x.ai/), [Hugging Face](https://huggingface.co/), [OpenRouter](https://openrouter.ai/), and [Ollama](https://ollama.com/) for fully local models, which I confirmed matches the provider list the CLI itself references when no key is configured; running `pi --list-models`\n\nwith no provider set pointed me directly at Pi's own provider and model documentation rather than failing silently.\n\nOne detail worth flagging for teams evaluating this seriously: Pi stores sessions as trees, not linear logs. The `/tree`\n\ncommand lets you navigate back to any earlier point in a conversation and branch from there, with every branch preserved in a single session file rather than overwritten. That's a genuinely different mental model from most chat-style agent interfaces, and it matters more once you're running longer, more exploratory sessions where you want to try two different approaches without losing either one.\n\n## # Building a Real Extension: A Permission Gate Plus a Custom Tool\n\nThis is where Pi's minimalism turns into something concrete. Since there's no built-in permission confirmation for risky bash commands, and no rule stopping the model from running `rm -rf`\n\nor a forced git push, you build that yourself, as a TypeScript extension. Here's a real one, written against Pi's documented extension API and then actually loaded into the installed binary to confirm it works.\n\n``` python\n// permission-gate.ts\nimport type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";\nimport { Type } from \"typebox\";\n\nexport default function (pi: ExtensionAPI) {\n  // Permission gate: confirm before pi runs anything that looks destructive\n  pi.on(\"tool_call\", async (event, ctx) => {\n    if (event.toolName === \"bash\" && typeof event.input.command === \"string\") {\n      const risky = /\\brm\\s+-rf\\b|\\bsudo\\b|\\bgit\\s+push\\s+--force\\b/;\n      if (risky.test(event.input.command)) {\n        const ok = await ctx.ui.confirm(\n          \"Risky command\",\n          `Allow: ${event.input.command}`\n        );\n        if (!ok) {\n          return { block: true, reason: \"Blocked by permission gate extension\" };\n        }\n      }\n    }\n  });\n\n  // A small custom tool the model can call directly\n  pi.registerTool({\n    name: \"count_words\",\n    label: \"Count Words\",\n    description: \"Counts words in a block of text.\",\n    promptSnippet: \"Count words in a string\",\n    parameters: Type.Object({\n      text: Type.String({ description: \"Text to count words in\" }),\n    }),\n    async execute(toolCallId, params) {\n      const count = params.text.trim().split(/\\s+/).filter(Boolean).length;\n      return {\n        content: [{ type: \"text\", text: `${count} words` }],\n        details: { count },\n      };\n    },\n  });\n\n  pi.registerCommand(\"gate-status\", {\n    description: \"Show that the permission gate extension is active\",\n    handler: async (_args, ctx) => {\n      ctx.ui.notify(\"Permission gate extension is active.\", \"info\");\n    },\n  });\n}\n```\n\nWhat this does: `pi.on(\"tool_call\", ...)`\n\nhooks into every tool call the agent attempts, before it executes. The regular expression checks whether a `bash`\n\ncall contains something genuinely dangerous — a recursive force-delete, a `sudo`\n\nescalation, or a forced push that could overwrite remote history — and if it matches, `ctx.ui.confirm`\n\npauses execution and asks you directly in the terminal. Returning `{ block: true, reason: ... }`\n\nis what actually stops the tool call from running; if you decline, the model sees the block reason and has to adjust rather than silently retrying. `pi.registerTool`\n\nis a separate, independent piece: it adds a brand new tool, `count_words`\n\n, that the model can call on its own whenever it decides counting words is useful, defined with a TypeBox schema so Pi can validate the input before your `execute`\n\nfunction ever runs. The `registerCommand`\n\nblock is just a convenience, a `/gate-status`\n\nslash command confirming the extension loaded.\n\nHow to test it: save the file, then load it explicitly with the `-e`\n\nflag:\n\n```\npi -e ./permission-gate.ts --list-models anthropic\n```\n\nI ran this exact command against the real installed Pi binary before writing this section. It returned cleanly with no syntax or registration errors, with pi loading the extension file, parsing the TypeScript, and registering both the event hook and the tool without complaint. In a full interactive session with a real API key, the next step would be asking the agent to run something like `rm -rf ./tmp`\n\n, and watching the confirmation prompt actually intercept it before execution — exactly the behavior Pi's own docs describe as the intended pattern for this kind of extension, since [permission handling isn't in the core by design](https://pi.dev/docs/latest/extensions) and is meant to be built to match your own threat model rather than imposed uniformly on every user.\n\nA simple sequence diagram\n\nExtensions can go considerably further than this: intercepting messages before every turn, replacing the default context compaction that runs automatically when a session fills up, wiring in retrieval-augmented memory, or adding entirely new slash commands. The permission gate above is a genuinely useful starting extension, but it's also a small sample of a much larger surface, one that Pi's own documentation describes in enough depth to build almost anything the built-in feature set left out.\n\n## # Where the Minimalism Actually Helps\n\nThree things held up under actual use rather than just sounding good in the pitch.\n\n- The session tree is the strongest one. Being able to branch a conversation at any point with\n`/tree`\n\nand try a different approach without losing the original thread is a real workflow improvement over a linear chat log, and it's not something most competing agents offer as a first-class, always-on feature. - Multi-provider switching is the second. Pi's provider list genuinely does span the major hosted APIs and local inference through Ollama, and switching models mid-session with\n`/model`\n\nor cycling favorites with**Ctrl+P** worked exactly as documented when I tested it against the installed binary — no restart, no lost context. For teams that want to compare model output on the same task without standing up separate tooling for each provider, that's a real, tangible convenience. - The token savings from the minimal system prompt are the third, and the hardest to independently verify without running side-by-side benchmarks across tools, but the mechanism is at least real and checkable: a sub-1,000-token system prompt versus a reported 7,000 to 10,000 tokens for comparable tools is a meaningful difference on every single request, especially for longer sessions where that overhead compounds across dozens of turns.\n\n## # Where It Costs You\n\nThe honest cost of minimalism is that the things Pi doesn't build in, you have to build yourself, or accept going without. If your team wants sub-agents coordinating on a large task, or a plan-review step before code gets written, or permission gates on every risky action rather than just the ones you thought to write a regex for, none of that exists until someone writes the extension for it. Pi will happily help you write that extension, since the model has full access to its own extension API and can generate new tools on request, but that's still work your team is doing that a more opinionated tool would have shipped already.\n\nOne independent review put this limitation more bluntly than most marketing copy would allow: a reviewer evaluating Pi against Claude Code for unattended, overnight agent runs concluded they loved Pi but couldn't use it for that specific workflow, precisely because the built-in safety rails other tools ship by default aren't there until you add them. That's not a knock on Pi's engineering; it's a direct consequence of the design decision covered in section 2, and it's worth taking at face value rather than assuming it's an exaggeration.\n\nDocumentation and community support are thinner than for an established tool too. Independent coverage describes Pi's docs as solid for core features but noticeably thinner for edge cases, backed by a single company, a Discord server, and a GitHub issue tracker rather than the years of accumulated Stack Overflow answers that a more mainstream tool has behind it. If you hit an unusual problem, reading the source is a more likely path to an answer than searching for it.\n\nThere's the ownership question, and it's worth restating plainly rather than glossing over: Pi's core is committed to staying MIT-licensed under RFC 0015, but Earendil's Fair Source layers and the Lefos hosted platform sit on top of that free core, and the company's revenue needs will shape what gets built into which layer over time. That's not a reason to avoid the tool today, since the free core works as described, but it's a reasonable thing to keep an eye on if you're planning to depend on this long term.\n\n## # The Verdict\n\nPi is a genuinely good fit if you already think carefully about what enters your model's context and want to control that deliberately rather than trust a vendor's black box, if you work primarily in a terminal and don't need a GUI fallback, if you're comfortable writing or requesting extensions rather than waiting for a feature to ship, and if using several different model providers in the same workflow matters to you. The permission gate extension in this article took under thirty lines of TypeScript and loaded into the real binary without a single error, which is a fair signal that \"*you can build what's missing*\" isn't just a marketing line.\n\nIt's a worse fit if what you actually want is a tool that runs unattended overnight with sensible defaults already in place, if you'd rather not read source code to solve an edge case, or if you're not willing to spend any time on extensions and just want sub-agents and plan mode to exist the moment you install something. Both of those are legitimate ways to want to work, and Pi is honest enough in its own documentation about which one it's built for.\n\n## # Wrapping Up\n\nThe most interesting thing about Pi isn't any single feature; it's that the project treats \"*what we didn't build*\" as documentation worth writing, which is rare enough on its own to take seriously. Before adopting it for real work, the question worth asking is the same one this article tried to answer directly: Do you want a harness that does more for you by default, or one that does less so you can decide exactly what gets added and why? Pi only wins that comparison for people who genuinely want the second option, and after actually installing it, running it, and building against its real extension API, that's a smaller but more sincere claim than most coding agent launches make.\n\nis a software engineer and technical writer passionate about leveraging cutting-edge technologies to craft compelling narratives, with a keen eye for detail and a knack for simplifying complex concepts. You can also find Shittu on\n\n[Shittu Olumide](https://www.linkedin.com/in/olumide-shittu/)", "url": "https://wpnews.pro/news/working-with-pi-coding-agents", "canonical_source": "https://www.kdnuggets.com/working-with-pi-coding-agents", "published_at": "2026-07-16 14:00:16+00:00", "updated_at": "2026-07-16 14:41:42.886596+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-tools", "ai-products", "ai-startups"], "entities": ["Pi", "Mario Zechner", "libGDX", "Armin Ronacher", "Earendil Inc.", "Lefos", "Claude Code", "Cursor"], "alternates": {"html": "https://wpnews.pro/news/working-with-pi-coding-agents", "markdown": "https://wpnews.pro/news/working-with-pi-coding-agents.md", "text": "https://wpnews.pro/news/working-with-pi-coding-agents.txt", "jsonld": "https://wpnews.pro/news/working-with-pi-coding-agents.jsonld"}}