ХЕЛЛОУИН СЕЙЛ-10%
До 31 октября-10%
ХЕЛЛОУИН СЕЙЛ-10%
До 31 октября-10%
ХЕЛЛОУИН СЕЙЛ-10%
До 31 октября-10%
ХЕЛЛОУИН СЕЙЛ-10%
До 31 октября-10%
ХЕЛЛОУИН СЕЙЛ-10%
До 31 октября-10%
ХЕЛЛОУИН СЕЙЛ-10%
До 31 октября-10%

Как настроить хуки в Claude Code

Чем хуки отличаются от CLAUDE.md и прав доступа, какие события они ловят и как за вечер настроить автоформатирование, запрет правок в .env и уведомления.
Guide DAO
Инструкция сверена с документацией Claude Code в октябре 2026 года. Хуки быстро обрастают новыми событиями и полями, поэтому полный список сверяйте со справочником.
Хуками в Claude Code называют команды, которые запускаются сами в заданные моменты: перед командой в терминале, после правки файла, в конце ответа. Запускает их харнес Claude Code, то есть программа вокруг модели, поэтому хук срабатывает каждый раз, что бы ни решила модель.

Зачем хуки, если есть CLAUDE.md

Правило «не трогай .env» можно записать в CLAUDE.md, и Claude постарается его соблюдать. Но для модели такой файл остаётся контекстом, а не обязательной конфигурацией, и строгого выполнения документация не обещает. Подробнее об этом в статье о контексте и памяти. А хук PreToolUse, который блокирует правку .env, сработает всегда.
Права доступа тоже соблюдаются всегда, но это шаблоны вроде «эту команду разрешить, этот файл не читать». Хук запускает ваш код. Он видит полный вызов, решает по своей логике и умеет то, чего правила не умеют, например отформатировать файл или прислать уведомление. Блокировка из хука действует в любом режиме, даже в bypassPermissions, а разрешение из хука не отменяет запретов deny.
Скил даёт Claude знания и процедуры, которые он применяет сам, субагент выполняет задачу в отдельном контекстном окне, MCP подключает внешние сервисы. Хук же в контекст ничего не добавляет, пока сам не вернёт текст.

Где настраивают хуки

Хуки живут в файлах settings.json рядом с правами доступа. Про эти файлы мы писали в статье об установке и настройке Claude Code. Хук из ~/.claude/settings.json работает во всех ваших проектах, из .claude/settings.json в одном проекте и, если файл закоммичен, у всей команды, из .claude/settings.local.json только у вас. Ещё хуки приходят из настроек организации, плагинов и шапки скилов и субагентов. Уровни складываются, проектный хук не отменяет личный.
Команда /hooks показывает все хуки по событиям и откуда пришёл каждый, но только для просмотра. Правки в файлах Claude Code обычно подхватывает без перезапуска. Писать JSON руками не обязательно, Claude сделает это по просьбе вроде «напиши хук, который запускает eslint после каждой правки файла». Выключить все хуки разом можно строкой "disableAllHooks": true.

Как устроен хук

У конфигурации три уровня. Сверху событие, в нём группа с фильтром matcher, а в группе один или несколько обработчиков. Этот хук запускает скрипт проверки после каждой записи или правки файла:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "/path/to/lint-check.sh"
          }
        ]
      }
    ]
  }
}
Обычно в type стоит command, то есть shell-команда. Бывают ещё http и mcp_tool, а типы prompt и agent отдают решение модели.
Событий больше тридцати, для начала хватит шести. SessionStart срабатывает при запуске или возобновлении сеанса, и его вывод попадает в контекст Claude. UserPromptSubmit получает промпт раньше модели и может его отклонить. PreToolUse срабатывает перед вызовом тула, то есть инструмента модели вроде Bash или Edit, и может его заблокировать. PostToolUse срабатывает после успешного вызова. Notification приходит вместе с уведомлением, например когда Claude ждёт ответа. Stop срабатывает, когда Claude закончил отвечать.
У событий тулов matcher сравнивается с именем тула. Bash ловит команды в терминале, Edit|Write ловит правку и запись файлов, а регулярное выражение mcp__github__.* ловит все тулы MCP-сервера github. У SessionStart matcher проверяет способ запуска, у Notification проверяет тип уведомления, а у UserPromptSubmit и Stop его нет вовсе.

Что хук получает и как отвечает

