| name | meta-extension-creator |
| description | Create Pi extensions with event handling, commands, and hooks. Use when building extensions that respond to session events or add custom commands. |
| license | MIT |
| compatibility | pi |
| metadata | {"audience":"developers","category":"meta"} |
Meta Extension Creator
Create Pi extensions with event handling, commands, and custom functionality.
What I Do
- Generate properly structured Pi extension files
- Set up TypeScript extensions with correct imports
- Create event handlers for session lifecycle
- Register custom commands
- Guide on extension architecture patterns
When to Use Me
Use this skill when:
- Creating extensions that respond to events
- Adding custom slash commands
- Building automation extensions
- Setting up session lifecycle hooks
Do NOT use for:
- Creating skills (use meta-skill-creator)
- Creating agents (use meta-agent-creator)
- Creating tools only (use meta-tool-creator - simpler)
Quick Start
Basic Extension
Create .pi/extensions/my-extension/index.ts:
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
export default function myExtension(pi: ExtensionAPI) {
pi.on("session_start", async (event, ctx) => {
ctx.ui.notify("Session started!", "info");
});
pi.on("session_end", async (event, ctx) => {
});
pi.registerCommand("hello", {
description: "Say hello",
handler: async (args, ctx) => {
ctx.ui.notify(`Hello, ${args || "world"}!`, "info");
},
});
}
Extension with Tool
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
import { Type } from "@sinclair/typebox";
export default function myExtension(pi: ExtensionAPI) {
pi.registerTool({
name: "my_tool",
label: "My Tool",
description: "Does something useful",
parameters: Type.Object({
input: Type.String({ description: "Input data" }),
}),
async execute(_toolCallId, params, _onUpdate, ctx, _signal) {
return {
content: [{ type: "text", text: `Processed: ${params.input}` }],
};
},
});
pi.registerCommand("do-thing", {
description: "Run my tool",
handler: async (args, ctx) => {
ctx.ui.notify("Running tool...", "info");
},
});
}
Extension Location
- Project:
.pi/extensions/<name>/index.ts
- Global:
~/.pi/agent/extensions/<name>/index.ts
Extensions are auto-discovered via "extensions": ["extensions/*"] in settings. No config change needed when adding new extensions to .pi/extensions/.
Available Events
| Event | Description |
|---|
session_start | Session begins |
session_end | Session ends |
message | User or assistant message |
tool_call | Tool is being called |
tool_result | Tool returned result |
Event Handler Signature
pi.on("session_start", async (event, ctx) => {
});
Registering Commands
pi.registerCommand("my-command", {
description: "What this command does",
handler: async (args, ctx) => {
if (args === "help") {
ctx.ui.notify("Usage: /my-command <arg>", "info");
return;
}
ctx.ui.notify("Done!", "success");
},
});
Custom Events
Extensions can emit and listen to custom events:
pi.events.emit("my-extension:something", { data: "value" });
pi.events.on("other-extension:event", (data) => {
console.log(data);
});
UI Methods
ctx.ui.notify("Message", "info");
ctx.ui.setStatus("key", "value");
ctx.ui.custom((tui, theme, kb, done) => {
});
Tool Execute Signature
async execute(toolCallId, params, signal, onUpdate, ctx) { ... }
If ctx is undefined, check parameter order matches above.
Tips
- Keep it focused: One extension, one purpose
- Use events: React to session lifecycle
- Notify sparingly: Don't spam the user
- Handle errors: Wrap in try/catch
- Clean up: Use session_end for cleanup
- Check pi version: Tool signatures change between versions
Detailed References