"Attach to the loop, don't write into the loop" — hooks inject extension logic before and after tool execution.

Problem

After the previous three chapters, our Agent now has permission checks. But every time we add a new check, such as "log every bash call" or "automatically git add after operations," we have to modify the agent_loop function.

In other words, every time you do a check permission, the AI has to make a complex judgment, and it's still inside the loop — make it slightly longer and your code here will become enormous:

def agent_loop(messages):
    while True:
        # ... LLM call ...
        for block in response.content:
            if block.type != "tool_use":
                continue
            log_to_file(block)          # 加一行
            check_permission(block)     # 加一行
            notify_slack(block)         # 又加一行
            output = execute(block)
            auto_git_add(block)         # 再加一行
            # ... 很快循环就认不出来了

What you want to extend is the Agent's behavior, but what you're changing is the loop itself. The loop should be a stable core, and extensions should be attached on the outside.

Solution

Hooks — Attach to the Loop, Don't Write Into the Loop

We kept the previous loop and permission logic fully intact. The only change was moving check_permission() from inside the loop body onto a hook; the loop no longer directly calls any check function, but instead uses trigger_hooks("PreToolUse", block) , and the registry decides what runs.

What Is a Hook

Let me explain what a Hook is, otherwise this will be hard to understand. The original illustration above assumes everyone is a technical person, and therefore already understands the basic concept of a Hook.

First, let's talk about what a Hook actually is. Let's skip the jargon; in language a designer can understand: a Hook is a Slot with conditional requirements. The figure above introduces 2 hooks; the first is PreToolUse , meaning before a tool call. And the figure doesn't express this clearly — the check permission that was previously inside the loop has actually been placed here. In other words, the thing still exists; it was previously in the loop flow, and now it's installed in this Hook, which only triggers under the condition of before a tool call.

Hooks — Attach to the Loop, Don't Write Into the Loop