HomeClaude Code › Hooks
OverviewInstallCLI referencePricing & limitsAgent SDKSkills & pluginsGitHubWeb, desktop & IDEModelsErrorsOpen source?TutorialFor studentsQA automationvs Cursorvs Codex & OpenCodeSubagentsHooksMCPEcosystem中文指南
Last updated: September 22, 2026

Claude Code hooks: deterministic control over what the agent does

Hooks are shell commands Claude Code runs at fixed points in its loop — before a tool call, after one, when you submit a prompt, when it finishes. Unlike instructions in CLAUDE.md, which the model may or may not follow, a hook always runs. They are how you make rules that hold.

TLDR

  • Configured in .claude/settings.json (project) or ~/.claude/settings.json (user), or with /hooks.
  • Events: PreToolUse, PostToolUse, UserPromptSubmit, Notification, Stop, SubagentStop, PreCompact, SessionStart.
  • The hook gets JSON on stdin (tool name, input, session); exit 0 allows, exit 2 blocks and feeds stderr back to Claude.
  • Typical uses: format after every edit, block dangerous commands, require tests before stop, desktop notifications.

Anatomy of a hook

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "npx prettier --write \"$(jq -r .tool_input.file_path)\"" }
        ]
      }
    ]
  }
}

Three parts: the event, a matcher (a regex on the tool name for tool events; omit it to match everything), and one or more commands. The command receives a JSON object on stdin describing the event — for tool events that includes tool_name and tool_input, which is how the example above finds the file that was just edited. Put it in .claude/settings.json to share with the repo, ~/.claude/settings.json for yourself, or run /hooks and let Claude Code write it.

The events

Blocking dangerous commands

#!/usr/bin/env bash
# .claude/hooks/guard.sh  -- PreToolUse, matcher: Bash
cmd=$(jq -r '.tool_input.command')
if echo "$cmd" | grep -Eq 'rm -rf|git push --force|DROP TABLE|--no-verify'; then
  echo "blocked by guard.sh: $cmd" >&2
  exit 2
fi
exit 0

Exit code 2 is the contract: the tool call does not happen, and whatever the hook printed to stderr becomes the explanation Claude sees, so it can choose a different approach instead of retrying the same thing. Any other non-zero exit is logged but does not block.

"Do not stop until the tests pass"

#!/usr/bin/env bash
# Stop hook: refuse to finish while the suite is red
if ! npm test --silent >/tmp/claude-test.log 2>&1; then
  echo "Tests are failing; fix them before finishing:" >&2
  tail -n 40 /tmp/claude-test.log >&2
  exit 2
fi

Pair it with a --max-turns cap in headless runs so a genuinely unfixable failure does not loop forever.

Hooks vs CLAUDE.md vs permissions

CLAUDE.md is advice the model reads; /permissions is a list of what it may do without asking; hooks are code that runs regardless. Use CLAUDE.md for style and context, permissions for the allow/ask boundary, and hooks for anything that must be true every time — formatting, secrets scanning, test gates, audit logs. They compose: a permission lets Bash(git *) run, a PreToolUse hook still blocks git push --force.

Hooks and the gateway

Hooks run locally and never touch the API, so nothing changes when Claude Code points at ANTHROPIC_BASE_URL=https://aiprimetech.io. One useful combination: a Stop hook that prints /cost-style usage from your own logs, so a team on pay-as-you-go credits sees the price of every session as it ends.

Frequently asked questions

What are Claude Code hooks?

Shell commands that Claude Code runs automatically at events in its loop — before/after tool calls, on prompt submit, on stop. They are deterministic, unlike instructions in CLAUDE.md.

How do I block a command with a hook?

A PreToolUse hook with matcher Bash that inspects tool_input.command from stdin and exits with code 2; the stderr text is shown to Claude as the reason.

Where do hooks go?

.claude/settings.json in the project (shared) or ~/.claude/settings.json (personal), under the hooks key; /hooks edits them interactively.

Run Claude Code on the gateway

Same models, two environment variables, credits at 7.69× face value — or a flat-rate unlimited plan.

Get an API key See unlimited plans

AI Prime Tech is an independent API gateway and is not affiliated with, endorsed by, or sponsored by Anthropic. “Claude” and “Claude Code” are trademarks of Anthropic. Claude Code features described here follow Anthropic’s public documentation at the time of writing and change frequently; prices and model lists on this page are read from this gateway’s live settings.

More Claude Code guides

Claude Code: the complete guideHow to install Claude CodeClaude Code CLI documentation: commands and flagsClaude Code pricing and limits, explainedThe Claude Code SDK, now the Claude Agent SDKClaude Code skills and pluginsClaude Code in GitHub: the App, the Action and @claudeDoes Claude Code have a web interface? Web, desktop and IDE explainedWhich model Claude Code uses, and how to change itClaude Code errors and how to fix themIs Claude Code open source?Claude Code tutorial: your first real sessionClaude Code for studentsHow to use Claude Code for QA automationClaude Code vs Cursor: which one, when — and how to run bothClaude Code vs Codex vs OpenCode: the terminal agents comparedClaude Code subagents: how they work, how to define them, and agent teamsClaude Code MCP: connecting servers, scopes, remote MCP and real examplesThe Claude Code ecosystem: routers, frameworks, plugins and the lists that track themClaude Code 怎么用:从安装到日常使用