Для руководства по быстрому старту с примерами см. Начало работы с хуками Claude Code.

Конфигурация

Хуки Claude Code настраиваются в ваших файлах настроек:

  • ~/.claude/settings.json - Пользовательские настройки
  • .claude/settings.json - Настройки проекта
  • .claude/settings.local.json - Локальные настройки проекта (не коммитятся)
  • Корпоративные управляемые настройки политики

Структура

Хуки организованы по матчерам, где каждый матчер может иметь несколько хуков:

{
  "hooks": {
    "EventName": [
      {
        "matcher": "ToolPattern",
        "hooks": [
          {
            "type": "command",
            "command": "your-command-here"
          }
        ]
      }
    ]
  }
}
  • matcher: Шаблон для сопоставления имен инструментов, чувствительный к регистру (применимо только для PreToolUse и PostToolUse)
    • Простые строки совпадают точно: Write совпадает только с инструментом Write
    • Поддерживает regex: Edit|Write или Notebook.*
    • Используйте * для сопоставления всех инструментов. Вы также можете использовать пустую строку ("") или оставить matcher пустым.
  • hooks: Массив команд для выполнения при совпадении шаблона
    • type: В настоящее время поддерживается только "command"
    • command: Bash-команда для выполнения (может использовать переменную окружения $CLAUDE_PROJECT_DIR)
    • timeout: (Опционально) Как долго команда должна выполняться, в секундах, перед отменой этой конкретной команды.

Для событий типа UserPromptSubmit, Notification, Stop и SubagentStop, которые не используют матчеры, вы можете опустить поле matcher:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/prompt-validator.py"
          }
        ]
      }
    ]
  }
}

Скрипты хуков для конкретного проекта

Вы можете использовать переменную окружения CLAUDE_PROJECT_DIR (доступна только когда Claude Code запускает команду хука) для ссылки на скрипты, хранящиеся в вашем проекте, обеспечивая их работу независимо от текущего каталога Claude:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-style.sh"
          }
        ]
      }
    ]
  }
}

События хуков

PreToolUse

Выполняется после того, как Claude создает параметры инструмента и перед обработкой вызова инструмента.

Общие матчеры:

  • Task - Задачи субагентов (см. документацию по субагентам)
  • Bash - Команды оболочки
  • Glob - Сопоставление шаблонов файлов
  • Grep - Поиск содержимого
  • Read - Чтение файлов
  • Edit, MultiEdit - Редактирование файлов
  • Write - Запись файлов
  • WebFetch, WebSearch - Веб-операции

PostToolUse

Выполняется сразу после успешного завершения инструмента.

Распознает те же значения матчеров, что и PreToolUse.

Notification

Выполняется, когда Claude Code отправляет уведомления. Уведомления отправляются когда:

  1. Claude нужно ваше разрешение на использование инструмента. Пример: “Claude нужно ваше разрешение на использование Bash”
  2. Ввод промпта бездействует не менее 60 секунд. “Claude ждет вашего ввода”

UserPromptSubmit

Выполняется, когда пользователь отправляет промпт, перед тем как Claude его обработает. Это позволяет вам добавить дополнительный контекст на основе промпта/разговора, валидировать промпты или блокировать определенные типы промптов.

Stop

Выполняется, когда основной агент Claude Code завершил ответ. Не выполняется, если остановка произошла из-за прерывания пользователем.

SubagentStop

Выполняется, когда субагент Claude Code (вызов инструмента Task) завершил ответ.

SessionEnd

Выполняется, когда сессия Claude Code завершается. Полезно для задач очистки, логирования статистики сессии или сохранения состояния сессии.

Поле reason во входных данных хука будет одним из:

  • clear - Сессия очищена командой /clear
  • logout - Пользователь вышел из системы
  • prompt_input_exit - Пользователь вышел, пока был виден ввод промпта
  • other - Другие причины выхода

PreCompact

Выполняется перед тем, как Claude Code собирается выполнить операцию компактирования.

Матчеры:

  • manual - Вызван из /compact
  • auto - Вызван из авто-компактирования (из-за полного окна контекста)

SessionStart

Выполняется, когда Claude Code начинает новую сессию или возобновляет существующую сессию (что в настоящее время запускает новую сессию под капотом). Полезно для загрузки контекста разработки, такого как существующие проблемы или недавние изменения в вашей кодовой базе.

