$ sudo teach IT

Всё, что вы настраивали до сих пор, — это просьбы. В CLAUDE.md вы пишете «после правки файла запускай форматтер», в скилле объясняете порядок действий. Модель это читает и обычно выполняет. Обычно — ключевое слово: в длинной сессии она может пропустить пункт, который вы считали обязательным, и вы об этом не узнаете, пока не посмотрите диф.

Хуки решают эту проблему. Хук — это ваш обработчик, который Claude Code запускает сам в определённой точке своей работы. Не модель решает, вызывать его: его вызывает программа. Форматтер после каждой записи файла, лог bash-команд, запрет на правку .env — всё это перестаёт быть договорённостью с моделью и становится свойством среды.

Что уже умеем / что добавим

Вы умеете формировать поведение агента текстом: описывать проект в CLAUDE.md, задавать правила, выносить процедуры в скиллы, делегировать работу подагентам. Всё это влияет на решения модели.

Теперь мы спускаемся уровнем ниже — к тому, что происходит независимо от решений модели. Разберём, из каких событий состоит жизненный цикл сессии, как часто они срабатывают, как устроена конфигурация хука и какими бывают обработчики. Боевые хуки будем писать в следующем уроке — здесь важно собрать карту.

Что вы узнаете в рамках статьи

  • Чем контроль хуками отличается от инструкций в CLAUDE.md и скиллах
  • Из каких событий состоит жизненный цикл сессии
  • Как часто срабатывает каждое ключевое событие
  • Как устроена конфигурация: событие, группа матчера, обработчики
  • В каких файлах живут хуки и что показывает команда /hooks
  • Какие бывают типы обработчиков помимо shell-команды

Ключевые термины

  • Хук (hook) — определённый вами обработчик, который Claude Code запускает в конкретной точке своего жизненного цикла.
  • Событие жизненного цикла — момент в работе Claude Code, к которому можно привязать хук: старт сессии, отправка промпта, вызов инструмента, завершение ответа.
  • Матчер — фильтр внутри события: определяет, на какие инструменты, файлы или типы уведомлений сработает обработчик.
  • Обработчик — конкретное действие хука. Задаётся полем type, бывает пяти видов.
  • Детерминированный контроль — гарантия, что действие произойдёт, потому что его запускает программа, а не модель.

Жизненный цикл сессии

Проще всего представить работу Claude Code как ленту событий. Самая частая цепочка:

SessionStart → UserPromptSubmit → PreToolUse → вызов инструмента → PostToolUse → Stop → SessionEnd

SessionStart срабатывает при старте или возобновлении сессии и получает поле source со значением startup, resume, clear, compact или fork — по нему видно, откуда пришёл запуск. Дальше вы отправляете промпт, и до начала его обработки срабатывает UserPromptSubmit с полем prompt.

Затем начинается самая насыщенная часть. Перед каждым вызовом инструмента срабатывает PreToolUse — единственное место, где вызов ещё можно заблокировать. Если вызову нужно решение о разрешении, срабатывает PermissionRequest. После успешного вызова — PostToolUse, после неуспешного — PostToolUseFailure. Эта пара повторяется столько раз, сколько инструментов Claude вызвал.

Когда Claude закончил отвечать, срабатывает Stop; он получает last_assistant_message и stop_hook_active. Завершение подагента отмечает SubagentStop, закрытие сессии — SessionEnd.

Рядом с основной линией живут события, не привязанные к ходу разговора. Notification — когда Claude Code отправляет уведомление. PreCompact и PostCompact — до и после сжатия контекста. ConfigChange — когда изменился файл настроек; матчер фильтрует тип: user_settings, project_settings, local_settings, policy_settings, skills. FileChanged — когда отслеживаемый файл изменился на диске, независимо от того, кто его записал.

Всего событий больше трёх десятков — полный список из справочника:

SessionStart, Setup, UserPromptSubmit, UserPromptExpansion, PreToolUse,
PermissionRequest, PermissionDenied, PostToolUse, PostToolUseFailure,
PostToolBatch, Notification, MessageDisplay, SubagentStart, SubagentStop,
TaskCreated, TaskCompleted, Stop, StopFailure, TeammateIdle,
InstructionsLoaded, ConfigChange, CwdChanged, DirectoryAdded, FileChanged,
WorktreeCreate, WorktreeRemove, PreCompact, PostCompact, PreModelSwitch,
PostModelSwitch, Elicitation, ElicitationResult, SessionEnd

Запоминать весь список не нужно: в работе вы будете использовать шесть-семь событий, остальные искать в справочнике.

Частота срабатывания

Частота определяет, что хуку можно позволить: обработчик, выполняемый раз за сессию, может быть медленным, а тот, что срабатывает на каждый инструмент, — нет.

  • Раз за сессию: SessionStart, SessionEnd.
  • Раз за ход: UserPromptSubmit, Stop.
  • На каждый вызов инструмента: PreToolUse, PostToolUse.

Пример: вы отправили один промпт, Claude прочитал четыре файла и отредактировал два. Хук на SessionStart сработал один раз, на UserPromptSubmit — один, на PreToolUse без матчера — шесть, на PostToolUse с матчером Edit|Write — два, на Stop — один.

Как устроена конфигурация

Конфигурация хука — три уровня вложенности: событие, группа матчера, список обработчиков.

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

Читается сверху вниз: событие PostToolUse, внутри — группа для инструментов Edit и Write, внутри группы — один обработчик типа command. Групп в событии может быть несколько (разные матчеры), обработчиков в группе — тоже.

Важная деталь: имена событий — ключи внутри одного объекта hooks. Если ключ hooks в файле уже есть, новое событие добавляется соседним ключом, а не заменяет объект целиком. Разбор матчеров, входного JSON и кодов выхода — в уроке 8.2.

Где живут хуки

Хуки объявляются в тех же файлах настроек, что и остальное:

Файл Область Коммитится
~/.claude/settings.json все ваши проекты нет
.claude/settings.json один проект да
.claude/settings.local.json один проект, личные настройки нет

Логика та же: командные договорённости — в файл проекта, личные привычки — в пользовательский или локальный. Кроме того, хуки можно объявить во frontmatter скилла: тогда они действуют до конца сессии после вызова скилла.

Посмотреть, что уже настроено, помогает команда /hooks в сессии. Она открывает браузер хуков по событиям и показывает событие, матчер, тип, файл-источник и команду. Меню только для чтения: менять хуки нужно правкой JSON. Правки настроек обычно подхватывает файловый наблюдатель; если через несколько секунд ничего не изменилось, перезапустите сессию.

Результат успешного хука в разговоре не показывается — это часто сбивает с толку. Проверять приходится по эффекту или через отладочный лог:

# Запустить сессию с записью отладочного лога
claude --debug-file /tmp/claude.log

# В соседнем терминале следить за срабатываниями
tail -f /tmp/claude.log

# Отключить все хуки разом можно настройкой "disableAllHooks": true

Хук — не обязательно shell-команда

Тип обработчика задаётся полем type, и типов пять:

  • command — shell-команда. Самый частый вариант; поля command, args, timeout, async, shell.
  • http — POST с JSON события на указанный url. Ответ использует тот же формат, что и вывод command-хуков. Один только HTTP-статус заблокировать действие не может.
  • mcp_tool — вызов инструмента на подключённом MCP-сервере: поля server, tool, input. Мост к главе 9.
  • prompt — однократная оценка моделью, возвращает решение в JSON. В поле prompt вход хука подставляется через плейсхолдер $ARGUMENTS.
  • agent — порождает подагента, который использует Read, Grep и Glob перед решением. Экспериментальный.

Таймауты по умолчанию: 600 секунд для command, http и mcp_tool, 30 для prompt, 60 для agent.

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

  • Ждать, что хук заменит инструкцию в CLAUDE.md. Хук не объясняет модели, как думать, — он выполняет действие в фиксированной точке. Описания стиля остаются в CLAUDE.md, гарантии — в хуках.
  • Вешать тяжёлый обработчик на PreToolUse без матчера. Он сработает на каждый вызов инструмента, включая десятки чтений, и замедлит сессию. Сузьте матчер.
  • Пытаться отменить действие на PostToolUse. Событие срабатывает после успешного вызова, отменять нечего. Блокировать можно только на PreToolUse.
  • Искать кнопку «добавить хук» в меню /hooks. Меню только для чтения, изменения делаются правкой файла настроек.

Наиболее частые вопросы

  • Чем хук лучше инструкции в скилле? — Он не зависит от решения модели. Скилл выполняется, когда модель сочла его уместным; хук — всегда, когда наступило событие.
  • Сколько раз сработает PostToolUse за один промпт? — Столько, сколько инструментов Claude успешно вызвал и сколько из них прошло матчер. Может быть и ноль, и десятки.
  • Хуки одного события выполняются по очереди? — Нет, все хуки одного события запускаются параллельно. Не рассчитывайте на порядок между ними.
  • Нужно ли перезапускать сессию после правки настроек? — Обычно нет, изменения подхватывает файловый наблюдатель. Если эффекта нет — перезапустите.
  • Обязательно ли писать shell-скрипт? — Нет. Кроме command есть http, mcp_tool, prompt и agent: можно отправить событие на свой сервис или запросить оценку у модели.

Итоги

Вы прошли важный водораздел курса. Раньше вы описывали желаемое поведение словами и полагались на то, что модель их учтёт; теперь у вас есть механизм, срабатывающий независимо от неё. Вы знаете порядок событий жизненного цикла, разницу между «раз за сессию», «раз за ход» и «на каждый инструмент», видите трёхуровневую структуру конфигурации и знаете, что обработчик не обязан быть shell-командой.

Этого достаточно, чтобы читать чужие конфигурации хуков. В следующем уроке перейдём от карты к практике: разберём матчеры, посмотрим, какой JSON хук получает на вход, и научимся возвращать решение — в том числе блокировать опасные вызовы.

На следующий урок