In the Tools lesson, you connected an MCP server to give Pi access to an external tool. That’s one way to extend Pi — but it only adds tools. What if you want to hook into Pi’s own lifecycle, add a custom slash command, or change how Pi behaves rather than just what it can reach?
That’s what extensions are for. An extension is a TypeScript module Pi loads at startup. It can subscribe to events, register custom tools and commands, and even build its own terminal UI — this is Pi’s flagship way of customizing itself.
Where extensions live
- Global —
~/.pi/agent/extensions/, as either a*.tsfile or a*/index.tssubdirectory. Available in every project. - Project —
.pi/extensions/, same file layout. Only loaded once the project is trusted.
Extensions in these locations are hot-reloaded with /reload — no restart needed for changes to existing extensions, though newly installed extensions still need Pi to discover them at startup.
What extensions can do
A minimal extension is just a function that receives an API object:
export default function (pi) {
pi.on("session_start", async (event, ctx) => {
// React to a session starting
});
pi.registerCommand("hello", {
description: "Say hello",
async execute(args, ctx) {
ctx.ui.notify("Hello!");
},
});
}
A few of the things extensions can do:
pi.on(event, handler)— subscribe to lifecycle events like a session starting, a tool being called, or the model changing.pi.registerTool(definition)— register a custom tool the LLM can call, the same way built-in tools likereadorbashwork.pi.registerCommand(name, options)— add a new/commandthat shows up alongside Pi’s built-in ones.ctx.ui.custom()— build a full custom TUI component with its own keyboard handling, for interactions more complex than plain text.
Extensions can also hold state across a session — well-behaved ones store it in a tool result’s details field so it reconstructs correctly if you branch the conversation (covered in the Branching lesson).
Pi ships more than 60 example extensions covering patterns like these — dynamic tool registration, custom footers, session handoff, and more. Browse them for inspiration before writing your own.
Install a real extension: pi-web-access
Pi has no built-in web search or URL-fetching tool. pi-web-access fills that gap — it adds web_search and fetch_content tools that handle regular web pages, GitHub repos (cloned locally instead of scraped), PDFs, and YouTube videos.
Install it:
pi install npm:pi-web-access
It works immediately with no API keys required. Run /reload to pick it up, then try it:
Search the web for what’s new in TypeScript 5.9
A note on modes
If you’ve used agent tools with a built-in “Plan mode” that separates planning from execution, you might look for the same thing in Pi’s settings — it isn’t there, since Pi has no built-in modes. The bundled plan-mode.ts example extension shows how to build that behavior yourself if you want it.
Find more extensions and write your own
Ask Pi to build you an extension for a workflow you want to automate — describe what you want and it can scaffold one using the patterns above. For the full API reference and all bundled examples, see Pi’s own extensions documentation.