Матчеры:

  • startup - Вызван при запуске
  • resume - Вызван из --resume, --continue или /resume
  • clear - Вызван из /clear

Входные данные хука

Хуки получают JSON-данные через stdin, содержащие информацию о сессии и данные, специфичные для события:

{
  // Общие поля
  session_id: string
  transcript_path: string  // Путь к JSON разговора
  cwd: string              // Текущий рабочий каталог при вызове хука

  // Поля, специфичные для события
  hook_event_name: string
  ...
}

Входные данные PreToolUse

Точная схема для tool_input зависит от инструмента.

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "PreToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  }
}

Входные данные PostToolUse

Точная схема для tool_input и tool_response зависит от инструмента.

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "PostToolUse",
  "tool_name": "Write",
  "tool_input": {
    "file_path": "/path/to/file.txt",
    "content": "file content"
  },
  "tool_response": {
    "filePath": "/path/to/file.txt",
    "success": true
  }
}

Входные данные Notification

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "Notification",
  "message": "Task completed successfully"
}

Входные данные UserPromptSubmit

{
  "session_id": "abc123",
  "transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "UserPromptSubmit",
  "prompt": "Write a function to calculate the factorial of a number"
}

Входные данные Stop и SubagentStop

stop_hook_active равно true, когда Claude Code уже продолжает работу в результате хука остановки. Проверьте это значение или обработайте транскрипт, чтобы предотвратить бесконечную работу Claude Code.

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "Stop",
  "stop_hook_active": true
}

Входные данные PreCompact

Для manual, custom_instructions берется из того, что пользователь передает в /compact. Для auto, custom_instructions пустые.

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "PreCompact",
  "trigger": "manual",
  "custom_instructions": ""
}

Входные данные SessionStart

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "hook_event_name": "SessionStart",
  "source": "startup"
}

Входные данные SessionEnd

{
  "session_id": "abc123",
  "transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
  "cwd": "/Users/...",
  "hook_event_name": "SessionEnd",
  "reason": "exit"
}

Выходные данные хука

Есть два способа для хуков вернуть выходные данные обратно в Claude Code. Выходные данные сообщают, следует ли блокировать, и любую обратную связь, которая должна быть показана Claude и пользователю.

Простой: Код выхода

Хуки сообщают статус через коды выхода, stdout и stderr:

  • Код выхода 0: Успех. stdout показывается пользователю в режиме транскрипта (CTRL-R), за исключением UserPromptSubmit и SessionStart, где stdout добавляется в контекст.
  • Код выхода 2: Блокирующая ошибка. stderr передается обратно Claude для автоматической обработки. См. поведение для каждого события хука ниже.
  • Другие коды выхода: Неблокирующая ошибка. stderr показывается пользователю и выполнение продолжается.

Напоминание: Claude Code не видит stdout, если код выхода равен 0, за исключением хука UserPromptSubmit, где stdout вводится как контекст.

Поведение кода выхода 2

Событие хукаПоведение
PreToolUseБлокирует вызов инструмента, показывает stderr Claude
PostToolUseПоказывает stderr Claude (инструмент уже выполнился)
NotificationН/Д, показывает stderr только пользователю
UserPromptSubmitБлокирует обработку промпта, стирает промпт, показывает stderr только пользователю
StopБлокирует остановку, показывает stderr Claude
SubagentStopБлокирует остановку, показывает stderr субагенту Claude
PreCompactН/Д, показывает stderr только пользователю
SessionStartН/Д, показывает stderr только пользователю
SessionEndН/Д, показывает stderr только пользователю

Продвинутый: JSON-вывод

Хуки могут возвращать структурированный JSON в stdout для более сложного контроля:

Общие поля JSON

Все типы хуков могут включать эти опциональные поля:

{
  "continue": true, // Должен ли Claude продолжить после выполнения хука (по умолчанию: true)
  "stopReason": "string", // Сообщение, показываемое когда continue равно false

  "suppressOutput": true, // Скрыть stdout из режима транскрипта (по умолчанию: false)
  "systemMessage": "string" // Опциональное предупреждающее сообщение, показываемое пользователю
}

