Pi is an amazing coding harness. It is delightfully minimalistic. Instead of implementing common harness features like plan mode, subagents, or even web search, it provides an extension system and extension-authoring documentation that make it incredibly easy to vibe up your own.

There is, however, a delightful irony in all this. Pi's minimalist philosophy is thoroughly trampled by the most popular extensions on the package catalog, which tend to be feature-bloated beyond all recognition. Load up Pi with a few of these and suddenly your lightweight harness is full of bells and whistles, many of which are not well conceived. There is a useful lesson here about how to checkity check yourself before you wreck yourself with agentic development, so let's explore two popular examples from the catalog.

Disclaimer

I want to state at the outset that I have a lot of respect for the developers of these extensions that I'm about to lay into. They are popular for a reason. They work as intended and fill a real need in the community. But at the same time, they are examples of the kind of feature bloat that agentic coding invites.

So you want to search the web in pi

Pi's stubborn refusal to add web search is frustrating but understandable. Web search is a useful way to enable your agent to work with code that is too new or obscure to feature in the training data. But there are many search providers and the whole Pi philosophy is to avoid making decisions for the user.

So what do you get if you instead install by far the most popular extension for this, pi-web-access? Well, you add 88 MiB to your pi install and 211 npm packages. For this, you get 46 search-provider integrations (as of 8 November 2026), with a complex set of built-in fallback behaviours if one is unavailable. You get custom behaviour for GitHub (repos get checked out and searched over locally), PDF content extraction, YouTube video content analysis, and so on.

flowchart TD A(["pi-web-access"]) A -->|Search| B{"Search mode?"} B -->|Named| N["One provider"] B -->|"all or list"| P["Parallel providers"] B -->|"Auto or ordered route"| T["Try next eligible provider"] T --> D{"Provider outcome?"} D -->|"Skip or retry"| T D -->|"Route exhausted"| E["Saved weak result or error"] D -->|Accepted| R["Search results"] N --> R P -->|Merge| R P -.->|"Eligible default-list failure"| T R -->|"Optional page fetch"| F{"Source type?"} A -->|"Direct fetch"| F F -->|GitHub| G["Clone, CLI, or API"] F -->|"YouTube, if enabled"| Y["Video or summary"] F -->|Otherwise| W["HTTP extraction"] G -->|"No specialized result"| W W -->|PDF| K["Convert to Markdown"] W -->|"Recoverable failure"| H["Try eligible fetch fallbacks"]

This is arguably excessive. 99% of use cases are solved by standard text search through an external provider like Exa, or by just wiring searches through the Responses API for providers that support this like OpenAI. The latter approach is the one taken by the alternative search extension I would recommend, pi-web-search.

But in fact, with the recent addition of MCP as a native tool, you don't need any extensions at all. Just install Exa MCP and you have search.

So you want subagents in pi

Subagents is another popular feature the pi developers have refused to implement so far (they do offer an "example" subagent extension, which is disabled by default and lacks basic functionality). I'm less sympathetic to this call. With the recent addition of codemode, pi can now orchestrate tool calls like MCP in blocks of JavaScript. That puts us tantalisingly close to having a capable subagent implementation if the developers would just add that tool as well...

Anyway, subagents is a complicated extension to DIY so you probably reach for pi-subagents instead. It looks reasonably lightweight at 23 MiB extra size and a mere 7 npm packages. But the feature set is anything but, because you end up with a full-on software factory. You get:

  • Several predefined agents with somewhat nebulous roles
  • Several workflows (basically scripts that instruct the agent to run subagents in a particular pattern)
  • A watchdog (basically a subagent that reviews each change by the main agent)
  • Missions, runs and records (basically attempts to manage overall project state natively within the extension)
  • Scheduling of runs

In fairness, not all of this is enabled by default, but enough of it is added to the agent's prompt that you may see some exciting dynamic behaviors if you so much as utter the word "subagents" in one of your prompts. If you use the associated skill things really go off the rails.

I don't want to be negative! A lot of these features sound cool and might be really useful! But did they all need to get bundled in the same extension?

So what should you use for subagents instead? Honestly, I'm not sure. If anyone has found a well-designed yet minimalistic extension for this, let me know! I live in hope that the pi maintainers eventually will provide a basic subagent tool with a native TUI.

What have we learned about agentic engineering today?

The point of all this isn't to pick on these specific developers - you don't have to use their extensions if you don't like their product choices. It's just that these extensions show so clearly what can happen to a codebase when the next feature is a prompt away.

People talk about the comprehension gap that results when the developer leaves all coding work to agents, but if you take this far enough you also end up with products that have so many features that the end user struggles to reason effectively about what the program's behaviour and capabilities are. I struggle with this myself constantly at $day_job and I wish I could write more about those experiences here.

Agents are not good at designing modular solutions with loose coupling between the components, or at creating new functionality as the combination of a set of modular tools. Agents are never going to respond to your latest prompt with a YAGNI.

The only way to stave off full agentic psychosis is to build with intent and clear purpose. That might mean coding less and researching and thinking a lot more than we're used to as developers. It might also mean that we need to get used to throwing new features away rather than merging half-baked ideas. Now that code is cheap we have to get a lot more selective with what gets included in a release.


Comments

comments powered by Disqus