Skip to contentllms.txt

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 EventNative NameCategory
after_tool_executetool_resultTool
agent_stopagent_endLifecycle
before_compactsession_before_compactContext
before_promptinputLifecycle
before_tool_executetool_callTool
context_updatecontextContext
message_endmessage_endModel
message_startmessage_startModel
model_selectmodel_selectModel
session_endsession_shutdownLifecycle
session_startsession_startLifecycle
subagent_startbefore_agent_startLifecycle
turn_endturn_endModel
turn_startturn_startModel
user_bashuser_bashTool

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.

FeatureConversionSummary
context_injectionTranslatedConversion type: TranslatedActively 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_controlTranslatedConversion type: TranslatedActively 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_typesTranslatedConversion type: TranslatedActively 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_scopesTranslatedConversion type: TranslatedActively 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_modificationTranslatedConversion type: TranslatedActively 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 promptNot portableConversion type: Not portableUnique 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 primitivesNot portableConversion type: Not portableUnique 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 commandNot portableConversion type: Not portableUnique 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 commandsNot portableConversion type: Not portableUnique 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 managementNot portableConversion type: Not portableUnique 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 toolsNot portableConversion type: Not portableUnique 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 typesNot portableConversion type: Not portableUnique 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/disableNot portableConversion type: Not portableUnique 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 executionNot portableConversion type: Not portableUnique 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 middlewareNot portableConversion type: Not portableUnique 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 jitiNot portableConversion type: Not portableUnique 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 !! commandsNot portableConversion type: Not portableUnique 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.

Sources

Source
https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/core/extensions/types.ts
https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/docs/extensions.md
https://raw.githubusercontent.com/badlogic/pi-mono/main/packages/coding-agent/src/core/extensions/runner.ts