Course · Pi · Your first extension
Your first extension
Last chapter ended on a specific lack. The cheap model ran the re-extraction sweep well, but only because your instructions were tight enough to leave nothing to interpret - and you typed them fresh, by hand, every time the backlog produced another chore.
The closer said it plainly: nothing you did in that module taught Pi a new move - a command that lists the backlog rows still needing attention, a tool that re-runs one feed’s sync. Config files can’t build you a capability. This chapter is where that promise gets built.
Every chapter so far has spent the context window on purpose instead of by accident: watching a turn run, reading the real prompt, routing work to the model that fits it. This chapter’s trade is different in kind, not degree. A registered tool earns a line in the system prompt, sent on every single turn for the rest of that extension’s life, whether you use it that session or not. Building a capability is cheap. Owning what it costs forever is the actual chore.
stash (the course’s running example, a small FastAPI feed reader) has a concrete case. The re-extraction backlog - rows saved during the broken-parse window, carrying a missing published, an empty link, or a blank summary - still sits in stash.db. Finding what’s left means hand-writing SQL against the database.
Fixing a feed means remembering the pipeline’s shape, opening a Python shell, and driving fetch_feed and save_article by hand. You have done both all week. That is exactly the kind of repeatable, well-defined chore that deserves to become a first-class move instead of a thing you re-derive from memory each time.
And it needs a new move, not a bridge to somewhere else. You don’t wait for the maintainers to ship a “re-sync” feature, and you don’t reach for an MCP server - the chore lives entirely inside the repo you already have. You write a small TypeScript file, and Pi picks it up.
You’ll build the three extensions below by hand, because seeing the shape once is worth more than reading about it. From the next chapter on, you’ll mostly describe the extension you want and let Pi write the file - the point of building these yourself is knowing enough to review and correct what it generates.
What you’ll build
Section titled “What you’ll build”- Anatomy of an extension - the factory function every extension exports, where Pi looks for them, and how
/reloadgets a new one running without restarting your session. - Build a command:
/stash- a user-triggered slash command that surfaces which stored entries still need attention, so you stop hand-writing SQL to find them. - Build a tool: re-sync a feed - a typed, LLM-callable tool that re-runs the fetch-and-parse pipeline for one feed, so the agent can clear its backlog rows without you doing the Python-shell dance.
- Hook into the loop - the lifecycle events that let an extension see and shape what Pi does on every turn, and where MCP actually fits into this picture (a lot narrower than you’d guess).
By the end you’ll have two new moves in your stash harness - one you trigger, one the agent triggers - and you’ll understand the event hooks that everything else in this course’s extensions (permissions, task discipline, subagents) turns out to be built from.
Start with how an extension is put together.