Если continue равно false, Claude прекращает обработку после выполнения хуков.

  • Для PreToolUse, это отличается от "permissionDecision": "deny", которое только блокирует конкретный вызов инструмента и предоставляет автоматическую обратную связь Claude.
  • Для PostToolUse, это отличается от "decision": "block", которое предоставляет автоматизированную обратную связь Claude.
  • Для UserPromptSubmit, это предотвращает обработку промпта.
  • Для Stop и SubagentStop, это имеет приоритет над любым выводом "decision": "block".
  • Во всех случаях, "continue" = false имеет приоритет над любым выводом "decision": "block".

stopReason сопровождает continue с причиной, показываемой пользователю, не показываемой Claude.

Контроль решений PreToolUse

Хуки PreToolUse могут контролировать, продолжается ли вызов инструмента.

  • "allow" обходит систему разрешений. permissionDecisionReason показывается пользователю, но не Claude.
  • "deny" предотвращает выполнение вызова инструмента. permissionDecisionReason показывается Claude.
  • "ask" просит пользователя подтвердить вызов инструмента в UI. permissionDecisionReason показывается пользователю, но не Claude.
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow" | "deny" | "ask",
    "permissionDecisionReason": "My reason here"
  }
}

Поля decision и reason устарели для хуков PreToolUse. Используйте hookSpecificOutput.permissionDecision и hookSpecificOutput.permissionDecisionReason вместо них. Устаревшие поля "approve" и "block" соответствуют "allow" и "deny" соответственно.

Контроль решений PostToolUse

Хуки PostToolUse могут предоставлять обратную связь Claude после выполнения инструмента.

  • "block" автоматически подсказывает Claude с reason.
  • undefined ничего не делает. reason игнорируется.
  • "hookSpecificOutput.additionalContext" добавляет контекст для рассмотрения Claude.
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "PostToolUse",
    "additionalContext": "Additional information for Claude"
  }
}

Контроль решений UserPromptSubmit

Хуки UserPromptSubmit могут контролировать, обрабатывается ли пользовательский промпт.

  • "block" предотвращает обработку промпта. Отправленный промпт стирается из контекста. "reason" показывается пользователю, но не добавляется в контекст.
  • undefined позволяет промпту продолжиться нормально. "reason" игнорируется.
  • "hookSpecificOutput.additionalContext" добавляет строку в контекст, если не заблокировано.
{
  "decision": "block" | undefined,
  "reason": "Explanation for decision",
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "My additional context here"
  }
}

Контроль решений Stop/SubagentStop

Хуки Stop и SubagentStop могут контролировать, должен ли Claude продолжить.

  • "block" предотвращает остановку Claude. Вы должны заполнить reason, чтобы Claude знал, как продолжить.
  • undefined позволяет Claude остановиться. reason игнорируется.
{
  "decision": "block" | undefined,
  "reason": "Must be provided when Claude is blocked from stopping"
}

Контроль решений SessionStart

Хуки SessionStart позволяют вам загружать контекст в начале сессии.

  • "hookSpecificOutput.additionalContext" добавляет строку в контекст.
  • Значения additionalContext нескольких хуков объединяются.
{
  "hookSpecificOutput": {
    "hookEventName": "SessionStart",
    "additionalContext": "My additional context here"
  }
}

Контроль решений SessionEnd

Хуки SessionEnd выполняются при завершении сессии. Они не могут блокировать завершение сессии, но могут выполнять задачи очистки.

Пример кода выхода: Валидация команд Bash

#!/usr/bin/env python3
import json
import re
import sys

# Определить правила валидации как список кортежей (regex pattern, message)
VALIDATION_RULES = [
    (
        r"\bgrep\b(?!.*\|)",
        "Use 'rg' (ripgrep) instead of 'grep' for better performance and features",
    ),
    (
        r"\bfind\s+\S+\s+-name\b",
        "Use 'rg --files | rg pattern' or 'rg --files -g pattern' instead of 'find -name' for better performance",
    ),
]


def validate_command(command: str) -> list[str]:
    issues = []
    for pattern, message in VALIDATION_RULES:
        if re.search(pattern, command):
            issues.append(message)
    return issues


try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")

if tool_name != "Bash" or not command:
    sys.exit(1)

