Мастер Claude · Блок 5. Hooks

Урок 41 из 93 · ~10 мин чтения

Что такое hooks и как они работают

Урок пока закрыт

Курс проходится последовательно.

К текущему уроку

Почему это важно именно вам

Представьте: вы попросили Claude разобрать папку с входящими документами. Он начал работать — читает файлы, создаёт папки, перемещает файлы. Всё идёт нормально, но в какой-то момент вы хотите знать: а что именно он сделал с файлом договора с подрядчиком? Вы смотрите в терминал, но там только итог — «готово». Что происходило внутри — неизвестно.

Или другой сценарий: Claude работает с вашей базой клиентов в Google Sheets, добавляет записи. Вы хотите, чтобы после каждой записи вам приходило уведомление в Telegram — не ждать окончания всего процесса, а видеть прогресс в реальном времени. Без hooks это невозможно настроить иначе, как переписывая логику каждого агента вручную.

Hooks — это механизм перехвата событий в жизненном цикле Claude Code. Вы описываете: «когда Claude делает X — выполни Y». Один раз настроили в конфигурации — и это работает для всех сессий и всех агентов. Логирование, уведомления, проверки, запреты — всё это реализуется через hooks без изменения ни одного промпта.

Что это такое

Если вы работали с CRM-системами, то уже знакомы с этой идеей под другим названием. В большинстве CRM есть триггеры: «когда сделка переходит в статус "закрыто" — отправить письмо клиенту». Вы не меняете логику сделки, не трогаете форму — просто вешаете реакцию на событие. Произошло событие — сработал триггер — выполнилось действие.

Hooks в Claude Code работают точно так же. Только события здесь — это действия Claude: он запустил команду в терминале, прочитал файл, вызвал инструмент, получил результат от внешнего сервиса. На каждое из этих событий можно повесить реакцию — скрипт, команду, HTTP-запрос.

Ещё одна аналогия из повседневной жизни: турникет в офисе. Вы прикладываете карточку — турникет пускает. Но параллельно срабатывает событие: в систему безопасности летит запись «Иванов вошёл в 09:14». Вы об этом не думаете, это происходит автоматически при каждом проходе. Hooks — это такие же «боковые реакции» на события, которые происходят независимо от основного процесса.

Hooks не меняют поведение Claude — они реагируют на него

Важное отличие от промптов и инструкций: hook не говорит Claude «делай так». Он говорит системе «когда Claude сделает вот это — выполни вот то». Промпт управляет намерением. Hook управляет последствиями.

Событий в Claude Code больше тридцати. Ниже — пять, с которых стоит начать (полная карта — в Дне 42):

PreToolUse — срабатывает до того, как Claude вызвал инструмент. Вы можете в этот момент залогировать запрос, проверить параметры или — если нужно — заблокировать вызов.

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

Notification — срабатывает, когда Claude хочет вас о чём-то уведомить. Можно перенаправить уведомление туда, где вам удобнее его получить — в Telegram, в файл, в систему алертов.

Stop — срабатывает, когда Claude закончил отвечать, то есть после каждого хода, а не один раз за сессию. На прерывание пользователем не срабатывает, на ошибки API есть отдельное событие StopFailure. Нужно одно уведомление на всю сессию — берите SessionEnd. Полезно для финальных отчётов, очистки временных файлов, уведомлений о завершении длинной задачи.

SubagentStop — то же самое, но для субагентов — когда завершает работу не основной агент, а один из параллельных дочерних процессов.

Стоит понимать, что hooks работают по принципу «подписки»: вы говорите не «всегда делай вот это», а «когда произойдёт вот это событие — тогда делай». Разница принципиальная. Первое — это инструкция Claude. Второе — это реакция системы, независимая от того, что Claude думает и делает. Даже если Claude ничего не знает о существовании hook, hook всё равно сработает.

Это даёт важное практическое свойство: hooks надёжнее промптов для задач наблюдаемости. Промпт можно «забыть» — особенно в длинном контексте, где более ранние инструкции уходят из фокуса. Hook не забывается — он срабатывает на уровне системы, независимо от состояния диалога. Если вам важно, чтобы каждое файловое изменение было залогировано — hook даёт эту гарантию, а промпт «логируй все изменения» — нет.

