Tool Hooks in the Claude Agent SDK

Intercept tool calls before and after they execute. Block sensitive file edits, build audit logs, and add guardrails that hold up in production without limiting what the agent can do for legitimate work.

6 min read
Claude Agent SDK hooks preToolUse hook agent hook SDK tool hook callback agent safety hooks

What hooks are

An agent does its work through tools. It reads files, edits code, runs shell commands, fetches web pages. By default, with bypass permissions mode enabled, it does all of this autonomously without checking in.

Hooks give you programmatic control over that behavior at the tool level.

A hook is a function that runs at a specific point in the agent's execution — before a tool fires, after it completes, at the start of a session, when a sub-agent finishes. You write the function, configure which tool it intercepts, and the SDK calls it automatically whenever the matching event occurs.

The practical use cases are broad: block file edits on sensitive paths, log every read operation for audit purposes, inject additional context before a specific tool call, deny dangerous commands before they execute. Hooks are how you make an agent trustworthy enough to deploy in real work environments.

> Hooks vs. permission mode. Permission mode controls which tools the agent can run at all. Hooks operate one level more specifically: they intercept individual tool calls and let you make decisions based on the actual input of that call. A hook can allow most edits but block any edit targeting a specific file. Permission mode alone cannot do that.

The hook event types

The SDK provides two categories of hooks:

Tool hooks — fire in response to specific tool calls.

  • preToolUse — runs before a tool executes. Can allow or deny the call.
  • postToolUse — runs after a tool executes. Cannot block it, but can log, react, or trigger follow-on behavior.

Lifecycle hooks — fire in response to agent-level events.

  • sessionStart — fires when a new session begins
  • subagentStop — fires when a sub-agent completes its turn
  • Additional lifecycle events are added to the SDK regularly; check the hooks reference in the Claude Agent SDK docs for the current list.

This guide focuses on tool hooks, which are the most immediately useful and the ones you will deploy most often.

How matchers work

Every hook needs a matcher. A matcher is a regular expression that tells the SDK which tools should trigger this hook.

If you want a hook to fire on the edit tool, the matcher is edit. If you want it to fire on either the edit or the write tool, the matcher is edit|write. The wildcard .* matches all tools.

Matchers are straightforward once you know the tool names. The SDK includes a complete list of built-in tool names. When you are building hooks and are unsure of the exact tool name for your use case, ask your coding agent — it can retrieve the type definitions and clarify which tool name to target.

Building a pre-tool use hook

Here is a concrete example: a hook that blocks any edit to a specific file.

import { query, type HookCallback, type PreToolUseHookInput } from "@anthropic-ai/claude-agent-sdk";

const blockSensitiveFile: HookCallback = async (input) => {
  const hookInput = input as PreToolUseHookInput;
  const filePath = hookInput.toolInput?.file_path ?? "";

  if (filePath.includes(".env")) {
    return {
      hookSpecificOutput: {
        hookEventName: "preToolUse",
        permissionDecision: "deny",
        permissionDecisionReason: "Editing .env files is not permitted.",
      },
    };
  }

  return {};
};

for await (const message of query(
  "Read config.ts and add a comment explaining what it does.",
  {
    model: "claude-sonnet-4-5",
    permissionMode: "bypassPermissions",
    dangerouslyAllowBypassPermissions: true,
    hooks: {
      preToolUse: [
        {
          matcher: "edit",
          hooks: [blockSensitiveFile],
        },
      ],
    },
  }
)) {
  if (message.type === "assistant" && message.content[0]?.type === "text") {
    console.log(message.content[0].text);
  }
}

What this does. Before every edit tool call, the blockSensitiveFile function runs. It checks the file path the agent is about to edit. If the path includes .env, it returns a deny decision with a reason. The agent receives the denial, stops the edit, and reports that the operation was blocked.

For any other file, the function returns an empty object. An empty return tells the SDK to proceed as normal — no intervention.

The types matter here. The HookCallback type gives your function the correct signature. The PreToolUseHookInput type gives you access to the structured input for pre-tool-use events, which includes the file path, tool name, and other properties depending on the tool. Typing these correctly is what makes it easy for a coding agent to write your hooks for you — it can read the type definitions and know exactly what properties are available.

Building a post-tool use hook

Post-tool-use hooks cannot block operations, but they are useful for logging and audit trails.

import { query, type HookCallback, type PostToolUseHookInput } from "@anthropic-ai/claude-agent-sdk";

const logFileReads: HookCallback = async (input) => {
  const hookInput = input as PostToolUseHookInput;
  const filePath = hookInput.toolInput?.file_path ?? "unknown";
  console.log(`[AUDIT] Read: ${filePath}`);
  return {};
};

for await (const message of query(
  "Read the project files and summarize the structure.",
  {
    model: "claude-sonnet-4-5",
    permissionMode: "bypassPermissions",
    dangerouslyAllowBypassPermissions: true,
    hooks: {
      postToolUse: [
        {
          matcher: "read",
          hooks: [logFileReads],
        },
      ],
    },
  }
)) {
  // process messages
}

Every time the read tool completes, the audit log entry fires. If you are building agents that access sensitive client documents, this pattern gives you a record of every file the agent touched during the session.

Combining multiple hooks

You can configure pre-tool-use and post-tool-use hooks simultaneously in the same agent. Each hook category accepts an array, so you can stack multiple matchers and multiple functions within the same agent run.

hooks: {
  preToolUse: [
    { matcher: "edit", hooks: [blockSensitiveFile] },
    { matcher: "bash", hooks: [blockDangerousCommands] },
  ],
  postToolUse: [
    { matcher: "read", hooks: [logFileReads] },
  ],
},

The execution order within each category is the order of the array. Pre-tool-use hooks run before permission mode is checked. If a hook denies a tool call, permission mode never gets evaluated for that call.

> Use hooks to protect .env files. The most common real-world use of preToolUse hooks in production agents is blocking any read or edit of environment files. Agents running with bypass permissions mode have broad access by default. A two-line hook that checks for .env in the file path and returns a deny decision is cheap insurance that prevents accidental credential exposure.

When to reach for hooks

Hooks add a layer of specificity that permission modes cannot provide alone. Reach for them when:

  • You want bypass permissions mode for speed but need to protect specific files or paths
  • You need an audit log of tool usage for compliance or debugging
  • You want to intercept a tool call and inject additional context before it runs
  • You are building an agent that others will use and you need guardrails that hold up regardless of how the agent is prompted

For personal-use agents handling non-sensitive work, permission modes alone may be sufficient. For agents handling client data, deployed to shared environments, or running autonomously on a schedule, hooks are the right tool.

---

Author: FractionalSkill

Keep Going

Ready to Start Building?

Pick the next step that matches where you are right now.

Tutorial
Claude Code Basics

Start with the terminal basics. A hands-on, step-by-step guide to your first 10 minutes with Claude Code.

Start the Tutorial
Guide
AI-Powered Workflows

Automate your client work. Learn how to connect AI tools into workflows that handle repetitive tasks for you.

Read the Guide
Community
Join the Community

Connect with other fractional leaders building with AI. Share workflows, get feedback, and learn from operators who are ahead of you.

Apply to Join