Хуки Claude Code: практическое руководство

Как работают хуки Claude Code: события, settings.json, matcher, коды выхода и JSON-ответ, плюс готовые хуки для форматирования, блокировки опасных команд и уведомлений.

Solviera Teknoloji 9 мин чтения

Хуки Claude Code — это команды, которые Claude Code сам запускает в фиксированные моменты сессии: перед вызовом инструмента, после правки файла, при отправке промпта, когда Claude останавливается или ему нужно ваше внимание. Они описываются под ключом hooks в settings.json. Хук может добавить контекст, отформатировать файл или заблокировать действие, завершившись с кодом 2 или вернув JSON-решение. В отличие от инструкций в CLAUDE.md, хук срабатывает всегда, потому что его запускает среда выполнения, а не модель.

В этом руководстве: важные события, формат конфигурации, matcher, коды выхода и JSON-ответ, три хука, которые можно скопировать сегодня, и замечания по безопасности, которые стоит прочитать до добавления любого хука. Факты взяты из официального справочника по хукам и руководства по хукам. Если нужно только короткое определение, см. статью глоссария о хуках Claude Code.

Зачем нужны хуки, если есть инструкции

В CLAUDE.md можно написать «всегда запускай Prettier после правок», и Claude обычно так и сделает. «Обычно» — вот в чём проблема. Инструкции — это совет, который модель взвешивает вместе со всем остальным в своём контексте. Хуки — это код, который выполняется каждый раз, когда срабатывает событие.

Поэтому хуки подходят для трёх видов правил:

  • То, что должно происходить всегда: форматирование, линтинг, логирование.
  • То, чего не должно происходить никогда: правка .env или rm -rf не в той папке.
  • То, о чём вы хотите знать: например, Claude ждёт ответа на запрос разрешения, пока вы в другом окне.

Советы по стилю и знания о проекте держите в CLAUDE.md, а жёсткие правила — в хуках.

События хуков, которые вам реально понадобятся

В справочнике больше тридцати событий, и список растёт с новыми релизами. В большинстве реальных настроек используется несколько:

СобытиеКогда срабатываетМожет ли блокировать?
PreToolUseПеред запуском вызова инструментаДа, блокирует вызов
PostToolUseПосле успешного вызова инструментаНет, инструмент уже отработал; stderr уходит Claude
UserPromptSubmitКогда вы отправляете промптДа, промпт не доходит до Claude
NotificationКогда Claude Code отправляет уведомление, например запрос разрешения или ожиданиеНет
StopКогда Claude заканчивает ответДа, Claude продолжает работать
SubagentStart / SubagentStopКогда субагент запускается или завершаетсяТолько SubagentStop
SessionStartПри запуске, возобновлении, /clear или сжатииНет, но stdout становится контекстом
PreCompactПеред сжатием контекстаДа, блокирует сжатие
PermissionRequestКогда вот-вот появится диалог разрешенияТолько через JSON, не через exit 2
SessionEndКогда сессия заканчиваетсяНет

Большинство задач закрывают PreToolUse и PostToolUse. Для «сообщи мне, когда готово или завис» подходят Notification и Stop.

Как хуки настраиваются в settings.json

Хуки живут в тех же файлах настроек, что и разрешения:

ФайлОбластьПередаётся через git?
~/.claude/settings.jsonВсе ваши проектыНет
.claude/settings.jsonОдин проектДа
.claude/settings.local.jsonОдин проект, только выНет (в gitignore)
Managed policy settingsВся организацияЗадают администраторы

Плагины могут поставлять хуки в hooks/hooks.json, а skills и субагенты — описывать хуки в своём frontmatter.

Структура состоит из трёх уровней: событие, группа matcher и список обработчиков.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write",
            "timeout": 30
          }
        ]
      }
    ]
  }
}

type обработчика может быть command (shell-команда), http (POST на URL), mcp_tool (инструмент подключённого MCP-сервера), prompt (быстрая проверка «да/нет» моделью) или agent (экспериментальная проверка субагентом). Таймаут по умолчанию — 600 секунд для обработчиков command, HTTP и MCP tool, 30 секунд для хуков prompt и 60 для хуков agent.

Каждый хук получает JSON на stdin. Общие поля: session_id, transcript_path, cwd, permission_mode и hook_event_name. События инструментов добавляют tool_name, tool_input и tool_use_id. Ваш скрипт читает этот JSON, обычно через jq, и решает, что делать. Переменная окружения CLAUDE_PROJECT_DIR указывает на корень проекта, что удобно для ссылок на скрипты из репозитория.

Введите /hooks в Claude Code, чтобы посмотреть, что загружено и из какого файла пришёл каждый хук. Браузер хуков работает только на чтение, поэтому менять хуки нужно, редактируя JSON.

Matcher: какие вызовы инструментов видит хук

matcher определяет, какие вызовы запускают хук. Для событий инструментов он сопоставляется с именем инструмента:

