> ## Documentation Index
> Fetch the complete documentation index at: https://docs.framework.vibeworkapp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Hooks

> Intercept and modify agent behavior at runtime

## Hook Events

```rust theme={null}
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

```rust theme={null}
// 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

```rust theme={null}
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
```

All hooks run (no short-circuit by default). If ANY returns Deny, final is Deny.

## Block Dangerous Commands

```rust theme={null}
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

```rust theme={null}
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

```rust theme={null}
hooks.add(HookEvent::PreToolUse, |ctx| {
    audit_log(ctx.tool_name, ctx.tool_input);
    HookResult::none()
})?;
```

## Auto-Approve Safe Tools

```rust theme={null}
hooks.add_with_pattern(HookEvent::PreToolUse, "Read|Glob|Grep", |_| {
    HookResult::allow()  // Skip permissions
})?;
```

## HookContext Fields

```rust theme={null}
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

```rust theme={null}
let config = AgentConfig::new("...")
    .with_hooks(hooks)
    .with_hook_short_circuit(true);  // Stop on first Deny
```

Default is false (all hooks run).

## Usage

```rust theme={null}
let config = AgentConfig::new("...")
    .with_hooks(Arc::new(hooks));
```
