Hook Events
use picrust::hooks::{HookRegistry, HookEvent, HookContext, HookResult};
let mut hooks = HookRegistry::new();
// PreToolUse - Before tool executes
hooks.add(HookEvent::PreToolUse, |ctx: &mut HookContext| {
HookResult::none()
})?;
// PostToolUse - After successful execution
hooks.add(HookEvent::PostToolUse, |ctx: &mut HookContext| {
HookResult::none()
})?;
// PostToolUseFailure - After tool fails
hooks.add(HookEvent::PostToolUseFailure, |ctx: &mut HookContext| {
HookResult::none()
})?;
// UserPromptSubmit - When user sends message
hooks.add(HookEvent::UserPromptSubmit, |ctx: &mut HookContext| {
HookResult::none()
})?;
// TurnComplete - After the full turn finishes (agent about to suspend)
hooks.add(HookEvent::TurnComplete, |ctx: &mut HookContext| {
HookResult::none()
})?;
Pattern Matching
// Match specific tools
hooks.add_with_pattern(HookEvent::PreToolUse, "Bash", |ctx| {
HookResult::none()
})?;
// Regex patterns
hooks.add_with_pattern(HookEvent::PreToolUse, "Write|Edit", |ctx| {
HookResult::none()
})?;
Hook Results
HookResult::allow() // Skip permission check, execute
HookResult::deny("reason") // Block execution
HookResult::ask() // Use normal permission flow
HookResult::none() // Continue normal flow
Result Priority
When multiple hooks return different results:Deny > Allow > Ask > None
Block Dangerous Commands
hooks.add_with_pattern(HookEvent::PreToolUse, "Bash", |ctx| {
let cmd = ctx.tool_input.as_ref()
.and_then(|v| v.get("command"))
.and_then(|v| v.as_str())
.unwrap_or("");
if cmd.contains("rm -rf /") || cmd.contains("sudo") {
return HookResult::deny("Blocked");
}
HookResult::none()
})?;
Modify Tool Input
hooks.add(HookEvent::PreToolUse, |ctx: &mut HookContext| {
if let Some(input) = ctx.tool_input.as_mut() {
if let Some(obj) = input.as_object_mut() {
obj.insert("modified".to_string(), json!(true));
}
}
HookResult::none()
})?;
Audit Logging
hooks.add(HookEvent::PreToolUse, |ctx| {
audit_log(ctx.tool_name, ctx.tool_input);
HookResult::none()
})?;
Auto-Approve Safe Tools
hooks.add_with_pattern(HookEvent::PreToolUse, "Read|Glob|Grep", |_| {
HookResult::allow() // Skip permissions
})?;
HookContext Fields
pub struct HookContext {
pub tool_name: Option<String>,
pub tool_input: Option<Value>,
pub tool_result: Option<ToolResult>,
pub user_prompt: Option<String>,
pub error: Option<String>,
}
Short-Circuit Mode
let config = AgentConfig::new("...")
.with_hooks(hooks)
.with_hook_short_circuit(true); // Stop on first Deny
Usage
let config = AgentConfig::new("...")
.with_hooks(Arc::new(hooks));