- Блокировать опасные операции перед их выполнением, такие как деструктивные команды shell или несанкционированный доступ к файлам
- Логировать и аудировать каждый вызов инструмента для соответствия требованиям, отладки или аналитики
- Преобразовывать входные и выходные данные для санитизации данных, внедрения учетных данных или перенаправления путей файлов
- Требовать одобрение человека для чувствительных действий, таких как запись в базу данных или вызовы API
- Отслеживать жизненный цикл сеанса для управления состоянием, очистки ресурсов или отправки уведомлений
Как работают hooks
1
Срабатывает событие
Что-то происходит во время выполнения агента, и SDK срабатывает событие: инструмент вот-вот будет вызван (
PreToolUse), инструмент вернул результат (PostToolUse), подагент запустился или остановился, агент неактивен или выполнение завершилось. См. полный список событий.2
SDK собирает зарегистрированные hooks
SDK проверяет наличие hooks, зарегистрированных для этого типа события. Это включает callback hooks, которые вы передаете в
options.hooks, и hooks команд shell из файлов настроек, когда соответствующая запись settingSources или setting_sources включена, что она есть для параметров query() по умолчанию.3
Matchers фильтруют, какие hooks запускаются
Если hook имеет паттерн
matcher (например, "Write|Edit"), SDK проверяет его против цели события (например, имя инструмента). Hooks без matcher запускаются для каждого события этого типа.4
Выполняются функции обратного вызова
Каждая функция обратного вызова matching hook получает информацию о том, что происходит: имя инструмента, его аргументы, ID сеанса и другие детали, специфичные для события.
5
Ваш callback возвращает решение
После выполнения любых операций (логирование, вызовы API, валидация), ваш callback возвращает объект вывода, который говорит агенту, что делать: разрешить операцию, заблокировать ее, изменить входные данные или внедрить контекст в разговор.
PreToolUse (шаг 1) с matcher "Write|Edit" (шаг 3), поэтому callback срабатывает только для инструментов записи файлов. При срабатывании callback получает входные данные инструмента (шаг 4), проверяет, нацелена ли путь файла на файл .env, и возвращает permissionDecision: "deny" для блокировки операции (шаг 5):
Доступные hooks
SDK предоставляет hooks для различных этапов выполнения агента. Некоторые hooks доступны в обоих SDK, в то время как другие доступны только в TypeScript.Настройка hooks
Чтобы настроить hook, передайте его в полеhooks ваших параметров агента (ClaudeAgentOptions в Python, объект options в TypeScript):
hooks — это словарь (Python) или объект (TypeScript), где:
- Ключи: имена событий hook, такие как
'PreToolUse','PostToolUse'и'Stop' - Значения: массивы matchers, каждый содержащий необязательный паттерн фильтра и ваши функции обратного вызова
Matchers
Используйте matchers для фильтрации, когда срабатывают ваши callbacks. Полеmatcher соответствует другому значению в зависимости от типа события hook. Например, hooks на основе инструментов соответствуют имени инструмента, в то время как hooks Notification соответствуют типу уведомления. См. справочник hooks Claude Code для полного списка значений matcher для каждого типа события.
SDK matchers следуют тем же правилам, что и matchers в файлах настроек. Matcher, содержащий только буквы, цифры, _, -, пробелы, , и |, сравнивается как точная строка, где альтернативы разделены | или , с необязательными окружающими пробелами, поэтому Write|Edit и Write, Edit каждый соответствует ровно этим двум инструментам, а code-reviewer соответствует только этому типу агента. Matcher *, пустая строка или отсутствие matcher вообще соответствует каждому возникновению события.
Matcher, содержащий любой другой символ, вычисляется как якорь-независимое регулярное выражение, поэтому ^mcp__ соответствует каждому MCP инструменту и Edit.* соответствует как Edit, так и NotebookEdit. Оберните регулярное выражение в ^ и $, когда вам нужно совпадение всей строки.
Matcher вроде mcp__memory или mcp__brave-search содержит только символы точного совпадения, поэтому он сравнивается как точная строка и не соответствует никакому инструменту; используйте mcp__memory__.* для соответствия каждому инструменту с этого сервера.
Дефисы в наборе точного совпадения требуют Claude Code runtime версии 2.1.195 или позже. В более ранних версиях имя с дефисом, такое как code-reviewer, вычисляется как якорь-независимое регулярное выражение и должно быть якорировано как ^code-reviewer$ для точного совпадения.
Используйте паттерн
matcher для нацеливания на конкретные инструменты, когда это возможно. Matcher с 'Bash' запускается только для команд Bash, в то время как опущение паттерна запускает ваши callbacks для каждого возникновения события.
Для tool-based hooks, matchers фильтруют только по имени инструмента, а не по путям файлов или другим аргументам. Для фильтрации по пути файла проверьте tool_input.file_path внутри вашего callback.
Функции обратного вызова
Входные данные
Каждый callback hook получает три аргумента:- Входные данные: типизированный объект, содержащий детали события. Каждый тип hook имеет свою форму входных данных. Например,
PreToolUseHookInputвключаетtool_nameиtool_input, в то время какNotificationHookInputвключаетmessage. См. полные определения типов в справочниках TypeScript и Python SDK.- Все входные данные hook содержат
session_id,cwdиhook_event_name. agent_idиagent_typeзаполняются, когда hook срабатывает внутри подагента. В TypeScript они находятся на базовом входе hook и доступны для всех типов hook. В Python они являются необязательными полями наPreToolUse,PostToolUse,PostToolUseFailureиPermissionRequest, и обязательными полями наSubagentStartиSubagentStop.
- Все входные данные hook содержат
- ID использования инструмента (
str | None/string | undefined): коррелирует событияPreToolUseиPostToolUseдля одного и того же вызова инструмента. - Контекст: в TypeScript содержит свойство
signal(AbortSignal) для отмены. В Python этот аргумент зарезервирован для будущего использования.
Выходные данные
Ваш callback возвращает объект с двумя категориями полей:- Поля верхнего уровня работают одинаково для каждого события:
systemMessageпоказывает сообщение пользователю, иcontinue(continue_в Python) определяет, продолжает ли агент работать после этого hook. hookSpecificOutputконтролирует текущую операцию. Поля внутри зависят от типа события hook. Для hooksPreToolUseздесь вы устанавливаетеpermissionDecision("allow","deny","ask"или"defer"),permissionDecisionReasonиupdatedInput. Возврат"defer"завершает запрос, чтобы вы могли возобновить его позже. Для hooksPostToolUseвы можете установитьadditionalContextдля добавления информации к результату инструмента. Чтобы заменить выходные данные инструмента перед тем, как Claude их увидит, установитеupdatedToolOutput, который работает для любого инструмента в обоих SDK. Более старое полеupdatedMCPToolOutputзаменяет только выходные данные MCP инструмента и является устаревшим.
{} для разрешения операции без изменений. SDK callback hooks используют тот же формат вывода JSON, что и hooks команд shell Claude Code, который документирует каждое поле и опцию, специфичную для события. Для определений типов SDK см. справочники TypeScript и Python SDK.
Когда применяются несколько hooks или правил разрешений,
deny имеет приоритет над defer, который имеет приоритет над ask, который имеет приоритет над allow. Если какой-либо hook возвращает deny, операция блокируется независимо от других hooks.Асинхронный вывод
По умолчанию агент ждет, пока ваш hook вернется, прежде чем продолжить. Если ваш hook выполняет побочный эффект, такой как логирование или отправка webhook, и не нужно влиять на поведение агента, вы можете вернуть асинхронный вывод вместо этого. Это говорит агенту продолжить немедленно без ожидания завершения hook:Асинхронные выходы не могут блокировать, изменять или внедрять контекст в операцию, так как агент уже продолжил. Используйте их только для побочных эффектов, таких как логирование, метрики или уведомления.
Примеры
Изменение входных данных инструмента
Этот пример перехватывает вызовы инструмента Write и переписывает аргументfile_path для добавления префикса /sandbox, перенаправляя все записи файлов в изолированный каталог. Callback возвращает updatedInput с измененным путем и permissionDecision: 'allow' для автоматического одобрения переписанной операции:
При использовании
updatedInput вы также должны включить permissionDecision: 'allow' для автоматического одобрения измененного входа или permissionDecision: 'ask' для отображения его пользователю. С 'defer' updatedInput игнорируется. Всегда возвращайте новый объект вместо мутирования оригинального tool_input.Добавление контекста и блокировка инструмента
Этот пример блокирует записи в каталог/etc и объясняет причину как модели, так и пользователю:
permissionDecision: 'deny'останавливает вызов инструмента.permissionDecisionReasonсообщает модели причину, чтобы она избежала повторной попытки.systemMessageпоказывает пользователю, что произошло.
Автоматическое одобрение конкретных инструментов
По умолчанию агент может запросить разрешение перед использованием определенных инструментов. Этот пример автоматически одобряет инструменты файловой системы только для чтения (Read, Glob, Grep), возвращаяpermissionDecision: 'allow', позволяя им запускаться без подтверждения пользователя, в то время как оставляя все остальные инструменты подлежащими обычным проверкам разрешений:
Регистрация нескольких hooks
Когда событие срабатывает, все соответствующие hooks выполняются параллельно. Для решений о разрешениях побеждает наиболее ограничивающий результат: одноdeny блокирует вызов инструмента независимо от того, что возвращают другие hooks. Поскольку порядок завершения недетерминирован, напишите каждый hook так, чтобы он действовал независимо, а не полагаясь на то, что другой hook уже выполнился.
Пример ниже регистрирует три независимые проверки для каждого вызова инструмента:
Фильтрация с помощью multi-tool matchers
Используйте multi-tool matchers для совместного использования одного callback для связанных инструментов. Этот пример регистрирует три matcher с разными областями:- Список с разделением через трубу (
Write|Edit|Delete) срабатываетfile_security_hookтолько для инструментов модификации файлов. - Regex (
^mcp__) срабатываетmcp_audit_hookдля любого MCP инструмента, имя которого начинается сmcp__. - Пропущенный matcher срабатывает
global_loggerдля каждого вызова инструмента независимо от имени.
Отслеживание активности подагента
Используйте hooksSubagentStop для мониторинга, когда подагенты завершают свою работу. См. полный тип входных данных в справочниках TypeScript и Python SDK. Этот пример логирует сводку каждый раз, когда подагент завершается:
Выполнение HTTP запросов из hooks
Hooks могут выполнять асинхронные операции, такие как HTTP запросы. Ловите ошибки внутри вашего hook вместо того, чтобы позволить им распространяться, так как необработанное исключение может прервать агента. Этот пример отправляет webhook после завершения каждого инструмента, логируя, какой инструмент запустился и когда. Hook ловит ошибки, чтобы неудачный webhook не прерывал агента:Перенаправление уведомлений в Slack
Используйте hooksNotification для получения системных уведомлений от агента и перенаправления их во внешние сервисы. Уведомления срабатывают для типов событий, таких как:
permission_promptкогда Claude нужно разрешениеidle_promptкогда Claude ждет вводаauth_successкогда аутентификация завершенаelicitation_dialog,elicitation_completeиelicitation_responseдля потоков запроса пользователя
message с описанием, понятным человеку, и опционально title.
Этот пример перенаправляет каждое уведомление в канал Slack. Требуется URL входящего webhook Slack, который вы создаете, добавляя приложение в ваше рабочее пространство Slack и включая входящие webhooks:
Исправление распространенных проблем
Hook не срабатывает
- Проверьте, что имя события hook правильное и чувствительно к регистру (
PreToolUse, а неpreToolUse) - Проверьте, что ваш паттерн matcher точно совпадает с именем инструмента
- Убедитесь, что hook находится под правильным типом события в
options.hooks - Для non-tool hooks, которые поддерживают matchers, таких как
NotificationиSubagentStop, matchers соответствуют разным полям, иStopполностью игнорирует matchers (см. matcher patterns) - Hooks могут не срабатывать, когда агент достигает лимита
max_turns, потому что сеанс заканчивается перед тем, как hooks смогут выполниться
Matcher не фильтрует как ожидается
Matchers соответствуют только имени инструмента, а не путям файлов или другим аргументам. Для фильтрации по пути файла проверьтеtool_input.file_path внутри вашего hook:
Hook timeout
- Увеличьте значение
timeoutв конфигурацииHookMatcher - Используйте
AbortSignalиз третьего аргумента callback для корректной обработки отмены в TypeScript
UserPromptSubmit или UserPromptExpansion, который превышает свой timeout, блокирует этот запрос с сообщением timeout, и сеанс продолжается. Прерывание запроса во время ожидания callback отменяет ожидающий вызов инструмента. До версии 2.1.208 timeout callback на этих событиях завершал запрос с error_during_execution, и прерывание во время ожидания callback PreToolUse могло позволить вызову инструмента продолжиться.
Инструмент заблокирован неожиданно
- Проверьте все hooks
PreToolUseна возвращениеpermissionDecision: 'deny' - Добавьте логирование в ваши hooks, чтобы увидеть, какие
permissionDecisionReasonони возвращают - Проверьте, что паттерны matcher не слишком широкие: пустой matcher соответствует всем инструментам
Измененный входной сигнал не применяется
-
Убедитесь, что
updatedInputнаходится внутриhookSpecificOutput, а не на верхнем уровне: -
Верните
permissionDecision: 'allow'для автоматического одобрения измененного входного сигнала или'ask'для отображения его пользователю на утверждение -
Включите
hookEventNameвhookSpecificOutputдля идентификации типа hook, для которого предназначен вывод
Hooks сеанса недоступны в Python
SessionStart и SessionEnd могут быть зарегистрированы как SDK callback hooks в TypeScript, но недоступны в Python SDK, потому что его тип HookEvent их опускает. В Python они доступны только как shell command hooks, определенные в файлах настроек, таких как .claude/settings.json. Для загрузки shell command hooks из вашего приложения SDK включите соответствующий источник настроек с setting_sources или settingSources:
client.receive_response() как ваш триггер.
Запросы разрешений подагента умножаются
При порождении нескольких подагентов каждый может запросить разрешения отдельно. Подагенты не автоматически наследуют разрешения родительского агента. Чтобы избежать повторных запросов, используйте hooksPreToolUse для автоматического одобрения конкретных инструментов или настройте правила разрешений, которые применяются к сеансам подагента.
Рекурсивные циклы hook с подагентами
HookUserPromptSubmit, который порождает подагентов, может создать бесконечные циклы, если эти подагенты срабатывают тот же hook. Чтобы предотвратить это:
- Проверьте индикатор подагента во входных данных hook перед порождением
- Используйте общую переменную или состояние сеанса для отслеживания, находитесь ли вы уже внутри подагента
- Ограничьте область действия hooks, чтобы они запускались только для сеанса агента верхнего уровня
systemMessage не появляется в выводе
ПолеsystemMessage показывает сообщение пользователю, а не модели. По умолчанию SDK выводит выходные данные hook в поток сообщений только для hooks SessionStart и Setup, поэтому сообщение из любого другого события hook не появляется, если вы не установите includeHookEvents (include_hook_events в Python). Для передачи контекста модели вместо этого верните additionalContext.
Если вам нужно надежно вывести решения hook в ваше приложение, логируйте их отдельно или используйте выделенный канал вывода.
Связанные ресурсы
- Справочник hooks Claude Code: полные схемы входных/выходных данных JSON, документация событий и паттерны matcher
- Руководство hooks Claude Code: примеры hooks команд shell и пошаговые инструкции
- Справочник TypeScript SDK: типы hooks, определения входных/выходных данных и параметры конфигурации
- Справочник Python SDK: типы hooks, определения входных/выходных данных и параметры конфигурации
- Разрешения: контролируйте, что может делать ваш агент
- Пользовательские инструменты: создавайте инструменты для расширения возможностей агента