103 lines
3.7 KiB
Markdown
103 lines
3.7 KiB
Markdown
---
|
|
title: "Extensions"
|
|
task: ""
|
|
lineage_type: import
|
|
upstream_source: https://github.com/K-Dense-AI/scientific-agent-skills/blob/9c9bd2e9/skills/pi-agent/references/extensions.md
|
|
upstream_sha: 9c9bd2e9
|
|
imported_at: 2026-06-27
|
|
prompt_class: prompt
|
|
upstream_changes: accepted
|
|
author: upstream
|
|
validated: false
|
|
---
|
|
|
|
# Extensions
|
|
|
|
Source: https://pi.dev/docs/latest/extensions
|
|
|
|
Extensions are TypeScript modules that extend Pi. They can register tools, commands, shortcuts, flags, custom providers, UI, event handlers, and persistent session entries.
|
|
|
|
## Locations
|
|
|
|
- `~/.pi/agent/extensions/*.ts`
|
|
- `~/.pi/agent/extensions/*/index.ts`
|
|
- `.pi/extensions/*.ts`
|
|
- `.pi/extensions/*/index.ts`
|
|
- Paths from settings or packages
|
|
|
|
Project-local extensions load only after project trust. Use `pi -e ./my-extension.ts` for quick tests. Auto-discovered extensions can be hot-reloaded with `/reload`.
|
|
|
|
## Quick Extension
|
|
|
|
```ts
|
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
import { Type } from "typebox";
|
|
|
|
export default function (pi: ExtensionAPI) {
|
|
pi.on("session_start", async (_event, ctx) => {
|
|
ctx.ui.notify("Extension loaded", "info");
|
|
});
|
|
|
|
pi.on("tool_call", async (event, ctx) => {
|
|
if (event.toolName === "bash" && event.input.command?.includes("rm -rf")) {
|
|
const ok = await ctx.ui.confirm("Dangerous", "Allow rm -rf?");
|
|
if (!ok) return { block: true, reason: "Blocked by user" };
|
|
}
|
|
});
|
|
|
|
pi.registerTool({
|
|
name: "greet",
|
|
label: "Greet",
|
|
description: "Greet someone by name",
|
|
parameters: Type.Object({ name: Type.String() }),
|
|
async execute(_toolCallId, params) {
|
|
return { content: [{ type: "text", text: `Hello, ${params.name}!` }], details: {} };
|
|
},
|
|
});
|
|
|
|
pi.registerCommand("hello", {
|
|
description: "Say hello",
|
|
handler: async (args, ctx) => ctx.ui.notify(`Hello ${args || "world"}`, "info"),
|
|
});
|
|
}
|
|
```
|
|
|
|
## Imports
|
|
|
|
- `@earendil-works/pi-coding-agent`: extension types and APIs.
|
|
- `typebox`: schemas for tool parameters.
|
|
- `@earendil-works/pi-ai`: AI utilities.
|
|
- `@earendil-works/pi-tui`: TUI components.
|
|
|
|
Runtime dependencies for distributed packages belong in `dependencies`; package installs use production installs by default.
|
|
|
|
## Event Flow
|
|
|
|
Startup: `project_trust`, `session_start`, `resources_discover`.
|
|
|
|
Prompt: extension commands, `input`, skill/template expansion, `before_agent_start`, `agent_start`, message events, turn events, provider request/response hooks, tool events, `agent_end`.
|
|
|
|
Session changes: `session_before_switch`, `session_shutdown`, `session_start`, `resources_discover`. Fork/clone use `session_before_fork`.
|
|
|
|
Compaction/tree: `session_before_compact`, `session_compact`, `session_before_tree`, `session_tree`.
|
|
|
|
Model changes: `model_select`, `thinking_level_select`.
|
|
|
|
Shutdown: `session_shutdown`.
|
|
|
|
## High-Value Hooks
|
|
|
|
- `project_trust`: user/global or CLI extensions can decide project trust.
|
|
- `resources_discover`: contribute skill, prompt, and theme paths.
|
|
- `before_agent_start`: inject custom messages or modify the system prompt.
|
|
- `context`: non-destructively modify messages before each LLM call.
|
|
- `before_provider_request`: inspect/replace provider payload for debugging or compatibility.
|
|
- `after_provider_response`: inspect status/headers before streaming body is consumed.
|
|
- `tool_call`: block or mutate tool inputs before execution.
|
|
- `tool_result`: modify tool results.
|
|
- `message_end`: replace finalized message while preserving role.
|
|
|
|
## Runtime Notes
|
|
|
|
Extension factories may be async; Pi awaits them before startup continues. Use async factories for startup-only work such as dynamic model discovery. In RPC or JSON/print mode, guard TUI-specific UI with `ctx.mode === "tui"` and check `ctx.hasUI` before prompting.
|