# Валидировать команду
issues = validate_command(command)

if issues:
    for message in issues:
        print(f"• {message}", file=sys.stderr)
    # Код выхода 2 блокирует вызов инструмента и показывает stderr Claude
    sys.exit(2)

Пример JSON-вывода: UserPromptSubmit для добавления контекста и валидации

Для хуков UserPromptSubmit, вы можете внедрить контекст любым из методов:

  • Код выхода 0 с stdout: Claude видит контекст (особый случай для UserPromptSubmit)
  • JSON-вывод: Предоставляет больше контроля над поведением
#!/usr/bin/env python3
import json
import sys
import re
import datetime

# Загрузить входные данные из stdin
try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

prompt = input_data.get("prompt", "")

# Проверить на чувствительные шаблоны
sensitive_patterns = [
    (r"(?i)\b(password|secret|key|token)\s*[:=]", "Prompt contains potential secrets"),
]

for pattern, message in sensitive_patterns:
    if re.search(pattern, prompt):
        # Использовать JSON-вывод для блокировки с конкретной причиной
        output = {
            "decision": "block",
            "reason": f"Security policy violation: {message}. Please rephrase your request without sensitive information."
        }
        print(json.dumps(output))
        sys.exit(0)

# Добавить текущее время в контекст
context = f"Current time: {datetime.datetime.now()}"
print(context)

"""
Следующее также эквивалентно:
print(json.dumps({
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": context,
  },
}))
"""

# Позволить промпту продолжиться с дополнительным контекстом
sys.exit(0)

Пример JSON-вывода: PreToolUse с одобрением

#!/usr/bin/env python3
import json
import sys

# Загрузить входные данные из stdin
try:
    input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
    print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
    sys.exit(1)

tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})

# Пример: Авто-одобрение чтения файлов для файлов документации
if tool_name == "Read":
    file_path = tool_input.get("file_path", "")
    if file_path.endswith((".md", ".mdx", ".txt", ".json")):
        # Использовать JSON-вывод для авто-одобрения вызова инструмента
        output = {
            "decision": "approve",
            "reason": "Documentation file auto-approved",
            "suppressOutput": True  # Не показывать в режиме транскрипта
        }
        print(json.dumps(output))
        sys.exit(0)

# Для других случаев, позволить нормальному потоку разрешений продолжиться
sys.exit(0)

Работа с инструментами MCP

Хуки Claude Code работают бесшовно с инструментами Model Context Protocol (MCP). Когда MCP-серверы предоставляют инструменты, они появляются со специальным шаблоном именования, который вы можете сопоставить в ваших хуках.

Именование инструментов MCP

Инструменты MCP следуют шаблону mcp__<server>__<tool>, например:

  • mcp__memory__create_entities - Инструмент создания сущностей сервера памяти
  • mcp__filesystem__read_file - Инструмент чтения файлов файловой системы
  • mcp__github__search_repositories - Инструмент поиска сервера GitHub

Настройка хуков для инструментов MCP

Вы можете нацеливаться на конкретные инструменты MCP или целые MCP-серверы:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "mcp__memory__.*",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
          }
        ]
      },
      {
        "matcher": "mcp__.*__write.*",
        "hooks": [
          {
            "type": "command",
            "command": "/home/user/scripts/validate-mcp-write.py"
          }
        ]
      }
    ]
  }
}

Примеры

Для практических примеров, включая форматирование кода, уведомления и защиту файлов, см. Больше примеров в руководстве по началу работы.

Соображения безопасности

Отказ от ответственности

ИСПОЛЬЗУЙТЕ НА СВОЙ РИСК: Хуки Claude Code выполняют произвольные команды оболочки в вашей системе автоматически. Используя хуки, вы признаете, что:

  • Вы несете единоличную ответственность за команды, которые вы настраиваете
  • Хуки могут изменять, удалять или получать доступ к любым файлам, к которым может получить доступ ваша учетная запись пользователя
  • Вредоносные или плохо написанные хуки могут вызвать потерю данных или повреждение системы
  • Anthropic не предоставляет гарантий и не несет ответственности за любой ущерб, возникший в результате использования хуков
  • Вы должны тщательно тестировать хуки в безопасной среде перед использованием в продакшене

