*[Watch on YouTube](https://www.youtube.com/watch?v=Zamh36RWKz8&list=PLDzwjhH-4yhU&index=5)*

About this lesson

The videos in this course are a snapshot in time. Strands is under active development, so the code featured on this page reflects the most up-to-date patterns, but the concepts covered in the video still apply. When in doubt, trust the code.

*Code for this lesson: [`samples/05-hooks`](https://github.com/aws-samples/sample-building-with-strands-course/tree/main/samples/05-hooks)*

## Rules That Don’t Depend on the Model

Hooks inject code at lifecycle events (before/after tool calls, before/after the agent loop) without changing the agent’s logic. Unlike tools, which the model decides to use, hooks fire automatically every time regardless of what the model reasons. That’s the key distinction: a prompt is a request, a hook is a guarantee.

A runaway loop could call the same tool dozens of times. A model might attempt a destructive operation without asking. Prompting asks the model to behave. Hooks guarantee it.

## Hook Architecture

-   Subclass `HookProvider` to define hooks
-   Register callbacks for lifecycle events in `register_hooks()`
-   Multiple hooks can listen to the same event (stackable)
-   `event.interrupt()` pauses the loop for human input
-   `event.cancel_tool` blocks tool execution and feeds a message back to the model explaining why

## Example: Human Approval for Deletions

```python
from strands import Agent, tool
from strands.hooks import BeforeToolCallEvent, HookProvider, HookRegistry

class DeleteApprovalHook(HookProvider):
    """Intercepts delete operations for human approval."""

    def register_hooks(self, registry: HookRegistry) -> None:
        registry.add_callback(BeforeToolCallEvent, self.check_delete)

    def check_delete(self, event: BeforeToolCallEvent) -> None:
        if event.tool_use["name"] != "delete_file":
            return

        approval = event.interrupt(
            "delete-approval",
            reason={"path": event.tool_use["input"]["path"]}
        )

        if approval.lower() != "y":
            event.cancel_tool = "User denied file deletion"

agent = Agent(
    tools=[list_files, read_file, write_file, delete_file],
    hooks=[DeleteApprovalHook()],
)
```

📂 [approval\_interrupt.py](https://github.com/aws-samples/sample-building-with-strands-course/tree/main/samples/05-hooks/approval_interrupt.py)

`event.interrupt()` pauses agent execution and returns control to the caller. That’s what makes approval workflows possible: the agent doesn’t proceed until a human answers.

## Example: Rate Limiting Tool Calls

```python
from strands.hooks import BeforeInvocationEvent, BeforeToolCallEvent, HookProvider, HookRegistry

class LimitToolCounts(HookProvider):
    def __init__(self, max_calls: int = 3):
        self.max_calls = max_calls
        self.counts: dict[str, int] = {}

    def register_hooks(self, registry: HookRegistry) -> None:
        registry.add_callback(BeforeInvocationEvent, self.reset)
        registry.add_callback(BeforeToolCallEvent, self.check)

    def reset(self, event: BeforeInvocationEvent) -> None:
        self.counts = {}

    def check(self, event: BeforeToolCallEvent) -> None:
        name = event.tool_use["name"]
        self.counts[name] = self.counts.get(name, 0) + 1
        if self.counts[name] > self.max_calls:
            event.cancel_tool = (
                f"'{name}' hit the {self.max_calls}-call limit. "
                "Do NOT call this tool again."
            )

agent = Agent(tools=[get_weather], hooks=[LimitToolCounts(max_calls=3)])
```

📂 [rate\_limiter.py](https://github.com/aws-samples/sample-building-with-strands-course/tree/main/samples/05-hooks/rate_limiter.py)

Notice the counter resets on `BeforeInvocationEvent`. Rate limits are per request, not for the agent’s lifetime. And because `cancel_tool` sends a message back to the model, the model learns why the call was blocked and stops retrying.

## When to Use Hooks

-   Rate limit tool usage to prevent runaway loops
-   Require human approval before destructive operations
-   Log every tool call for audit trails
-   Validate tool inputs and outputs against business rules
-   Enforce access control on sensitive tools

Hooks don’t touch tools or prompts. They’re a separate, reusable layer you can drop onto any agent.

## Resources

-   📖 [Hooks](/pr-cms-4519/docs/user-guide/sdk/agents/hooks/index.md)
-   📖 [Lifecycle Controls](/pr-cms-4519/docs/user-guide/sdk/agents/lifecycle-controls/index.md)