Pi — Hooks
- File format
- ts
- Discovery path
-
.pi/extensions - Global install path
-
~/.pi/agent/extensions - Syllago install method
- Symlink
- Symlink support
- Yes
- Config file
-
.pi/extensions/ - Handler types
-
command
Hook events
| Canonical Event | Native Name | Category |
|---|---|---|
after_tool_execute | tool_result | Tool |
agent_stop | agent_end | Lifecycle |
before_compact | session_before_compact | Context |
before_prompt | input | Lifecycle |
before_tool_execute | tool_call | Tool |
context_update | context | Context |
message_end | message_end | Model |
message_start | message_start | Model |
model_select | model_select | Model |
session_end | session_shutdown | Lifecycle |
session_start | session_start | Lifecycle |
subagent_start | before_agent_start | Lifecycle |
turn_end | turn_end | Model |
turn_start | turn_start | Model |
user_bash | user_bash | Tool |
Features
How each feature converts to syllago's canonical format. See format conversion for what these statuses mean.
Other features
Behaviors, conventions, and capabilities that aren't tied to a single named field — things like path-based activation, discovery rules, and lifecycle behavior.
| Feature | Conversion | Summary |
|---|---|---|
context_injection | Translated Conversion type: Translated Actively mapped to the target provider’s equivalent field during conversion. Learn more → | before_agent_start handlers return { message: { customType, content, display } } to inject a persistent message stored in session and sent to LLM; context handlers return { messages } to modify the message array before each LLM call |
decision_control | Translated Conversion type: Translated Actively mapped to the target provider’s equivalent field during conversion. Learn more → | tool_call handlers return { block: true, reason? } to prevent tool execution; tool_call errors also block the tool (fail-safe behavior) |
handler_types | Translated Conversion type: Translated Actively mapped to the target provider’s equivalent field during conversion. Learn more → | pi_extension_typescript_native: Pi hooks support TypeScript/native extension handler type beyond shell commands |
hook_scopes | Translated Conversion type: Translated Actively mapped to the target provider’s equivalent field during conversion. Learn more → | Extensions load from global scope (~/.pi/agent/extensions/) and project-local scope (.pi/extensions/); both scopes are auto-discovered and can be combined |
input_modification | Translated Conversion type: Translated Actively mapped to the target provider’s equivalent field during conversion. Learn more → | tool_call handlers mutate event.input in place to modify tool arguments before execution; later handlers see prior mutations |
| before_agent_start can inject messages and modify system prompt | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | before_agent_start handlers return { message, systemPrompt } to inject a persistent LLM-visible message and/or replace the chained system prompt for the turn. systemPromptOptions exposes the structured data Pi uses to build the system prompt. |
| Full TUI component access and UI primitives | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | ctx.ui exposes dialogs, status, widgets, header/footer replacement, custom TUI overlays with keyboard focus, theme management, editor text control, and custom editor components. |
| Hot reload with /reload command | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | Auto-discovered extensions support /reload hot reload; CLI-flag-loaded extensions do not, and resources_discover can also trigger reload. |
| registerCommand() adds slash commands | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | Extensions register custom slash commands via pi.registerCommand(); matched commands run before the agent and bypass the turn. |
| registerProvider() and unregisterProvider() for dynamic model provider management | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | Extensions can register or override model providers at runtime (baseUrl, apiKey, API type, models, OAuth) and unregister them. |
| registerTool() adds LLM-callable tools | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | Extensions register LLM-callable tools (name, label, description, TypeBox schema, execute) via pi.registerTool(); can override built-ins. New tools are immediately available to the LLM without /reload. |
| Rich lifecycle event model with 29 named event types | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | Extensions subscribe via pi.on() to 29 named events spanning resources, session, agent, turn, message, tool execution, tool call/result, model, thinking level, user bash, and input lifecycle phases. |
| setActiveTools() for runtime tool enable/disable | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | Extensions call pi.setActiveTools(names) to enable or disable tools (including dynamically added tools) at runtime. pi.getActiveTools() and pi.getAllTools() inspect the current tool set. |
| tool_call event can block or mutate tool execution | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | tool_call handlers can return { block: true, reason } or mutate event.input in place; later handlers see prior mutations. tool_call errors also block the tool (fail-safe). |
| tool_result handlers chain as middleware | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | tool_result handlers chain like middleware in load order, each seeing prior changes; partial patches keep omitted fields. |
| TypeScript-native extensions loaded via jiti | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | Extensions are TypeScript modules exporting a default factory; jiti loads them at runtime with no compilation step required. |
| user_bash event intercepts ! and !! commands | Not portable Conversion type: Not portable Unique to this provider — can’t be carried across providers. Learn more → | user_bash handlers can intercept user-executed shell commands (! prefix), provide custom BashOperations (e.g., SSH), or return a full replacement BashResult. |