Данные события приходят хуку в формате JSON через стандартный ввод. Перед командой npm test хук PreToolUse получит примерно такое:
{
  "session_id": "abc123",
  "cwd": "/Users/sarah/myproject",
  "hook_event_name": "PreToolUse",
  "tool_name": "Bash",
  "tool_input": {
    "command": "npm test"
  }
}
У Edit и Write в tool_input.file_path лежит абсолютный путь к файлу, а PostToolUse получает ещё tool_response с результатом. Поля достают утилитой jq, на ней построены bash-примеры в документации. На macOS её ставят командой brew install jq.
Ответ хук даёт кодом выхода. Код 0 значит «возражений нет», но для PreToolUse это ещё не разрешение, вызов проходит обычную проверку прав. Код 2 блокирует действие. Если это вызов тула, текст из stderr уходит Claude как фидбек, и он может сменить подход. Любой другой код, даже привычная единица, считается сбоем хука, и действие выполнится.
У Stop код 2 не даёт Claude закончить ответ, и он продолжает работу. А PostToolUse срабатывает, когда тул уже отработал, и отменить ничего не может.
Для тонкого управления хук выходит с кодом 0 и печатает JSON. Так PreToolUse отклоняет вызов с объяснением для Claude:
{
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "deny",
    "permissionDecisionReason": "Use rg instead of grep for better performance"
  }
}
Вместо deny можно вернуть ask, и вы увидите обычный запрос разрешения, или allow, который пропускает запрос, но не обходит запреты из настроек. PostToolUse и Stop отвечают иначе, полем "decision": "block" с причиной в reason. Выбирайте один способ на хук, код 2 или JSON.

Уведомление, когда Claude ждёт ответа

Этот хук присылает системное уведомление, когда Claude ждёт вас, и терминал можно не караулить. Создайте ~/.claude/settings.json, если его ещё нет, и добавьте событие Notification. Вариант для macOS:
{
  "hooks": {
    "Notification": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude Code needs your attention\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}
На Linux вместо команды с osascript подставьте notify-send 'Claude Code' 'Claude Code needs your attention', вариант для Windows есть в документации. Если ключ hooks уже есть, добавьте Notification рядом с другими событиями.
Пустой matcher ловит все уведомления. Чаще других придут два. permission_prompt значит, что Claude ждёт разрешения, а вы около шести секунд ничего не печатали. idle_prompt приходит примерно через минуту после конца ответа, если вы ничего не печатали. Чтобы получать только их, укажите "matcher": "permission_prompt|idle_prompt".
Для проверки наберите /hooks, хук должен появиться под Notification. Нажмите Esc и переключайте режим клавишами Shift+Tab, пока в строке состояния не появится ⏸ manual mode on. Попросите Claude о действии, которое требует разрешения, и уйдите в другое окно. Уведомление придёт через несколько секунд.
Если на macOS уведомление не пришло, скорее всего, у Script Editor, через который работает osascript, нет разрешения. Выполните один раз osascript -e 'display notification "test"', найдите Script Editor в настройках уведомлений macOS и разрешите ему уведомления.

Автоформатирование после правки

Второй хук запускает Prettier после каждой правки, и форматирование больше не зависит от памяти модели. Добавьте в .claude/settings.json в корне проекта:
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
          }
        ]
      }
    ]
  }
}
Команда достаёт из JSON путь к файлу и передаёт его Prettier. Попросите Claude добавить в JS-файл строку с одинарными кавычками, и при настройках по умолчанию хук заменит их на двойные. Успешный хук в чат ничего не пишет, смотрите на сам файл. Правку командой в терминале этот хук не заметит, для такого случая есть событие FileChanged.

Запрет правок в .env и защищённых папках

Третий хук не даёт править .env, package-lock.json и всё внутри .git/. Сохраните скрипт как .claude/hooks/protect-files.sh:
#!/bin/bash
# protect-files.sh

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