Как работает на практике

Hooks настраиваются в файле settings.json. Этот файл живёт в папке .claude/ вашего проекта или глобально в ~/.claude/settings.json. Если хотите, чтобы hook работал во всех проектах — пишите в глобальный файл.

Шаг 1. Откройте или создайте settings.json

Глобальный файл:

~/.claude/settings.json

Проектный файл (только для текущего проекта):

.claude/settings.json

Если файла нет — создайте его. Минимальная структура:

{
  "hooks": {}
}

Обратите внимание: hooks — это один из разделов settings.json. Если у вас уже есть этот файл с другими настройками (например, разрешениями из Дня 8), добавляйте раздел "hooks" внутрь существующего объекта, а не создавайте новый файл. Два settings.json в одной папке невозможны — файл один, настройки все внутри него.

Шаг 2. Разберём структуру hook

Каждый hook описывается так:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '\"Claude изменил файл: \\(.tool_input.file_path // \"?\")\"' >> ~/claude-file-log.txt"
          }
        ]
      }
    ]
  }
}

Разберём каждую часть:

Шаг 3. Первый практический пример — лог файловых операций

Создайте или откройте ~/.claude/settings.json и добавьте:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit|Read",
        "hooks": [
          {
            "type": "command",
            "command": "jq -r '\"\\(now|strftime(\"%Y-%m-%d %H:%M:%S\")) TOOL=\\(.tool_name) FILE=\\(.tool_input.file_path // \"-\")\"' >> ~/Desktop/claude-audit.log"
          }
        ]
      }
    ]
  }
}

После этого запустите любую сессию Claude Code и попросите его поработать с файлами. Затем откройте ~/Desktop/claude-audit.log — там будет хронология каждого файлового действия с временными метками.

Этот лог можно использовать для разбора полётов. Если что-то пошло не так — вы открываете файл и видите точную последовательность действий: какой файл читался, что менялось, в какое время. Это особенно ценно при работе агентов в неинтерактивном режиме с флагом --bg (День 8) — когда Claude работает в фоне, вы не видите терминал, но лог пишется.

Что здесь происходит по шагам:

  1. Claude решает прочитать или изменить файл и вызывает инструмент Read, Write или Edit
  2. Claude Code видит, что в settings.json есть hook для PostToolUse с matcher на эти инструменты
  3. После того как инструмент отработал, Claude Code запускает команду из hook
  4. Claude Code отправляет хуку на stdin JSON события — с полями hook_event_name, tool_name, tool_input, session_id, cwd
  5. Скрипт разбирает этот JSON сам — например, утилитой jq или несколькими строками на Python
  6. Команда дописывает строку в лог-файл

Переменные окружения в hooks

Событие приходит хуку JSON-ом на стандартный вход: hook_event_name (какое событие), tool_name (какой инструмент), tool_input (его параметры — путь к файлу лежит в tool_input.file_path, команда в tool_input.command), session_id, cwd, transcript_path. У PostToolUse добавляется tool_response. Отдельных переменных $CLAUDE_TOOL_* не существует — из окружения доступен CLAUDE_PROJECT_DIR и несколько служебных переменных, но никаких $CLAUDE_TOOL_* не существует.

Шаг 4. Hook для уведомлений о завершении задачи

Если Claude работает над длинной задачей — анализирует большой документ, обрабатывает папку файлов — удобно получить уведомление, когда он закончил. Вот hook для macOS-уведомления:

{
  "hooks": {
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude завершил задачу\" with title \"Claude Code\"'"
          }
        ]
      }
    ]
  }
}

У события Stop matcher не поддерживается вовсе. И помните: оно срабатывает после каждого ответа Claude, так что уведомление будет приходить часто. После сохранения settings.json уведомление будет всплывать каждый раз, когда Claude заканчивает ответ. Нужно ровно одно за сессию — используйте SessionEnd.

Шаг 5. Проверяем, что hook работает

Запустите сессию:

claude

Попросите Claude сделать что-то с файлами — например, создать тестовый файл. После завершения проверьте лог:

cat ~/Desktop/claude-audit.log

Если там появились записи с временными метками и именами инструментов — hook работает.

Синтаксис JSON не прощает ошибок

Если в settings.json есть синтаксическая ошибка — лишняя запятая, незакрытая скобка — Claude Code проигнорирует весь файл настроек. Проверить, не в этом ли дело: claude doctor из терминала или /doctor внутри сессии — они покажут ошибки разбора файлов настроек. Перед сохранением проверьте JSON через любой онлайн-валидатор или расширение редактора. Самая частая ошибка — запятая после последнего элемента массива.

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

Ошибка 1. Hook не срабатывает — не та точка в пути

Вы создали hooks в .claude/settings.json внутри проекта, но запускаете Claude Code из другой папки. Или наоборот — хотели глобальный hook, но создали проектный. Правило простое: если хотите, чтобы hook работал везде — используйте ~/.claude/settings.json. Если только для одного проекта — .claude/settings.json в корне этого проекта.

Ошибка 2. Matcher написан неправильно

"matcher": "write" — не сработает. Имена инструментов чувствительны к регистру: Write, Edit, Read, Bash, WebSearch. Строчные буквы не совпадут. Если не уверены в точном имени инструмента — пропустите matcher вообще, тогда hook сработает на любой инструмент, и вы увидите в логах реальные имена.

Ошибка 3. Команда в hook падает с ошибкой и блокирует работу

Блокирует только код выхода 2. Любой другой ненулевой код Claude Code считает технической ошибкой хука и всё равно выполняет действие. Поэтому || true в конце команды спасает от шума в логе, но не от блокировки. Пишите команды в hooks максимально простыми и добавляйте || true в конце, чтобы ошибки в hook не влияли на основной процесс:

"command": "echo \"лог\" >> ~/claude.log || true"

Ошибка 4. Слишком тяжёлая команда в hook

Hook срабатывает синхронно — Claude ждёт, пока команда завершится, и только потом продолжает работу. Если вы поставили в hook что-то тяжёлое — например, отправку HTTP-запроса на медленный сервер или конвертацию видео — каждый вызов инструмента будет тормозить. Для долгих операций поставьте у хука "async": true — он уйдёт в фон и не будет держать сессию.

Когда нужно / когда нет

Используйте hooks, когда:

Не используйте hooks, когда:

Hooks — это инфраструктура, а не функциональность

Hooks сами по себе ничего не делают для качества работы Claude. Они дают вам наблюдаемость и контроль над тем, что происходит. Это как камеры в офисе: они не делают работу лучше, но вы знаете, что происходит, и можете среагировать.

Связь с другими уроками

День 8 — разрешения и безопасность. Там вы настраивали, что Claude вообще может делать: какие папки трогать, какие команды запускать. Hooks — следующий уровень: теперь вы не только ограничиваете, но и наблюдаете. PreToolUse hook можно использовать как дополнительный слой контроля — проверить параметры вызова до того, как инструмент сработает.

День 28 — оркестратор и субагенты. Когда у вас несколько субагентов работают параллельно, сложно отследить, кто что делает. Hook SubagentStop позволяет получать уведомление каждый раз, когда один из субагентов завершает свою часть работы. Это даёт вам полную картину без необходимости следить за каждым агентом отдельно.

День 46 — hook типа http и интеграции. В этом уроке hooks только командного типа — type: command. В День 46 разберём hook типа http: вместо команды в терминале Claude Code отправляет HTTP-запрос на ваш сервис. Это открывает интеграции с любыми внешними системами — CRM, мессенджерами, базами данных — без написания промежуточных скриптов.

Задание на сегодня

Добавьте в ~/.claude/settings.json один hook — лог файловых операций из примера в уроке. Запустите Claude Code и попросите его создать любой тестовый файл (например, «создай файл test.txt с текстом привет»). После этого откройте ~/Desktop/claude-audit.log и убедитесь, что там появилась запись с временной меткой и именем инструмента.

Критерий «выполнено»: в claude-audit.log есть хотя бы одна строка с датой, TOOL=Write и путём к файлу.

Резюме

Следующий урок откроется после отметки.