MatcherЗначение
"*", "" или без matcherКаждый вызов
"Bash"Именно инструмент Bash
"Edit|Write"Edit или Write (список)
"mcp__memory__.*"Каждый инструмент MCP-сервера memory
"mcp__.*__write.*"Любой инструмент MCP, имя которого начинается с write

Правило простое. Если matcher содержит только буквы, цифры, _, -, пробелы, запятые или |, это точное имя или список имён. Любой другой символ превращает его в регулярное выражение JavaScript. Инструменты MCP называются mcp__<server>__<tool>.

Некоторые события игнорируют matcher, в том числе UserPromptSubmit и Stop, потому что сопоставлять нечего. Другие сопоставляют не имя инструмента. SessionStart сопоставляет способ запуска сессии (startup, resume, clear, compact), а Notification — тип уведомления, например permission_prompt или idle_prompt.

События инструментов также принимают поле if с синтаксисом правил разрешений, так что хук Bash может запускаться только для, скажем, "Bash(git *)". В документации это описано как фильтр по принципу «лучшее из возможного», поэтому настоящую проверку держите в скрипте.

Коды выхода и JSON-ответ

Командный хук отвечает Claude Code двумя способами: кодом выхода и необязательным JSON в stdout.

Код выходаЧто происходит
0Успех. stdout разбирается как JSON, если это один JSON-объект. Для UserPromptSubmit и SessionStart простой текст в stdout добавляется в контекст Claude.
2Блокирующая ошибка. stderr — это причина. В PreToolUse вызов отменяется, в UserPromptSubmit промпт отклоняется, в Stop Claude продолжает работу.
Любой другой, включая 1Неблокирующая ошибка. Claude Code отмечает её и идёт дальше.

Ловушка здесь — код выхода 1. Многие скрипты по умолчанию падают с 1, и это не блокирует ничего. Если вы имеете в виду «остановить», выходите с 2.

Для более тонкого управления завершайтесь с 0 и выводите JSON. Хук PreToolUse может разрешить, запретить или спросить:

{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Use rg instead of grep for better performance"
  }
}

permissionDecision принимает allow, deny, ask или defer. Хук также может переписать вызов через updatedInput или передать Claude дополнительный текст через additionalContext. Поля, работающие для любого события, включают continue: false (полностью остановить Claude, с stopReason) и systemMessage (предупреждение, которое видите вы).

Если подходит несколько хуков, они выполняются параллельно, и побеждает самый строгий ответ: deny сильнее defer, defer сильнее ask, ask сильнее allow. allow от хука не отменяет правило deny в ваших разрешениях.

Пример 1: форматировать файлы после каждой правки

С этого хука начинает большинство. Он запускает Prettier для любого файла, который пишет или правит Claude:

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

Для других языков подставьте ruff format, gofmt -w или rustfmt. Поскольку форматтер запускается после правки, Claude увидит отформатированный файл при следующем чтении, а вы перестанете встречать в ревью diff, где меняется только стиль.

Пример 2: блокировать опасные команды и защищённые файлы

Хук PreToolUse — место для жёстких ограничений. Этот скрипт, адаптированный из официального руководства, блокирует правки чувствительных файлов. Сохраните его как .claude/hooks/protect-files.sh:

#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done

exit 0

Сделайте его исполняемым командой chmod +x .claude/hooks/protect-files.sh, затем зарегистрируйте:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}

Тот же приём работает для shell-команд. Сопоставьте Bash, прочитайте .tool_input.command и выходите с 2, если там есть то, что вам не нужно никогда, например rm -rf /, git push --force или DROP TABLE. Помните, что проверку по строке легко обойти, поэтому считайте её ремнём безопасности, а не замком.

Пример 3: получить уведомление на рабочем столе

Долгие задачи останавливаются и ждут вас чаще, чем хотелось бы. Хук Notification сообщит об этом сразу. В macOS:

{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

В Linux используйте вместо этого notify-send 'Claude Code' 'Claude Code needs your attention'. Задайте matcher permission_prompt, если вас интересуют только запросы разрешений, или добавьте хук Stop с той же командой, чтобы узнавать, когда Claude закончил.

Ещё полезные приёмы

  • Вернуть контекст после сжатия. Хук SessionStart с matcher compact может сделать echo короткого напоминания о ваших правилах. Его stdout добавляется в новый контекст.
  • Аудит изменений конфигурации. Хук ConfigChange может дописывать каждое изменение настроек в лог-файл.
  • Контроль качества на Stop. Хук Stop может запускать ваши тесты и завершаться с 2, передав сбои, чтобы Claude продолжал исправлять. Проверяйте поле stop_hook_active во входных данных, чтобы не попасть в бесконечный цикл. Кроме того, Claude Code отключает хук Stop после нескольких блокировок подряд.
  • Автоодобрение одного безопасного запроса. Хук PermissionRequest может ответить на конкретный диалог с помощью {"behavior": "allow"} внутри объекта решения. Делайте matcher узким.

Замечания по безопасности перед добавлением хуков

Хуки выполняются как shell-команды с правами вашего пользователя, без вопросов. В этом и смысл, и риск.

  • Читайте хуки, прежде чем доверять репозиторию. .claude/settings.json проекта может содержать хуки. Просматривайте их так же, как скрипт postinstall.
  • Заключайте переменные в кавычки. Входные данные хука приходят от модели, а модель читает файлы и веб-страницы, где может быть prompt injection. Используйте "$VAR", никогда не применяйте eval ко входным данным и предпочитайте jq самодельному разбору.
  • Используйте абсолютные или относительные к проекту пути через $CLAUDE_PROJECT_DIR, чтобы хук не зависел от текущей папки.
  • Держите хуки быстрыми. Медленный хук PreToolUse замедляет каждый вызов инструмента. Задайте timeout.
  • Хуки — не песочница. Хук deny блокирует вызовы даже при --dangerously-skip-permissions, и это полезно, но настойчивый или запутавшийся агент может прийти к тому же результату другим путём. Сочетайте хуки с правилами deny и изоляцией, как описано в статьях безопасность ИИ-агентов для кода и безопасный пропуск разрешений.
  • Знайте выключатели. "disableAllHooks": true отключает хуки, а администраторы могут задать allowManagedHooksOnly в managed settings, чтобы заблокировать пользовательские и проектные хуки.

Если хук ведёт себя странно, запустите Claude Code с claude --debug или пишите лог в файл через --debug-file /tmp/claude.log, чтобы увидеть matcher, код выхода и вывод каждого хука.

Как AgentVera использует хуки

AgentVera — десктопное приложение, которое запускает Claude Code, Codex, Gemini CLI и другие кодовые CLI рядом друг с другом. Хуки — важная часть того, как оно работает с Claude Code.

  • Ваши хуки остаются вашими. AgentVera передаёт собственные хуки каждому процессу Claude Code через флаг --settings. Claude Code объединяет их с хуками из ваших файлов настроек, а ваш settings.json не редактируется.
  • Статус агента берётся из хуков. Статус, который каждый агент показывает в приложении, читается из собственных событий хуков CLI, а не угадывается по тексту терминала.
  • Smart tools — это хуки. Функция smart tools добавляет четыре хука локальным агентам Claude Code: блокирует повторное чтение одного и того же файла, запускает только те тесты, которых касается правка, проверяет ошибки сразу после правки и делит результаты между агентами. Они включены по умолчанию, и их можно отключить в Settings → “Token saving”.
  • Скрипт уведомлений не нужен. Уведомления и одобрения собирают всех агентов, ждущих одобрения, в одну очередь, отправляют уведомления на рабочий стол, пока приложение в фоне, и могут отправить сообщение на телефон через Telegram.

Qwen Code тоже получает хуки AgentVera, потому что его система хуков следует событиям и формату JSON Claude Code.

Итоги

Начните с одного форматтера PostToolUse и одной защиты PreToolUse, проверьте их через /hooks и --debug и добавляйте новые, только когда правило продолжают нарушать. Выходите с 2, чтобы заблокировать, выводите JSON, когда нужно больше контроля, и относитесь к каждому хуку как к коду, который работает с вашими правами.

Читайте также:

Чтобы попробовать AgentVera, начните с главной страницы.

Вопросы

Что такое хуки Claude Code?

Хуки — это shell-команды, HTTP-вызовы, инструменты MCP или промпты, которые Claude Code сам запускает в заданные моменты сессии: перед вызовом инструмента, после правки файла или когда Claude нужно ваше внимание. Они описываются в settings.json.

Где разместить хуки Claude Code?

Под ключом hooks в файле настроек: ~/.claude/settings.json для всех проектов, .claude/settings.json для проекта, которым вы делитесь через git, или .claude/settings.local.json для проекта только на вашей машине. Хуки могут задавать и плагины, skills и субагенты.

Как хук блокирует вызов инструмента?

Хук PreToolUse либо завершается с кодом 2 и пишет причину в stderr, либо завершается с 0 и выводит JSON с permissionDecision, равным deny. Claude Code отменяет вызов и показывает причину Claude. Код выхода 1 не блокирует.

Работают ли хуки при --dangerously-skip-permissions?

Да. Хук, вернувший deny, блокирует вызов инструмента даже в режиме bypassPermissions. Поэтому PreToolUse полезен как последний рубеж для команд, которые вам не нужны никогда, хотя песочницей он не является.

Как отладить хук Claude Code, который не срабатывает?

Откройте /hooks, чтобы увидеть загруженные хуки и их источники, проверьте, что matcher совпадает с точным именем инструмента, и запустите Claude Code с --debug или --debug-file, чтобы увидеть каждый запуск хука, его код выхода и вывод.

Соберите своих агентов за одним столом.

Скачайте AgentVera бесплатно; ваши установленные CLI уже готовы к работе.

Другие статьи