Всегда просматривайте и понимайте любые команды хуков перед добавлением их в вашу конфигурацию.

Лучшие практики безопасности

Вот некоторые ключевые практики для написания более безопасных хуков:

  1. Валидируйте и очищайте входные данные - Никогда не доверяйте входным данным слепо
  2. Всегда заключайте переменные оболочки в кавычки - Используйте "$VAR", а не $VAR
  3. Блокируйте обход пути - Проверяйте на .. в путях файлов
  4. Используйте абсолютные пути - Указывайте полные пути для скриптов (используйте $CLAUDE_PROJECT_DIR для пути проекта)
  5. Пропускайте чувствительные файлы - Избегайте .env, .git/, ключей и т.д.

Безопасность конфигурации

Прямые изменения хуков в файлах настроек не вступают в силу немедленно. Claude Code:

  1. Захватывает снимок хуков при запуске
  2. Использует этот снимок на протяжении всей сессии
  3. Предупреждает, если хуки изменены извне
  4. Требует просмотра в меню /hooks для применения изменений

Это предотвращает влияние вредоносных изменений хуков на вашу текущую сессию.

Детали выполнения хуков

  • Таймаут: 60-секундный лимит выполнения по умолчанию, настраивается для каждой команды.
    • Таймаут для отдельной команды не влияет на другие команды.
  • Параллелизация: Все совпадающие хуки выполняются параллельно
  • Дедупликация: Несколько идентичных команд хуков автоматически дедуплицируются
  • Окружение: Выполняется в текущем каталоге с окружением Claude Code
    • Переменная окружения CLAUDE_PROJECT_DIR доступна и содержит абсолютный путь к корневому каталогу проекта (где был запущен Claude Code)
  • Входные данные: JSON через stdin
  • Выходные данные:
    • PreToolUse/PostToolUse/Stop/SubagentStop: Прогресс показывается в транскрипте (Ctrl-R)
    • Notification/SessionEnd: Логируется только в отладке (--debug)
    • UserPromptSubmit/SessionStart: stdout добавляется как контекст для Claude

Отладка

Базовое устранение неполадок

Если ваши хуки не работают:

  1. Проверьте конфигурацию - Запустите /hooks, чтобы увидеть, зарегистрирован ли ваш хук
  2. Проверьте синтаксис - Убедитесь, что ваши JSON-настройки валидны
  3. Тестируйте команды - Сначала запустите команды хуков вручную
  4. Проверьте разрешения - Убедитесь, что скрипты исполняемы
  5. Просмотрите логи - Используйте claude --debug, чтобы увидеть детали выполнения хуков

Общие проблемы:

  • Кавычки не экранированы - Используйте \" внутри JSON-строк
  • Неправильный матчер - Проверьте, что имена инструментов совпадают точно (чувствительно к регистру)
  • Команда не найдена - Используйте полные пути для скриптов

Продвинутая отладка

Для сложных проблем с хуками:

  1. Инспектируйте выполнение хуков - Используйте claude --debug, чтобы увидеть подробное выполнение хуков
  2. Валидируйте JSON-схемы - Тестируйте входные/выходные данные хуков с внешними инструментами
  3. Проверьте переменные окружения - Убедитесь, что окружение Claude Code корректно
  4. Тестируйте крайние случаи - Попробуйте хуки с необычными путями файлов или входными данными
  5. Мониторьте системные ресурсы - Проверьте на истощение ресурсов во время выполнения хуков
  6. Используйте структурированное логирование - Реализуйте логирование в ваших скриптах хуков

Пример отладочного вывода

Используйте claude --debug, чтобы увидеть детали выполнения хуков:

[DEBUG] Executing hooks for PostToolUse:Write
[DEBUG] Getting matching hook commands for PostToolUse with query: Write
[DEBUG] Found 1 hook matchers in settings
[DEBUG] Matched 1 hooks for query "Write"
[DEBUG] Found 1 hook commands to execute
[DEBUG] Executing hook command: <Your command> with timeout 60000ms
[DEBUG] Hook command completed with status 0: <Your stdout>

Сообщения о прогрессе появляются в режиме транскрипта (Ctrl-R), показывая:

  • Какой хук выполняется
  • Выполняемая команда
  • Статус успеха/неудачи
  • Выходные данные или сообщения об ошибках