# Normalize Windows backslash separators so the patterns below match
FILE_PATH="${FILE_PATH//\\//}"

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
Если путь совпал с шаблоном, скрипт пишет причину в stderr и выходит с кодом 2. Свои папки допишите в PROTECTED_PATTERNS, например "migrations/". Шаблон сравнивается по подстроке, поэтому .env закроет и .env.example. Сделайте скрипт исполняемым:
chmod +x .claude/hooks/protect-files.sh
И подключите его в .claude/settings.json:
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
          }
        ]
      }
    ]
  }
}
Переменная $CLAUDE_PROJECT_DIR указывает на корень проекта, и скрипт найдётся из любой папки. Попросите Claude добавить комментарий в .env. Правка не случится, а Claude получит сообщение Blocked: из скрипта.
Хук видит только Edit и Write, поэтому echo >> .env в терминале он пропустит, а чтение не трогает вовсе. Правила deny охватывают больше. Read(./.env) и Edit(./.env) действуют и на команды вроде cat и tee, которые Claude Code распознаёт в терминале, и на перенаправления вроде >> file. Поэтому секреты стоит закрыть и такими правилами, а хук оставить для запретов со своей логикой.

Безопасность

Хук выполняет команды с вашими правами и может прочитать, изменить или удалить любой файл, доступный вашей учётной записи. Сэндбокс и права доступа ограничивают вызовы тулов Claude, а хуки работают вне сэндбокса. Поэтому читайте каждый хук, прежде чем его добавить, а у плагина перед установкой загляните в hooks/hooks.json.
Хуки из .claude/settings.json приходят вместе с чужим репозиторием. В интерактивном сеансе Claude Code не запускает их, пока вы не подтвердите доверие к папке. В claude -p и SDK такого диалога нет, и хуки репозитория сработают сразу. Перед таким запуском на чужом коде просмотрите его папку .claude/, добавьте флаг --bare, с которым Claude Code не читает хуки, скилы и плагины проекта, или отключите хуки флагом --settings '{"disableAllHooks": true}'.
Хук может дописать и сам Claude. Запись в папку .claude Claude Code автоматически не одобряет. В ручном режиме и в acceptEdits он спросит вас, в auto запись проверит классификатор. Читайте, что одобряете, ведь новый хук будет запускаться без вопросов.
Аргументы тула в tool_input сгенерировала модель, поэтому не доверяйте им вслепую. Берите переменные в кавычки, "$VAR" вместо $VAR, проверяйте пути на .. и указывайте к скриптам полные пути.

Частые ошибки

Хук не срабатывает. Найдите его в /hooks и проверьте регистр в matcher, ведь bash не совпадёт с Bash. JSON в настройках должен быть валидным, без лишних запятых и комментариев. В новой папке хуки ждут, пока вы подтвердите доверие к ней.
Охранный хук ничего не блокирует. Скорее всего, скрипт выходит с кодом 1, а блокирует только 2. Так же всё пропустит хук, чей скрипт лежит по неверному пути или не получил chmod +x. В версиях 2.1.295 и новее охранному хуку можно добавить "onFailure": "block", тогда его сбой блокирует действие.
JSON не действует. permissionDecision должен лежать внутри hookSpecificOutput, а в stdout не должно быть ничего лишнего, даже строки, которую печатает ваш профиль оболочки.
Claude не может закончить ответ. Хук на Stop должен проверять поле stop_hook_active и выходить с кодом 0, если оно равно true. Без этого Claude будет работать дальше, пока Claude Code не завершит ход после восьми блокировок подряд.
Работа тормозит. Команде в хуке по умолчанию дают десять минут, а хуку на UserPromptSubmit 30 секунд, и всё это время Claude ждёт. Долгие задачи запускайте с "async": true, но такой хук уже ничего не блокирует.
Отлаживать хук удобно без Claude:
echo '{"tool_name":"Bash","tool_input":{"command":"ls"}}' | ./my-hook.sh
echo $?
Подробный журнал пишет claude --debug-file /tmp/claude.log, а в начатом сеансе его включает /debug.

Что дальше

Дальше попробуйте SessionStart с matcher compact. Такой хук после компактинга возвращает в контекст то, что нельзя терять, например вывод git log --oneline -5. А хук типа prompt на Stop спросит модель, всё ли сделано, и Claude продолжит работу, пока ответ отрицательный.
Наш совет: начните с уведомлений и форматирования. Охранные хуки добавляйте под ошибки, которые агент уже совершал, а то, что не страшно иногда нарушить, оставьте в CLAUDE.md. Хуки, скилы и субагентов мы разбираем на практике в модуле «Скилы, хуки и автономность» курса «Основы Claude Code».
Трек: Основы Claude Code
Научитесь без программирования поручать Claude Code настоящую работу: сайт, ролики для соцсетей, отчёт по цифрам вашего проекта. Повторяющиеся задачи он будет делать сам по расписанию.
Подробнее
Поделиться
Интересно погрузиться в крипту?
Поможем выбрать направление!