Hook Registration
Hooks are registered usingpi.on() in your extension’s default export function:
Lifecycle Hooks
Session Lifecycle
session_start
Fired on initial session load.'session_start'
Event type
session_before_switch
Fired before switching to another session. Can cancel the operation.'session_before_switch'
Event type
'new' | 'resume'
Why the switch is happening
string | undefined
Target session file path
{ cancel?: boolean }
session_switch
Fired after switching to another session.'session_switch'
Event type
'new' | 'resume'
Why the switch happened
string | undefined
Previous session file path
session_shutdown
Fired on process exit. Useful for cleanup.'session_shutdown'
Event type
Agent Lifecycle
before_agent_start
Fired after user submits prompt but before agent loop starts. Can inject custom messages or modify system prompt.'before_agent_start'
Event type
string
User’s submitted prompt
ImageContent[] | undefined
Attached images, if any
string
Current system prompt
{ message?: CustomMessage; systemPrompt?: string }
agent_start
Fired when an agent loop starts.agent_end
Fired when an agent loop ends.'agent_end'
Event type
AgentMessage[]
All messages in the conversation
turn_start
Fired at the start of each turn (LLM request/response cycle).number
Zero-based turn index
number
Timestamp (milliseconds since epoch)
turn_end
Fired at the end of each turn.number
Zero-based turn index
AgentMessage
The assistant message from this turn
ToolResultMessage[]
Tool results from this turn
Message Hooks
message_start
Fired when a message starts (user, assistant, or toolResult).AgentMessage
The message that’s starting
message_update
Fired during assistant message streaming with token-by-token updates.AgentMessage
The message being updated
AssistantMessageEvent
Streaming event (text_delta, tool_call, thinking, etc.)
message_end
Fired when a message ends.AgentMessage
The completed message
Tool Hooks
tool_call
Fired before a tool executes. Can block execution.'tool_call'
Event type
string
Unique ID for this tool call
string
Name of the tool being called
Record<string, unknown>
Tool input parameters
{ block?: boolean; reason?: string }
tool_result
Fired after a tool executes. Can modify the result.'tool_result'
Event type
string
Unique ID for this tool call
string
Name of the tool
Record<string, unknown>
Tool input parameters
(TextContent | ImageContent)[]
Tool result content
unknown
Tool-specific details
boolean
Whether the tool execution failed
{ content?: Content[]; details?: unknown; isError?: boolean }
tool_execution_start
Fired when a tool starts executing.string
Unique ID for this tool call
string
Name of the tool
any
Tool arguments
tool_execution_update
Fired during tool execution with partial/streaming output.string
Unique ID for this tool call
string
Name of the tool
any
Tool arguments
any
Partial result from the tool
tool_execution_end
Fired when a tool finishes executing.string
Unique ID for this tool call
string
Name of the tool
any
Final result
boolean
Whether execution failed
Context Hooks
context
Fired before each LLM call. Can modify messages sent to the model.'context'
Event type
AgentMessage[]
Messages about to be sent to the LLM
{ messages?: AgentMessage[] }
Input Hooks
input
Fired when user input is received, before agent processing. Can transform or handle input.'input'
Event type
string
Input text
ImageContent[] | undefined
Attached images
'interactive' | 'rpc' | 'extension'
Where the input came from
{ action: 'continue' } | { action: 'transform'; text: string; images?: ImageContent[] } | { action: 'handled' }
user_bash
Fired when user executes a bash command via! or !! prefix.
'user_bash'
Event type
string
Command to execute
boolean
True if
!! prefix was used (excluded from LLM context)string
Current working directory
{ operations?: BashOperations; result?: BashResult }
Model Hooks
model_select
Fired when a new model is selected.'model_select'
Event type
Model<any>
New model
Model<any> | undefined
Previous model
'set' | 'cycle' | 'restore'
How the model was selected
Resource Hooks
resources_discover
Fired aftersession_start to allow extensions to provide additional resource paths.
'resources_discover'
Event type
string
Current working directory
'startup' | 'reload'
Why resources are being discovered
{ skillPaths?: string[]; promptPaths?: string[]; themePaths?: string[] }
Hook Patterns
Stateful Extensions
Usepi.appendEntry() to persist state across sessions:
Blocking Tool Execution
Usetool_call to implement safety checks: