Жизненный цикл hook
Claude Code запускает hooks в определённых точках во время сеанса. Когда событие срабатывает и совпадает с фильтром, Claude Code передаёт JSON-контекст события вашему обработчику hook. Для command hooks входные данные поступают на stdin. Для HTTP hooks они поступают как тело POST-запроса. Ваш обработчик может затем проверить входные данные, выполнить действие и опционально вернуть решение. События срабатывают в трёх ритмах:- один раз за сеанс:
SessionStartиSessionEnd - один раз за ход:
UserPromptSubmit,StopиStopFailure - при каждом вызове инструмента внутри агентного цикла:
PreToolUseиPostToolUse, за исключением вызововEndConversation, которые пропускают оба
Как разрешается hook
Чтобы увидеть, как событие, фильтр и обработчик работают вместе, рассмотрим этот hookPreToolUse, который блокирует деструктивные команды оболочки.
- macOS/Linux
- Windows (PowerShell)
Фильтр Скрипт читает JSON входные данные из stdin, извлекает команду и возвращает Этот скрипт, как и другие примеры Bash на этой странице, которые анализируют JSON входные данные, использует
matcher сужает область до вызовов инструмента Bash, а условие if сужает её дальше до команд Bash, совпадающих с rm *, поэтому block-rm.sh запускается только когда оба фильтра совпадают:permissionDecision со значением "deny", если она содержит rm -rf. Сохраните его в .claude/hooks/block-rm.sh в вашем проекте и сделайте его исполняемым с помощью chmod +x .claude/hooks/block-rm.sh, чтобы Claude Code мог его запустить:jq, поэтому установите jq и убедитесь, что он находится в вашем PATH перед попыткой их использования.Bash "rm -rf /tmp/build" с конфигурацией macOS/Linux. Вот что происходит:
1
Событие срабатывает
Событие
PreToolUse срабатывает. Claude Code отправляет входные данные инструмента как JSON на stdin hook:2
Фильтр проверяет
Фильтр
"Bash" совпадает с именем инструмента, поэтому эта группа hook активируется. Если вы опустите фильтр или используете "*", группа активируется при каждом возникновении события.3
Условие if проверяет
Условие
if "Bash(rm *)" совпадает, потому что rm -rf /tmp/build — это подкоманда, совпадающая с rm *, поэтому этот обработчик запускается. Если бы команда была npm test, проверка if не удалась бы и block-rm.sh никогда не запустился бы, избегая затрат на порождение процесса. Поле if опционально; без него каждый обработчик в совпадающей группе запускается.4
Обработчик hook запускается
Скрипт проверяет полную команду и находит Если бы команда была более безопасным вариантом
rm -rf, поэтому выводит решение на stdout:rm, таким как rm file.txt, скрипт выполнил бы exit 0 вместо этого. Код выхода 0 без вывода означает, что hook не имеет решения для отчёта, поэтому вызов инструмента продолжается через нормальный поток разрешений. Hook может отклонить вызов, но молчание не одобряет его.5
Claude Code действует на основе результата
Claude Code читает JSON решение, блокирует вызов инструмента и показывает Claude причину.
Конфигурация
Hooks определяются в JSON файлах настроек. Конфигурация имеет три уровня вложенности:- Выберите hook event для ответа, например
PreToolUseилиStop - Добавьте matcher group для фильтрации срабатывания, например “только для инструмента Bash”
- Определите один или несколько hook handlers для запуска при совпадении
На этой странице используются специальные термины для каждого уровня: hook event для точки жизненного цикла, matcher group для фильтра и hook handler для команды оболочки, конечной точки HTTP, инструмента MCP, подсказки или агента, который запускается. “Hook” сам по себе относится к общей функции.
Расположение hook
Место, где вы определяете hook, определяет его область действия:
Облачные сеансы на Claude Code в веб-версии не читают ваш локальный
~/.claude/settings.json. В самостоятельно размещённой среде, Claude Code также запускает hooks, которые оператор инициализировал из ~/.claude/ хоста runner, и запускает hooks в файле управляемых параметров образа runner, когда этот файл находится среди управляемых источников, которые применяет Claude Code, что по умолчанию означает только когда ни управляемые на сервере параметры, ни доставленная MDM политика Claude Code не предоставляют управляемый уровень. См. что переносится из вашей установки для того, какие файлы настроек и плагины, и таким образом какие hooks, достигают облачного сеанса.
Для получения подробной информации о разрешении файлов настроек см. settings.
Hooks из файлов настроек, управляемых параметров политики и плагинов также запускаются внутри subagents. Когда subagent вызывает инструмент, события инструмента, такие как PreToolUse и PostToolUse, запускают те же настроенные hooks, что и в основном разговоре, и входные данные содержат поля agent_id и agent_type общих входных полей, которые идентифицируют subagent.
Администраторы предприятия могут использовать allowManagedHooksOnly для ограничения того, какие hooks запускаются:
- Ваши пользовательские, проектные, локальные и плагинные hooks блокируются. Hooks из плагинов, принудительно включённых в управляемых параметрах
enabledPlugins, исключены - Claude Code также сужает ваши параметры
statusLine,fileSuggestionиsubagentStatusLineдо управляемых параметров - Claude Code также отключает плагины с источником
command, включая плагины, принудительно включённые в управляемых параметрахenabledPlugins, если толькоdisableCommandPluginSourcesявно не установлен наfalse. Источникиcommandтребуют Claude Code v2.1.229 или позже - Claude Code также блокирует команды marketplace
headersHelperесли толькоdisableCommandPluginSourcesявно не установлен наfalse, за исключением marketplace, которые сами управляемые параметры объявляют
allowManagedHooksOnly.
Hook записи объединяются на уровнях параметров, а не заменяют друг друга: пользовательские, проектные и локальные параметры добавляют свои собственные hooks без удаления управляемых, и параметр disableAllHooks не может отключить управляемые hooks извне управляемых параметров.
HTTP hook allowlists применяются к hooks из каждого источника, включая управляемые параметры политики:
allowedHttpHookUrls: когда определено на любом уровне параметров, Claude Code запускает обработчик HTTP hook только если его URL совпадает с объединённым allowlisthttpHookAllowedEnvVars: когда определено, Claude Code интерполирует только переменные окружения из этого списка в заголовки hook
Matcher patterns
Полеmatcher фильтрует срабатывание hooks. Способ оценки фильтра зависит от содержащихся в нём символов:
Фильтр на пути регулярного выражения проверяется с помощью
RegExp.prototype.test JavaScript, который успешно совпадает в любом месте значения. Edit.* совпадает как с Edit, так и с NotebookEdit; оберните шаблон в ^ и $, как в ^Edit$, когда вам нужно совпадение всей строки.
Дефисы в наборе точного совпадения требуют Claude Code v2.1.195 или позже. На более ранних версиях дефисное имя, такое как code-reviewer, оценивается как регулярное выражение без привязки, поэтому оно также срабатывает для senior-code-reviewer; закрепите его как ^code-reviewer$ на этих версиях, чтобы совпадать только с этим именем.
FileChanged и StopFailure используют более узкий набор точного совпадения только букв, цифр, _ и |. Дефис, пробел или запятая в фильтре для этих двух событий держит его на пути регулярного выражения, и только | разделяет альтернативы. Каждое другое событие с поддержкой фильтра в таблице ниже принимает | или ,.
Событие FileChanged не следует этим правилам при построении своего списка наблюдения. См. FileChanged.
Каждый тип события совпадает с другим полем:
Совпадение
StopFailure на cloud_credential_error требует Claude Code v2.1.267 или позже, первой версии, которая сообщает об ошибках загрузки учётных данных под этим значением вместо server_error или unknown.
Для большинства событий Claude Code оценивает фильтр против поля из JSON входа, который он отправляет вашему hook на stdin. Для событий инструмента это поле — tool_name. Для PreModelSwitch и PostModelSwitch, Claude Code оценивает фильтр против канонического имени, которое он выводит из to_model, как описано в PreModelSwitch. Каждый раздел hook event перечисляет полный набор значений фильтра и схему входа для этого события.
Этот пример запускает скрипт линтинга только когда Claude пишет или редактирует файл:
matcher к событию без поддержки фильтра, оно будет молча проигнорировано.
Для событий инструмента вы можете фильтровать более узко, установив поле if на отдельных обработчиках hook. if использует синтаксис правила разрешения для совпадения с именем инструмента и аргументами вместе, поэтому "Bash(git *)" запускается когда любая подкоманда входа Bash совпадает с git * и "Edit(*.ts)" запускается только для файлов TypeScript.
Match MCP tools
MCP server инструменты отображаются как обычные инструменты в событиях инструментов (PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied), поэтому вы можете совпадать с ними так же, как с любым другим именем инструмента.
MCP инструменты следуют шаблону именования mcp__<server>__<tool>, например:
mcp__memory__create_entities: инструмент create entities сервера Memorymcp__filesystem__read_file: инструмент read file сервера Filesystemmcp__github__search_repositories: инструмент поиска сервера GitHub
.* к префиксу сервера. .* требуется: фильтр, такой как mcp__memory или mcp__brave-search, содержит только символы точного совпадения, поэтому он сравнивается как точная строка и не совпадает ни с одним инструментом.
mcp__memory__.*совпадает со всеми инструментами сервераmemorymcp__brave-search__.*совпадает со всеми инструментами с сервера, чьё имя содержит дефисmcp__.*__write.*совпадает с любым инструментом, чьё имя начинается сwriteиз любого сервера
mcp__brave-search, оценивается как регулярное выражение без привязки и совпадает с каждым инструментом с этого сервера. Форма mcp__brave-search__.* работает на каждой версии.
Инструменты из plugin-bundled MCP server используют сегмент сервера с областью, который включает имя плагина: mcp__plugin_<plugin-name>_<server-name>__<tool>. Фильтр, написанный против голого ключа сервера, никогда не срабатывает для этих инструментов. Для плагина с именем my-plugin, который объединяет сервер под ключом db, инструмент query отображается как mcp__plugin_my-plugin_db__query, поэтому фильтр для каждого инструмента с этого сервера — mcp__plugin_my-plugin_db__.*. Используйте то же имя инструмента с областью в поле if обработчика. См. Plugin-provided MCP servers для того, как строится имя с областью.
Этот пример логирует все операции сервера memory и проверяет операции записи из любого MCP сервера:
Hook handler fields
Каждый объект во внутреннем массивеhooks — это hook handler: команда оболочки, конечная точка HTTP, инструмент MCP, подсказка LLM или агент, который запускается при совпадении фильтра. Есть пять типов:
- Command hooks (
type: "command"): запускают команду оболочки. Ваш скрипт получает JSON входные данные события на stdin и передаёт результаты обратно через коды выхода и stdout. - HTTP hooks (
type: "http"): отправляют JSON входные данные события как HTTP POST запрос на URL. Конечная точка передаёт результаты обратно через тело ответа, используя тот же JSON формат выхода, что и command hooks. - MCP tool hooks (
type: "mcp_tool"): вызывают инструмент на уже подключённом MCP сервере. Текстовый вывод инструмента обрабатывается как stdout command hook. - Prompt hooks (
type: "prompt"): отправляют подсказку модели Claude для однооборотной оценки. Модель возвращает решение как JSON. См. Prompt-based hooks. - Agent hooks (
type: "agent"): порождают subagent, который может использовать инструменты, такие как Read, Grep и Glob, для проверки условий перед возвратом решения. Agent hooks являются экспериментальными и могут измениться. См. Agent-based hooks.
$CLAUDE_CODE_REMOTE устанавливается на "true" в удалённых веб-окружениях и не устанавливается в локальном CLI. Claude Code v2.1.199 и позже устанавливает $CLAUDE_CODE_BRIDGE_SESSION_ID на ID сеанса Remote Control пока локальный сеанс имеет активное соединение Remote Control.
Common fields
Эти поля применяются ко всем типам hooks:
Поле
if содержит ровно одно правило разрешения. Нет синтаксиса &&, || или списка для объединения правил; чтобы применить несколько условий, определите отдельный обработчик hook для каждого.
В условии if для инструмента файла, шаблон каталога с одним сегментом, такой как "Edit(src/**)", совпадает только с каталогом src в рабочем каталоге и файлами под ним. Чтобы совпадать с каталогом с именем src на любой глубине, напишите "Edit(**/src/**)". До v2.1.214, "Edit(src/**)" совпадал с каталогом с именем src на любой глубине под рабочим каталогом.
Для Bash шаблонов, запускается ли ваша команда hook зависит от формы шаблона и команды Bash, которую вызывает Claude. Ведущие присваивания VAR=value удаляются перед совпадением.
Когда Claude Code не может определить, какие команды запускает входные данные Bash, он запускает ваш hook независимо от шаблона. Поскольку фильтр
if является лучшим усилием, используйте систему разрешений вместо hook для обеспечения жёсткого разрешения или отказа.
Command hook fields
В дополнение к общим полям, command hooks принимают эти поля:
Command hook запускается в exec form когда установлен
args, и в shell form когда args опущен. Установите args всякий раз, когда hook ссылается на path placeholder, так как каждый элемент передаётся как один аргумент без кавычек. Опустите args когда вам нужны функции оболочки, такие как pipes или &&, или когда ни одна из этих проблем не применяется.
Exec form запускается когда присутствует args. Claude Code разрешает command как исполняемый файл на PATH и запускает его напрямую с args как вектор аргументов. Нет оболочки, поэтому каждый элемент args — это ровно один аргумент, написанный как есть, и path placeholders, такие как ${CLAUDE_PLUGIN_ROOT}, подставляются в command и в каждый элемент args как простые строки. Специальные символы, такие как апострофы, $ и обратные кавычки, проходят дословно, потому что нет оболочки для их интерпретации. На любой платформе не происходит никакой токенизации оболочки.
Shell form запускается когда args отсутствует. Строка command передаётся в оболочку: sh -c на macOS и Linux, Git Bash на Windows, или PowerShell когда Git Bash не установлен. Установите поле shell для явного выбора. Оболочка токенизирует строку, расширяет переменные и интерпретирует pipes, &&, redirects и globs.
На Windows, exec form требует, чтобы
command разрешался в реальный исполняемый файл, такой как .exe. Shims .cmd и .bat, которые npm, npx, eslint и другие инструменты устанавливают в node_modules/.bin, не являются исполняемыми файлами и не могут быть запущены без оболочки. Чтобы запустить их в exec form, вызовите базовый скрипт с node напрямую, например "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/node_modules/eslint/bin/eslint.js"]. Паттерн node плюс script-path работает на каждой платформе, потому что node.exe — это реальный бинарный файл. Чтобы запустить shim .cmd или .bat по имени, используйте shell form.CLAUDE_PROJECT_DIR, CLAUDE_PLUGIN_ROOT и CLAUDE_PLUGIN_DATA на порождённом процессе, поэтому скрипт может читать process.env.CLAUDE_PLUGIN_ROOT независимо от того, как он был запущен.
Plugin hooks дополнительно подставляют значения ${user_config.*}, только в exec form: значение подставляется в command и в каждый элемент args как простая строка, поэтому оболочка не переанализирует его.
Shell-form plugin hook, чей command ссылается на ${user_config.*}, завершается с ошибкой вместо запуска. Чтобы использовать значение опции из shell-form hook, прочитайте переменную окружения $CLAUDE_PLUGIN_OPTION_<KEY>, такую как $CLAUDE_PLUGIN_OPTION_WEBHOOK_URL для опции webhook_url, или установите args для переключения hook на exec form. До v2.1.207, shell-form plugin hook команды также подставляли ${user_config.*}.
В exec form,
command — это только имя исполняемого файла или путь. Если command — это голое имя без разделителя пути и содержит пробелы рядом с args, Claude Code логирует предупреждение, потому что spawn не удастся: нет исполняемого файла с именем node script.js. Переместите дополнительные токены в args. Абсолютные пути с пробелами, такие как C:\Program Files\nodejs\node.exe, — это один действительный исполняемый файл и не вызывают предупреждение.HTTP hook fields
В дополнение к общим полям, HTTP hooks принимают эти поля:
Claude Code отправляет JSON входные данные hook как тело POST запроса с
Content-Type: application/json. Тело ответа использует тот же JSON формат выхода, что и command hooks.
Обработка ошибок отличается от command hooks; см. HTTP response handling.
Этот пример отправляет события PreToolUse на локальный сервис валидации, аутентифицируясь с токеном из переменной окружения MY_TOKEN:
MCP tool hook fields
В дополнение к общим полям, MCP tool hooks принимают эти поля:
Этот пример вызывает инструмент
security_scan на MCP сервере my_server после каждого Write или Edit, передавая путь отредактированного файла:
isError: true, hook производит неблокирующую ошибку и выполнение продолжается.
На событиях, где hook может блокировать или изменять результат, такие как PreToolUse или Stop, Claude Code ждёт подключения сервера перед вызовом инструмента, максимум MCP_TIMEOUT и в пределах собственного timeout hook. На наблюдательных событиях, таких как Notification или SessionEnd, он не ждёт.
Сервер, показывающий статус cached, подключается, когда hook вызывает его инструмент. Если сервер не подключён в этот момент, hook производит неблокирующую ошибку и выполнение продолжается. Hook никогда не запускает поток OAuth, поэтому аутентифицируйте сервер из /mcp сначала.
SessionStart при запуске, включая с --continue или --resume, и каждое событие Setup срабатывают перед доступностью MCP серверов сеанса для hooks. Claude Code пропускает их mcp_tool hooks без вызова инструмента, и debug log записывает mcp_tool hooks are not available for the 'SessionStart' hook event (no MCP client context), или то же сообщение, называющее Setup. Когда SessionStart срабатывает снова позже в сеансе, после /clear или компактирования, его mcp_tool hooks запускаются. Для всего, что сеансу нужно при запуске, используйте type: "command" hook на SessionStart вместо этого.
Prompt and agent hook fields
В дополнение к общим полям, prompt и agent hooks принимают эти поля:Reference scripts by path
Используйте эти заполнители для ссылки на скрипты hook относительно корня проекта или плагина, независимо от рабочего каталога при запуске hook:${CLAUDE_PROJECT_DIR}: корень проекта, где сеанс начался. Claude Code также устанавливает эту переменную в окружении stdio MCP серверов и plugin LSP серверов.${CLAUDE_PLUGIN_ROOT}: каталог установки плагина, для скриптов, поставляемых с плагином. См. plugin environment variables для того, как путь ведёт себя при обновлениях.${CLAUDE_PLUGIN_DATA}: каталог постоянных данных плагина, для зависимостей и состояния, которые должны пережить обновления плагина.
Worktrees отличаются. Если Claude входит в worktree во время сеанса, Claude Code держит
${CLAUDE_PROJECT_DIR} там, где он был, и передаёт путь worktree вашим hooks другим способом:${CLAUDE_PROJECT_DIR}остаётся на месте: он всё ещё указывает на корень проекта, где сеанс начался, поэтому команда, такая как${CLAUDE_PROJECT_DIR}/.claude/hooks/check-style.sh, всё ещё запускает скрипт в основной checkout.cwdследует за Claude: полеcwdв входных JSON hook — это корень worktree после того, как Claude входит в worktree, и новый каталог после того, как Claude запускаетcd. Прочитайте его, когда hook нужно знать, в каком каталоге Claude работает.
- Project scripts
- Plugin scripts
Этот пример использует
${CLAUDE_PROJECT_DIR} для запуска проверки стиля из каталога .claude/hooks/ проекта после любого вызова инструмента Write или Edit:Hooks in skills and agents
В дополнение к файлам настроек и плагинам, hooks могут быть определены непосредственно в skills и subagents с использованием frontmatter, в том же формате конфигурации, что и hooks на основе настроек. Как долго Claude Code их регистрирует, зависит от компонента:- Subagent hooks: Claude Code запускает их только пока этот subagent работает и удаляет их, когда он завершается. Claude Code преобразует hook
Stopздесь вSubagentStop, событие, которое срабатывает при завершении subagent. - Skill hooks: Claude Code регистрирует их, когда вы или Claude вызываете skill, и продолжает запускать их для остатка сеанса, на ходах после собственного хода skill. Чтобы Claude Code удалил hook после его первого успешного запуска вместо этого, установите
once: trueна нём.
PreToolUse, который запускает скрипт проверки безопасности перед каждой командой Bash:
-p в папке, которую вы не доверяли.
Frontmatter hooks в project subagent запускаются только после того, как вы примете диалог доверия рабочей области для папки, из которой пришёл файл агента. Сеанс -p не считается принятием. Что запускается перед тем, как вы доверяете папке сравнивает это с правилом файла настроек, и страница subagents перечисляет какие области исключены. До v2.1.218, эти hooks могли запускаться из папок, которым вы не доверяли.
Меню /hooks
Введите /hooks в Claude Code, чтобы открыть браузер только для чтения ваших настроенных hooks. Меню показывает каждое hook событие с количеством настроенных hooks, позволяет вам углубиться в фильтры и показывает полные детали каждого hook обработчика. Используйте его для проверки конфигурации, проверки того, из какого файла настроек пришёл hook, или проверки команды, подсказки или URL hook.
Меню отображает все пять типов hook: command, prompt, agent, http и mcp_tool. Каждый hook помечен префиксом [type] и источником, указывающим, где он был определён:
User Settings: из~/.claude/settings.jsonProject Settings: из.claude/settings.jsonLocal Settings: из.claude/settings.local.jsonPlugin Hooks: изhooks/hooks.jsonплагинаSession Hooks: зарегистрирован в памяти для текущего сеанса
Отключение или удаление hooks
Чтобы удалить hook, удалите его запись из JSON файла настроек. Чтобы временно отключить все hooks без их удаления, установите"disableAllHooks": true в файле настроек. Claude Code читает значение, оставшееся после применения приоритета параметров, поэтому "disableAllHooks": false в .claude/settings.json проекта переопределяет true в ваших пользовательских параметрах. Чтобы отключить hooks для одного запуска, независимо от того, что говорят параметры проекта, передайте --settings '{"disableAllHooks": true}', что имеет приоритет над параметрами проекта и локальными параметрами. Нет способа отключить отдельный hook, сохраняя его в конфигурации.
Параметр disableAllHooks соблюдает иерархию управляемых параметров. Если администратор настроил hooks через управляемые параметры политики, disableAllHooks, установленный в пользовательских, проектных или локальных параметрах, не может отключить эти управляемые hooks. Только disableAllHooks, установленный на уровне управляемых параметров, может отключить управляемые hooks. Для полного охвата каждого уровня см. disableAllHooks.
Прямые редактирования hooks в файлах настроек обычно захватываются автоматически наблюдателем файлов.
Входные и выходные данные Hook
Hooks команд получают JSON-данные через stdin и передают результаты через коды выхода, stdout и stderr. HTTP hooks получают тот же JSON, что и тело POST-запроса, и передают результаты через тело HTTP-ответа. В этом разделе рассматриваются поля и поведение, общие для всех событий. Каждый раздел события в разделе Hook events включает его конкретную схему входных данных и параметры управления решением. На macOS и Linux hooks команд запускаются в собственном сеансе без управляющего терминала. Процесс hook и любые дочерние процессы не могут открыть/dev/tty или отправлять последовательности escape непосредственно в интерфейс Claude Code. Windows не имеет /dev/tty.
Чтобы вывести сообщение пользователю на любой платформе, верните systemMessage в JSON-выводе. Некоторые события игнорируют его или доставляют его в другое место, и в каждом разделе события указано, как это происходит. Чтобы вызвать уведомление рабочего стола, установить заголовок окна или издать звуковой сигнал, верните terminalSequence вместо этого.
Общие входные поля
Hook события получают эти поля в виде JSON в дополнение к полям, специфичным для события, задокументированным в каждом разделе hook event. Для hooks команд этот JSON поступает через stdin. Для HTTP hooks он поступает как тело POST-запроса.
При запуске с
--agent или внутри subagent включаются два дополнительных поля:
Только hooks
SessionStart могут получить поле model, и Claude Code не всегда его включает. Hooks PreModelSwitch и PostModelSwitch получают from_model и to_model вместо этого, поэтому используйте hook PostModelSwitch для отслеживания модели по мере ее изменения во время сеанса.
Нет переменной окружения $CLAUDE_MODEL. Hook может читать $ANTHROPIC_MODEL, если вы установили ее в своей оболочке, но это значение не изменяется при переключении моделей с помощью /model во время сеанса.
Процесс hook наследует родительское окружение, за исключением переменных экспортера OTEL_*, которые Claude Code удаляет из каждого подпроцесса, который он порождает, и, когда установлена CLAUDE_CODE_SUBPROCESS_ENV_SCRUB в 1, переменные, которые он удаляет.
Например, hook PreToolUse для команды Bash получает это на stdin:
tool_name, tool_input и tool_use_id специфичны для события. Каждый раздел hook event документирует дополнительные поля для этого события.
Выходные коды выхода
Код выхода из вашей команды hook сообщает Claude Code, должно ли действие продолжаться, быть заблокировано или игнорироваться. Код выхода не действует в одиночку. Claude Code читает поля JSON output из stdout при каждом коде выхода, не только 0, и для событий, которые используют стандартную модель решения, проанализированный объект, который проходит валидацию схемы, вступает в силу наряду с кодом. Блокировка Exit 2 — это единственный результат, который JSON не может переопределить. Две таблицы владеют исключениями для каждого события: Exit code 2 behavior per event говорит, что коды выхода делают для каждого события, и Decision control говорит, какие поля решения каждое событие учитывает. Универсальные поля, такие какsystemMessage, работают на большинстве событий и перечислены в таблице JSON output.
Exit code 0
Exit 0 означает успех и является предполагаемым кодом выхода, когда вы печатаете JSON для структурированного управления. Для большинства событий Claude Code записывает stdout в журнал отладки и не показывает его в транскрипте. Исключения — этоUserPromptSubmit, UserPromptExpansion, SessionStart и PostModelSwitch, где Claude Code добавляет простой текст stdout как контекст, который Claude может видеть и действовать.
Читает ли Claude Code ваш stdout как JSON output или как простой текст, зависит от того, как он начинается и заканчивается, игнорируя окружающие пробелы:
- Начинается с
{и заканчивается на}: Claude Code анализирует его как JSON. Когда выход состоит из двух или более строк, которые каждая анализируются как JSON самостоятельно, и ни одна строка не является объектом JSON output, который устанавливает поле, Claude Code рассматривает весь выход как простой текст. Когда одна из этих строк устанавливает поле, весь выход является ошибкой анализа, описанной ниже. - Начинается с
{но не заканчивается на}: Claude Code рассматривает это как простой текст. - Начинается с чего-либо еще: Claude Code рассматривает это как простой текст, JSON массив или включенную строку JSON в кавычках.
<hook name> hook error с сообщением валидации. То же самое происходит при любом коде выхода, отличном от 2, в то время как exit 2 все еще блокирует.
Для событий, которые используют стандартную модель решения, когда Claude Code пытается анализировать ваш stdout как JSON и не может, он сообщает о неблокирующей ошибке при каждом коде выхода, отличном от 2. Транскрипт показывает уведомление об ошибке <hook name> hook error с сообщением анализа. На событиях, которые добавляют простой текст stdout как контекст, Claude Code не добавляет текст. До v2.1.248 Claude Code рассматривал этот stdout как простой текст.
Stderr из hook, который выходит с 0, идет только в журнал отладки, никогда в транскрипт, и Claude его не видит. Чтобы прочитать его самостоятельно, включите debug logging. Чтобы вывести предупреждение Claude из hook PostToolUse или PostToolUseFailure, выйдите с 2 вместо этого, чтобы Claude видел stderr, даже если инструмент уже запустился.
Exit code 2
Exit 2 означает блокирующую ошибку. На событиях, которые могут блокировать, exit 2 блокирует независимо от того, печатаете ли вы JSON: даже JSONpermissionDecision из "allow" не может его переопределить. Claude Code все еще читает любой действительный JSON output на stdout. На Elicitation и ElicitationResult, hookSpecificOutput hook с exit-2 игнорируется.
Сообщение блокировки — это причина из решения блокировки вашего JSON, когда оно его делает, и ваш текст stderr в противном случае. Что делает блокировка, варьируется в зависимости от события: PreToolUse блокирует вызов инструмента, UserPromptSubmit отклоняет запрос и так далее. Exit code 2 behavior per event перечисляет эффект для каждого события, и каждый раздел события говорит, куда идет сообщение.
Hook, который выходит с 2 при печати JSON, который не проходит валидацию схемы JSON output, все еще блокирует: Claude Code использует stderr как причину блокировки и записывает ошибку валидации в журнал отладки. До v2.1.214 Claude Code рассматривал эту комбинацию как неблокирующую ошибку и действие продолжалось.
Этот скрипт блокирует команды rm, выходя с 2 и оставляет каждую другую команду нормальному потоку разрешений:
Другие коды выхода
Любой другой код выхода не блокирует сам по себе для большинства hook событий. Что происходит, зависит от вашего stdout:- С проанализированным объектом, который проходит валидацию схемы, для событий, которые используют стандартную модель решения, Claude Code игнорирует код выхода и только JSON решает результат:
- Каждое поле, которое событие поддерживает, учитывается, включая
permissionDecision,additionalContext,updatedInputиsystemMessage, и hook не сообщается как ошибка. - Decision control перечисляет поля решения для каждого события; универсальные поля, такие как
systemMessage, следуют таблице JSON output.
- Каждое поле, которое событие поддерживает, учитывается, включая
- С проанализированным объектом, который не проходит валидацию схемы, для событий, которые используют стандартную модель решения, это то же самое неблокирующее ошибка, что и на exit 0: действие продолжается, и уведомление
<hook name> hook errorсодержит сообщение валидации. - С stdout, который Claude Code пытается анализировать как JSON и не может, Claude Code сообщает о той же неблокирующей ошибке, что и на exit 0 для событий, которые используют стандартную модель решения. Действие продолжается, и уведомление содержит сообщение анализа.
- С stdout, который Claude Code рассматривает как простой текст, или с пустым stdout, это неблокирующая ошибка для большинства hook событий: действие продолжается, и транскрипт показывает уведомление об ошибке
<hook name> hook error, за которым следует первая строка stderr, с префиксомFailed with non-blocking status code:. Чтобы захватить полный stderr, включите debug logging.
WorktreeCreate не создает при любом ненулевом выходе, независимо от того, что говорит ваш JSON, и события, которые полностью игнорируют выход hook, такие как StopFailure, игнорируют ваш JSON при каждом коде выхода, кроме полей побочных эффектов, таких как terminalSequence, которые все еще срабатывают.
Hook, который не может запуститься, попадает в ту же неблокирующую корзину. Когда путь скрипта не существует или не исполняемый, оболочка выходит с кодом, например 127, и вы видите то же уведомление с сообщением интерпретатора, например Failed with non-blocking status code: /bin/sh: /path/to/hook.sh: No such file or directory. Для большинства hook событий действие продолжается. Когда вы устанавливаете hook политики, следите за этим уведомлением при его первом запуске: неправильно введенный путь в settings.json оставляет ворота молча отключенными.
Timeouts
Кроме hook команды, который вы запускаете сasync: true, Claude Code отменяет hook command, http или mcp_tool, который достигает своего timeout, отбрасывая выход hook, поэтому на большинстве событий истекший по времени hook не отображает решение.
На PreModelSwitch, hook, отмененный при его timeout, блокирует переключение модели. На PreToolUse две семьи hook отличаются:
- Истекший по времени hook
command,httpилиmcp_toolне блокирует вызов инструмента. Вызов продолжается через нормальный поток разрешений, поэтому не рассчитывайте на зависший hook, чтобы действовать как ворота. - Agent SDK callback hook, который превышает свой timeout, блокирует вызов инструмента.
Exit code 2 behavior per event
Exit code 2 — это способ, которым hook сигнализирует “стоп, не делай этого”. Эффект зависит от события, потому что некоторые события представляют действия, которые могут быть заблокированы (например, вызов инструмента, который еще не произошел), а другие представляют вещи, которые уже произошли или не могут быть предотвращены.
Для
SessionStart, SubagentStart и PostModelSwitch, Claude Code отображает stderr exit code 2 в транскрипте как уведомление об ошибке <hook name> hook error, так же как оно отображает неблокирующую ошибку. Claude его не видит, и сеанс или subagent продолжается. Для SubagentStart уведомление появляется в собственном транскрипте subagent, а не в родительском разговоре.
HTTP response handling
HTTP hooks используют коды состояния HTTP и тела ответов вместо кодов выхода и stdout. Результаты ниже применяются к большинству событий; событие с его собственным контрактом отказа в таблице для каждого события, такое какWorktreeCreate, применяет этот контракт к неудачному HTTP hook также:
- 2xx с пустым телом: успех, эквивалентно exit code 0 без выхода
- 2xx с телом объекта JSON: анализируется с использованием той же схемы JSON output, что и hooks команд. Тело, которое не проходит валидацию схемы, является неблокирующей ошибкой
- 2xx с любым другим телом, таким как простой текст: неблокирующая ошибка, обрабатывается так же, как статус non-2xx. Claude Code не добавляет текст в контекст Claude
- Статус non-2xx: неблокирующая ошибка, выполнение продолжается
- Ошибка соединения: неблокирующая ошибка, выполнение продолжается
- Timeout: hook отменяется, как описано в разделе Timeouts
JSON output
Коды выхода позволяют вам только блокировать или молчать, но JSON output дает вам более точное управление. Вместо выхода с кодом 2 для блокировки, выйдите с 0 и напечатайте объект JSON на stdout. Claude Code читает конкретные поля из этого JSON для управления поведением, включая decision control для блокировки, разрешения или эскалации пользователю.Выберите один подход для каждого hook: либо используйте коды выхода только для сигнализации, либо выйдите с 0 и напечатайте JSON для структурированного управления. Если вы их смешиваете, exit 2 сохраняет свой блокирующий эффект, и Claude Code все еще читает поля JSON, с единственным исключением elicitation, отмеченным в разделе Exit code 2.
additionalContext, systemMessage и initialUserMessage hook, а также его простой stdout, ограничены 10 000 символов:
- Область: Claude Code измеряет каждую строку отдельно, даже когда несколько hooks запускаются для одного события. Для JSON output каждое поле измеряется отдельно; простой stdout измеряется целиком.
- Превышение лимита: Claude Code сохраняет выход в файл в каталоге сеанса и заменяет его путем к файлу и предпросмотром до первых 2000 символов. Большой действительный результат Bash обрабатывается так же, как описано в разделе Output limits. В отличие от этого потолка Bash, эта крышка не имеет параметра или переменной окружения для ее повышения.
- Чтение файла: Claude Code не просит Claude прочитать файл, поэтому держите все, что Claude должен всегда видеть, в пределах крышки.
- Универсальные поля, такие как
continue, перечислены в таблице ниже. Каждое событие их принимает, но некоторые события игнорируют их или доставляютsystemMessageв другое место, чем транскрипт. Каждый раздел события говорит об этом.terminalSequenceработает на этих событиях также, с исключениями, перечисленными в разделе Emit terminal notifications. - Top-level
decisionиreasonиспользуются некоторыми событиями для блокировки или предоставления обратной связи. hookSpecificOutput— это вложенный объект для событий, которым нужно более богатое управление. Он требует полеhookEventName, установленное на имя события.
Чтобы полностью остановить Claude:
PreToolUse и PostToolUse остановка применяется даже когда вызов инструмента не удается или завершается, пока Claude все еще потоком ответ.
Emit terminal notifications
Hooks запускаются без управляющего терминала, поэтому запись последовательностей escape непосредственно в/dev/tty не удается. Вместо этого верните последовательность escape в поле terminalSequence и Claude Code выпустит ее от вашего имени через свой собственный путь записи терминала. Это свободно от гонок, работает внутри tmux и GNU screen, и работает на Windows, где нет /dev/tty.
Поле принимает строку из одной или нескольких последовательностей escape в списке разрешений:
- OSC
0,1,2: заголовки окна и значков - OSC
9: уведомления iTerm2, ConEmu, Windows Terminal и WezTerm, включая прогресс панели задач9;4 - OSC
99: уведомления Kitty - OSC
777: уведомления urxvt, Ghostty и Warp - Bare BEL
systemMessage и continue, такие как Notification и StopFailure. Оно имеет два ограничения:
- Claude Code выпускает последовательность только в интерактивном сеансе и только пока его интерфейс находится на экране. В неинтерактивном режиме с флагом
-pи в Agent SDK он игнорирует поле. - Hook команды
WorktreeCreateне может вернуть JSON, потому что Claude Code читает его stdout как путь worktree. HTTP hookWorktreeCreateвозвращает JSON и может включать поле.
Notification. Последовательность escape строится с помощью printf восьмеричных escape, поэтому управляющие байты никогда не появляются в командной строке оболочки, и jq -n --arg строит выход JSON, поэтому кавычки, обратные слэши и новые строки в сообщении уведомления правильно экранируются:
{ "terminalSequence": "..." } одинакова из любой оболочки или языка.
Add context for Claude
ПолеadditionalContext передает строку из вашего hook в контекстное окно Claude. Claude Code оборачивает строку в напоминание системы и вставляет ее в разговор в точке, где сработал hook. Claude читает напоминание при следующем запросе модели, но оно не появляется как сообщение чата в интерфейсе.
Верните additionalContext внутри hookSpecificOutput рядом с именем события:
- SessionStart и SubagentStart: в начале разговора, перед первым запросом
- UserPromptSubmit и UserPromptExpansion: рядом с отправленным запросом
- PreToolUse, PostToolUse, PostToolUseFailure и PostToolBatch: рядом с результатом инструмента
- Stop и SubagentStop: в конце хода. Разговор продолжается, поэтому Claude может действовать на обратную связь. См. Stop decision control
- PostModelSwitch: со следующим запросом после переключения. См. PostModelSwitch decision control для синхронизации
additionalContext для одного события, Claude получает все значения.
Если значение превышает 10 000 символов, Claude Code записывает текст в файл в каталоге сеанса и передает Claude путь к файлу с предпросмотром до первых 2000 символов вместо этого. Claude может прочитать файл, но Claude Code не просит его.
Используйте additionalContext для информации, которую Claude должен знать о текущем состоянии вашей среды или операции, которая только что запустилась:
- Состояние среды: текущая ветвь, цель развертывания или активные флаги функций
- Условные правила проекта: какая команда теста применяется к только что отредактированному файлу, какие каталоги доступны только для чтения в этом worktree
- Внешние данные: открытые проблемы, назначенные вам, недавние результаты CI, контент, полученный из внутреннего сервиса
bun test”, читается как информация о проекте. Текст, сформулированный как внеполосные системные команды, может вызвать защиту Claude от инъекций подсказок, что заставляет Claude вывести текст вам вместо того, чтобы рассматривать его как контекст.
Claude Code сохраняет введенный текст в транскрипте сеанса. Для событий середины сеанса, таких как PostToolUse или UserPromptSubmit, когда вы возобновляете с --continue или --resume, Claude Code воспроизводит сохраненный текст, а не повторно запускает hook для прошлых ходов, поэтому значения, такие как временные метки или SHA коммитов, становятся устаревшими. Hooks SessionStart запускаются снова при возобновлении с source, установленным на "resume", или "fork", если вы добавили --fork-session, поэтому они могут обновить свой контекст.
Decision control
Не каждое событие поддерживает блокировку или управление поведением через JSON. События, которые это делают, каждое использует другой набор полей для выражения этого решения. Используйте эту таблицу как быструю ссылку перед написанием hook:
Несколько событий также могут переписывать контент, а не только разрешать или блокировать его:
PreToolUse:updatedInputнепосредственно подhookSpecificOutputзаменяет аргументы инструмента перед его запуском. См. PreToolUse decision controlPermissionRequest:updatedInputвнутри объектаdecision. См. PermissionRequest decision controlPostToolUse:updatedToolOutputзаменяет результат инструмента. См. PostToolUse decision controlUserPromptSubmit: не может переписать запрос; он только вводитadditionalContextрядом с ним
PreToolUse для исходящих входов инструмента и PostToolUse для входящих результатов инструмента.
Вот примеры каждого паттерна в действии:
- Top-level decision
- PreToolUse
- PermissionRequest
Единственное значение для
decision — это "block". Чтобы разрешить действию продолжаться, опустите decision из вашего JSON или выйдите с 0 без какого-либо JSON вообще:События hooks
Каждое событие соответствует точке в жизненном цикле Claude Code, где могут выполняться hooks. Разделы ниже упорядочены в соответствии с жизненным циклом: от настройки сеанса через агентский цикл к завершению сеанса. Каждый раздел описывает, когда срабатывает событие, какие matchers оно поддерживает, какой JSON-ввод оно получает и как управлять поведением через вывод.SessionStart
Запускается, когда Claude Code начинает новый сеанс или возобновляет существующий сеанс. Полезно для загрузки контекста разработки, такого как существующие проблемы или недавние изменения в вашей кодовой базе, или для установки переменных окружения. Для статического контекста, который не требует скрипта, используйте вместо этого CLAUDE.md. SessionStart запускается в каждом сеансе, поэтому держите эти hooks быстрыми. Поддерживаются только hookstype: "command" и type: "mcp_tool". См. MCP tool hook fields для информации о том, когда выполняются hooks mcp_tool.
Значение matcher соответствует тому, как был инициирован сеанс:
До версии 2.1.214 разветвленные сеансы сообщали источник
"resume".
Когда вы запускаете интерактивный сеанс, возобновляете разговор при запуске с --continue или --resume или запускаете /clear, hooks SessionStart выполняются в фоновом режиме. Вы можете сразу же печатать, и возобновленный разговор появляется без ожидания hooks. Первый ответ Claude все еще ждет завершения hooks, поэтому их контекст достигает Claude.
Когда вы переключаете разговоры с /resume внутри сеанса, переключение ждет завершения hooks. Если вы запустите /clear или переключитесь на другой разговор, пока фоновые hooks все еще выполняются, ничего из того, что они возвращают, не применяется к сеансу.
То же самое ожидание применяется при запуске, включая возобновленный сеанс: подсказка, которую вы отправляете, пока hooks SessionStart все еще выполняются, не достигает Claude до их завершения.
Во время любого ожидания нажмите Esc, чтобы вернуть подсказку в ввод без отправки. Hooks продолжают выполняться.
Ввод SessionStart
Помимо общих полей ввода, hooks SessionStart получаютsource и опционально model, agent_type и session_title:
Когда
source имеет значение "resume" или "fork" и транскрипт содержит по крайней мере один ответ от Claude, hooks SessionStart также получают четыре поля ниже. Ваш hook может использовать их для сообщения о стоимости возобновления устаревшего разговора перед первым запросом, например в systemMessage. Эти поля требуют Claude Code v2.1.251 или позже.
Этот пример показывает ввод для сеанса, возобновленного через 90 минут после его последнего ответа:
Управление решением SessionStart
Claude Code добавляет stdout, который он рассматривает как простой текст, в контекст Claude. Помимо полей JSON-вывода, доступных всем hooks, вы можете вернуть эти поля, специфичные для события:sessionTitle.
Используйте reloadSkills, когда hook SessionStart устанавливает или обновляет skills. Обнаружение skills обычно выполняется до завершения hooks SessionStart, поэтому файлы, которые hook записывает в ~/.claude/skills/ или .claude/skills/, в противном случае появятся только в следующем сеансе. Этот пример синхронизирует репозиторий общих skills и запрашивает повторное сканирование:
fatal: в stderr. Stderr из hook SessionStart, который выходит с кодом 0, только информационный, поэтому запрос reloadSkills все еще применяется.
Сохранение переменных окружения
Hooks SessionStart имеют доступ к переменной окруженияCLAUDE_ENV_FILE, которая предоставляет путь к файлу, где вы можете сохранить переменные окружения для последующих команд Bash.
Чтобы установить отдельные переменные окружения, напишите операторы export в CLAUDE_ENV_FILE. Используйте добавление (>>) для сохранения переменных, установленных другими hooks:
CLAUDE_ENV_FILE доступен для hooks SessionStart, Setup, CwdChanged и FileChanged. Другие типы hooks не имеют доступа к этой переменной.Setup
Срабатывает только при запуске Claude Code с--init-only или с --init или --maintenance в неинтерактивном режиме с флагом -p. Не срабатывает при нормальном запуске. Используйте для одноразовой установки зависимостей или запланированной очистки, которую вы явно запускаете из CI или скриптов, отдельно от нормального запуска сеанса. Для инициализации для каждого сеанса используйте вместо этого SessionStart.
Значение matcher соответствует флагу CLI, который запустил hook:
Когда вы запускаете
claude --init-only, Claude Code запускает hooks Setup и hooks SessionStart с matcher startup, затем выходит без запуска разговора.
Когда вы запускаете или продолжаете разговор с -p, вам также нужно предоставить подсказку как аргумент или через stdin. Вы можете пропустить подсказку, когда hook SessionStart предоставляет initialUserMessage или когда вы возобновляете сеанс с отложенным вызовом инструмента.
При успехе --init-only ничего не выводит на терминал. Чтобы подтвердить, что hooks выполнились, начните с claude --debug-file <path> --init-only, заменив <path> на местоположение файла журнала, и проверьте журнал на наличие записей hooks Setup и SessionStart.
Поскольку Setup не срабатывает при каждом запуске, плагин, которому нужна установленная зависимость, не может полагаться только на Setup. Практический паттерн — проверить зависимость при первом использовании и установить при отсутствии, например hook или skill, который тестирует ${CLAUDE_PLUGIN_DATA}/node_modules и запускает npm install, если отсутствует. См. persistent data directory для информации о том, где хранить установленные зависимости. Если вы распространяете свой плагин через marketplace, вам может не понадобиться этот паттерн: Claude Code автоматически устанавливает подходящие зависимости пакетов Node.js при кэшировании плагина.
Ввод Setup
Помимо общих полей ввода, hooks Setup получают полеtrigger, установленное либо на "init", либо на "maintenance":
Управление решением Setup
Hooks Setup не могут блокировать; выполнение продолжается при любом коде выхода. При каждом коде выхода Claude Code отбрасывает поля JSON-вывода hook Setup, такие какsystemMessage, continue и hookSpecificOutput.additionalContext. С -p stdout, stderr и код выхода hook Setup появляются в выводе запуска только как hook_response события при запуске с --output-format stream-json --verbose.
Hooks Setup имеют доступ к CLAUDE_ENV_FILE. Переменные, записанные в этот файл, сохраняются в последующих командах Bash для сеанса, как и в hooks SessionStart. На Setup выполняются только hooks type: "command". Hook type: "mcp_tool" на Setup всегда пропускается, как описано в MCP tool hook fields.
InstructionsLoaded
Срабатывает, когда файлCLAUDE.md или .claude/rules/*.md загружается в контекст. Это событие срабатывает при запуске сеанса для файлов, загружаемых с нетерпением, и снова позже, когда файлы загружаются с нетерпением, например когда Claude получает доступ к подпапке, содержащей вложенный CLAUDE.md, или когда условные правила с frontmatter paths: совпадают. Hook не поддерживает блокировку или управление решением. Он выполняется асинхронно в целях наблюдаемости.
Это событие не срабатывает, когда Claude читает AGENTS.md напрямую через параметр Project instructions. Оно срабатывает, когда CLAUDE.md импортирует ваш AGENTS.md с load_reason, установленным на include, как для любого другого импортированного файла, и когда CLAUDE.md является символической ссылкой на него, как нормальная загрузка CLAUDE.md.
Matcher выполняется против load_reason. Например, используйте "matcher": "session_start" для срабатывания только для файлов, загруженных при запуске сеанса, или "matcher": "path_glob_match|nested_traversal" для срабатывания только для ленивых загрузок.
Ввод InstructionsLoaded
Помимо общих полей ввода, hooks InstructionsLoaded получают эти поля:Управление решением InstructionsLoaded
Hooks InstructionsLoaded не имеют управления решением. Они не могут блокировать или изменять загрузку инструкций. Claude Code отбрасывает их поля JSON-вывода, такие какsystemMessage и continue. Используйте это событие для аудита логирования, отслеживания соответствия или наблюдаемости.
UserPromptSubmit
Запускается, когда пользователь отправляет подсказку, перед обработкой Claude. Это позволяет вам добавить дополнительный контекст на основе подсказки/разговора, проверить подсказки или заблокировать определенные типы подсказок. HooksUserPromptSubmit имеют тайм-аут по умолчанию 30 секунд для типов command, http и mcp_tool, короче, чем 600-секундный стандарт для этих типов на большинстве других событий. Поскольку этот hook выполняется перед каждой подсказкой и блокирует обработку модели до его завершения, застрявший hook замораживает сеанс. Если вашему hook нужно больше времени, установите поле timeout в записи hook.
Помимо command hook, который вы запускаете с async: true, hook UserPromptSubmit command, HTTP или MCP tool, который достигает своего тайм-аута, отменяется и его вывод, включая любой additionalContext, отбрасывается. Подсказка все еще достигает Claude без этого контекста. Транскрипт показывает уведомление с названием hook, тайм-аутом, который сработал, и что вывод был отброшен.
Callback hook Agent SDK на UserPromptSubmit, который достигает своего тайм-аута, блокирует подсказку сообщением с названием hook и тайм-аутом, потому что callback там может действовать как политический шлюз, который не должен открываться при отказе. Сеанс продолжается. До версии 2.1.208 тайм-аут callback на этом событии заканчивал ход с ошибкой выполнения.
Ввод UserPromptSubmit
Помимо общих полей ввода, hooks UserPromptSubmit получают полеprompt, содержащее текст, отправленный пользователем. Вставленный контент, который свернулся в заполнитель [Pasted text #N], прибывает развернутым на месте. В сеансах, где Claude Code отмечает вставленный текст для Claude, этот развернутый контент находится между строкой <pasted_content id="…"> и строкой </pasted_content id="…">, поэтому учитывайте эти строки, если ваш hook анализирует подсказку.
Управление решением UserPromptSubmit
HooksUserPromptSubmit могут управлять тем, обрабатывается ли подсказка пользователя, и добавлять контекст. Все поля JSON-вывода доступны.
Есть два способа добавить контекст к разговору при коде выхода 0:
- Простой текст stdout: Claude Code добавляет stdout, который он рассматривает как простой текст, в контекст Claude
- JSON с
additionalContext: используйте формат JSON ниже для большего контроля. ЗначениеadditionalContextдобавляется как контекст
additionalContext каждый вводятся как системное напоминание, которое начинается с названия hook; Claude читает оба. Чтобы подтвердить доставку, проверьте debug log.
Чтобы заблокировать подсказку, верните объект JSON с decision, установленным на "block":
Hook, который блокирует выходом 2, маршрутизируется так же, как
reason: сообщение блокировки показывает текст stderr пользователю и не добавляется в контекст.
UserPromptExpansion
Запускается, когда команда, введенная пользователем, расширяется в подсказку перед достижением Claude. Используйте это для блокировки определенных команд от прямого вызова, внедрения контекста для определенного skill или логирования того, какие команды вызывают пользователи. Например, hook, соответствующийdeploy, может заблокировать /deploy, если отсутствует файл одобрения, или hook, соответствующий skill проверки, может добавить контрольный список проверки команды как additionalContext.
Это событие охватывает путь, который PreToolUse не охватывает: hook PreToolUse, соответствующий инструменту Skill, срабатывает только, когда Claude вызывает инструмент, но ввод /skillname напрямую обходит PreToolUse. UserPromptExpansion срабатывает на этом прямом пути.
Совпадает с command_name. Оставьте matcher пустым для срабатывания на каждой команде типа подсказки.
Ввод UserPromptExpansion
Помимо общих полей ввода, hooks UserPromptExpansion получаютexpansion_type, command_name, command_args, command_source и исходную строку prompt. Поле expansion_type имеет значение slash_command для skill и пользовательских команд или mcp_prompt для подсказок сервера MCP.
Управление решением UserPromptExpansion
HooksUserPromptExpansion могут блокировать расширение или добавлять контекст. Все поля JSON-вывода доступны.
Hook, который блокирует выходом 2, маршрутизируется так же, как
reason: сообщение блокировки показывает текст stderr пользователю.
MessageDisplay
Запускается, пока сообщение помощника транслируется на экран. Claude Code отображает сообщение порциями: каждый раз, когда партия новых завершенных строк готова к отрисовке, hook выполняется один раз с этими строками, и Claude Code отображает текст замены hook на их месте. Длинное сообщение создает несколько вызовов; короткое сообщение может создать только один. Используйте MessageDisplay для:- удаления markdown для минимального отображения
- преобразования текста, который приложение Agent SDK показывает своим пользователям
- редактирования ключей API или внутренних имен хостов из ответов Claude
timeout в записи hook.
MessageDisplay только для отображения: текст замены изменяет только то, что отображается на экране. Транскрипт и то, что видит Claude, сохраняют исходный текст, поэтому Claude никогда не видит замену, и подробный режим показывает исходный. Hook получает только текст сообщения помощника, поэтому результаты инструментов и текст, который вы вводите, отображаются без изменений.
MessageDisplay не поддерживает matchers и срабатывает для каждого сообщения помощника, которое транслирует текст; сообщения без текста, такие как ответы только с вызовом инструмента, не запускают его.
В неинтерактивных запусках, включая запросы Agent SDK и claude -p, MessageDisplay выполняется один раз для каждого сообщения помощника вместо один раз для каждой партии строк. Один вызов прибывает после завершения сообщения и несет полный текст сообщения: index имеет значение 0, final имеет значение true, и delta содержит все сообщение. Hook, который собирает текст delta для каждого сообщения, получает одинаковый общий текст в обоих режимах.
Ввод MessageDisplay
Помимо общих полей ввода, hooks MessageDisplay получают идентификаторы для хода и сообщения, позицию этого вызова в сообщении и новый текст вdelta. Границы партий зависят от того, как транслируется текст, поэтому используйте index и final для отслеживания прогресса через сообщение, а не ожидайте, что строки будут сгруппированы определенным образом.
Вывод MessageDisplay
Помимо полей JSON-вывода, доступных всем hooks, hooks MessageDisplay могут вернутьdisplayContent для замены delta на экране:
Hooks MessageDisplay не имеют управления решением. Они не могут блокировать сообщение или изменять то, что хранится в транскрипте или отправляется Claude. Claude Code действует на
displayContent из их JSON-вывода и отбрасывает systemMessage и continue.
Этот пример удаляет форматирование markdown из ответов Claude для отображения простого текста. Скрипт читает каждую партию из stdin, удаляет маркеры жирного шрифта и обратные кавычки встроенного кода из delta и возвращает результат как displayContent.
- macOS/Linux
- Windows (PowerShell)
Зарегистрируйте command hook для события в файле параметров:Сохраните этот скрипт в
.claude/hooks/plain-display.sh в вашем проекте и сделайте его исполняемым с помощью chmod +x:jq отсутствует, Claude Code отображает исходный текст и отмечает сбой только в debug output, а не в сеансе.
PreToolUse
Запускается после того, как Claude создает параметры инструмента и перед обработкой вызова инструмента. Совпадает с любым названием инструмента, кромеEndConversation: встроенные инструменты, такие как Bash, PowerShell, Edit, Write, Read, Glob, Grep, Agent, Workflow, WebFetch, WebSearch, AskUserQuestion и ExitPlanMode, и любые имена инструментов MCP.
Чтобы запустить hook, когда определенный файл изменяется на диске, независимо от того, что его написало, используйте вместо этого FileChanged. В отличие от PreToolUse, Claude Code запускает hooks FileChanged после изменения, и они не имеют управления решением, поэтому они не могут блокировать запись.
Используйте управление решением PreToolUse для разрешения, отказа, запроса или отложения вызова инструмента.
Callback hook Agent SDK на PreToolUse, который превышает свой тайм-аут, блокирует вызов инструмента, и Claude получает результат ошибки с названием тайм-аута. Явный отказ, возвращенный другим hook, все еще имеет приоритет.
Ввод PreToolUse
Помимо общих полей ввода, hooks PreToolUse получаютtool_name, tool_input и tool_use_id.
Для инструмента MCP ввод также несет mcp_server, объект с name сервера и source, который говорит, откуда пришло определение сервера. Значения source включают plugin, sdk и области конфигурации, такие как user и project. McpServerProvenance в справочнике Agent SDK перечисляет их все и говорит, как рассматривать тот, который вы не узнаете. Основывайте решения о доверии на source, а не на name или префиксе инструмента mcp__<server>__. Поле mcp_server требует Claude Code v2.1.274 или позже.
Для инструментов файлов Write, Edit и Read, tool_input.file_path всегда абсолютен:
- Claude Code расширяет
~и относительные пути перед выполнением hooks, поэтому hook, который совпадает с путями, не может быть обойден через~или относительное написание одного пути - На Windows путь прибывает с разделителями обратной косой черты, даже когда ваш hook выполняется под Git Bash, где
$PWDвыглядит как/c/project - Сравнение, написанное с прямыми косыми чертами, такое как проверка
/src/, никогда не совпадает с путем обратной косой черты, и вызов инструмента продолжается, как если бы hook не имел ничего для блокировки - Нормализуйте разделители перед сравнением:
FILE_PATH="${FILE_PATH//\\//}"в Bash илиfile_path.replace("\\", "/")в Python, затем совпадайте с сегментом пути, такой как/src/, а не якорем с^, так как путь абсолютен
Write на Windows доставляет:
tool_input зависят от инструмента:
Выполняет команды оболочки.
Когда команда Bash изменяет файлы в репозитории Git, Claude Code может записать, что изменилось. Он записывает изменения в каждом режиме разрешений, когда параметр
bashEditDiffEnabled включает запись; запись этого параметра говорит, какие файлы могут его установить. В противном случае он записывает их только в режиме auto и режиме bypassPermissions, и только когда Claude Code направляет Claude на редактирование файлов через Bash. Установите bashEditDiffEnabled на false, чтобы отключить запись. Фоновые команды и команды только для чтения не несут diff.
Ваш hook PostToolUse затем получает измененные файлы в tool_response.bashEditDiff. Список охватывает то, что изменилось в репозитории, пока выполнялась команда. Файлы, которые Git игнорирует, и файлы в подмодулях не указаны. Требует Claude Code v2.1.269 или позже.
Список лучше всего усилен и находится в публичной бета-версии. Claude Code может пропустить изменение, включить файл, который другой процесс изменил одновременно, или остановиться на его пределах размера. Форма поля может измениться. Используйте список для поиска того, что нужно проверить, а не для применения политики.
changedFiles и files перечисляют то, что команда изменила; остальные поля говорят, насколько полон и надежен этот список.
Выполняет команды PowerShell. См. инструмент PowerShell для доступности по платформе.
Поля совпадают с инструментом Bash, со строкой команды в
command:
Совпадайте с
Bash|PowerShell в hooks, которые проверяют команды оболочки, чтобы они охватывали оба инструмента:
- На Windows, везде, где включен инструмент PowerShell, Claude рассматривает PowerShell как основную оболочку и маршрутизирует команды оболочки через него.
- На Windows без Git Bash инструмент включен автоматически и Claude Code не регистрирует инструмент Bash вообще.
- Hook, который совпадает только с
Bash, никогда не срабатывает там.
Заменяет строку в существующем файле.
Читает содержимое файла.
Находит файлы, соответствующие шаблону glob.
Ищет содержимое файлов с регулярными выражениями.
Получает и обрабатывает веб-контент.
Ищет в веб.
Порождает подагента.
Когда вызов Agent переднего плана завершается, ваш hook PostToolUse получает результат подагента и телеметрию запуска в
tool_response. Прочитайте эти поля для проверки запуска; для сводок токенов и затрат по подагентам используйте счетчики токенов и затрат, отфильтрованные по query_source "subagent", так как totalTokens и usage охватывают только финальный запрос:
На Claude Code v2.1.271 или позже подагент, который выполняется с инструментом
SubagentHandback, который Claude Code предоставляет в режиме auto, доставляет свой отчет через этот инструмент, а не возвращает его как текст. Поле content его результата completed затем несет краткую заметку об этой передаче, а не сам отчет. Чтобы прочитать отчет, совпадайте с hook PreToolUse или PostToolUse на SubagentHandback и прочитайте tool_input.message.
Для подагентов фонового плана инструмент возвращается, когда задача переходит в фоновый режим, поэтому tool_response не несет полей использования: фоновый запуск возвращается немедленно, и задача переднего плана, которую Claude Code переводит в фоновый режим во время запуска, возвращается при этом переходе. Он имеет status: "async_launched", agentId, description, prompt, outputFile и resolvedModel.
На ответе completed, resolvedModel называет модель, на которой подагент начал, которая может отличаться от значения model в tool_input, такой как когда availableModels или другое переопределение применяется. На ответе async_launched, resolvedModel называет модель в использовании, когда агент перешел в фоновый режим, поэтому переключение, которое произошло перед переходом в фоновый режим, отражается там. modelsUsed и поведение resolvedModel во время перехода в фоновый режим требуют Claude Code v2.1.212 или позже.
Задает пользователю один-четыре вопроса с множественным выбором.
Представляет план и просит пользователя одобрить его перед тем, как Claude покинет режим плана. Claude записывает план в файл на диск перед вызовом инструмента, поэтому буквальный
tool_input из модели обычно пуст. Claude Code вводит содержимое плана и путь к файлу перед передачей ввода в hooks.
В
PostToolUse, tool_response — это объект с полями plan и filePath, содержащими одобренный план, плюс внутренние флаги статуса. Прочитайте tool_response.plan для содержимого плана, а не перечитывайте файл с диска.
Управление решением PreToolUse
HooksPreToolUse могут управлять тем, продолжается ли вызов инструмента. В отличие от других hooks, которые используют поле decision верхнего уровня, PreToolUse возвращает свое решение внутри объекта hookSpecificOutput. Это дает ему более богатый контроль: четыре результата (разрешить, отказать, спросить или отложить) плюс возможность изменить ввод инструмента перед выполнением.
Когда несколько hooks PreToolUse возвращают разные решения, приоритет —
deny > defer > ask > allow.
Hook, который блокирует выходом 2, маршрутизируется так же, как "deny": Claude видит сообщение stderr как причину отказа.
Когда hook возвращает "ask", подсказка разрешения, отображаемая пользователю, включает ярлык, определяющий, откуда пришел hook: [settings] для hook из любого файла параметров или из frontmatter агента, [plugin:<name>] для hook плагина или [skill] для hook из frontmatter skill. Это помогает пользователям понять, какой источник конфигурации запрашивает подтверждение.
"ask" hook также принуждает подсказку разрешения в режиме auto: классификатор все еще может отказать вызову инструмента, но не может одобрить вызов молча. До версии 2.1.211 классификатор мог одобрить команду Bash, выполняющуюся вне sandbox, без показа подсказки, которую запросил hook; классификатор все еще применял свои собственные правила безопасности к этой команде, и hook "deny" всегда соблюдался.
-p Claude Code предлагает AskUserQuestion и ExitPlanMode только, когда запуск имеет хост разрешений для получения подсказки, такой как callback canUseTool Agent SDK. Эти инструменты требуют взаимодействия с пользователем. Возврат permissionDecision: "allow" вместе с updatedInput удовлетворяет это требование: hook читает ввод инструмента из stdin, собирает ответ через ваш собственный UI и возвращает его в updatedInput, чтобы инструмент выполнялся без подсказки. Возврат только "allow" недостаточен для этих инструментов. Для AskUserQuestion повторите исходный массив questions и добавьте объект answers, отображающий текст каждого вопроса на выбранный ответ.
Начиная с версии 2.1.199, инструмент MCP, сервер которого отмечает его с помощью _meta["anthropic/requiresUserInteraction"], более строг: hook не может пропустить его подсказку одобрения с "allow", с updatedInput или без него, потому что Claude Code не может подтвердить, что hook собрал взаимодействие, которое требует инструмент.
PreToolUse ранее использовал поля
decision и reason верхнего уровня, но они устарели для этого события. Используйте вместо этого hookSpecificOutput.permissionDecision и hookSpecificOutput.permissionDecisionReason. Устаревшие значения "approve" и "block" отображаются на "allow" и "deny" соответственно. Другие события, такие как PostToolUse и Stop, продолжают использовать decision и reason верхнего уровня как их текущий формат.Отложить вызов инструмента на потом
"defer" предназначен для интеграций, которые запускают claude -p как подпроцесс и читают его JSON-вывод, такие как приложение Agent SDK или пользовательский UI, построенный на основе Claude Code. Это позволяет этому вызывающему процессу приостановить Claude при вызове инструмента, собрать ввод через его собственный интерфейс и возобновить, где он остановился. Claude Code соблюдает это значение только в неинтерактивном режиме с флагом -p. В интерактивных сеансах он логирует предупреждение и игнорирует результат hook.
Инструмент AskUserQuestion — типичный случай: Claude хочет что-то спросить у пользователя, но нет терминала для ответа. Запуск -p предлагает AskUserQuestion только, когда он имеет хост разрешений, такой как инструмент MCP, который вы передаете с --permission-prompt-tool, поэтому начните запуск с одного. Круговой путь работает так:
- Claude вызывает
AskUserQuestion. Срабатывает hookPreToolUse. - Hook возвращает
permissionDecision: "defer". Инструмент не выполняется. Процесс выходит сstop_reason: "tool_deferred"и отложенный вызов инструмента сохраняется в транскрипте. - Вызывающий процесс читает
deferred_tool_useиз результата SDK, выводит вопрос в своем собственном UI и ждет ответа. - Вызывающий процесс запускает
claude -p --resume <session-id>с тем же хостом разрешений. Тот же вызов инструмента срабатываетPreToolUseснова. - Hook возвращает
permissionDecision: "allow"с ответом вupdatedInput. Инструмент выполняется и Claude продолжает.
deferred_tool_use несет id, name и input инструмента. input — это параметры, которые Claude сгенерировал для вызова инструмента, захваченные перед выполнением:
"defer" снова и процесс выходит так же. Вызывающий процесс управляет тем, когда разорвать цикл, в конечном итоге возвращая "allow" или "deny" из hook.
"defer" работает только, когда Claude делает один вызов инструмента в ходе. Если Claude делает несколько вызовов инструментов одновременно, "defer" игнорируется с предупреждением и инструмент проходит через нормальный поток разрешений. Ограничение существует, потому что возобновление может повторно запустить только один инструмент: нет способа отложить один вызов из партии без оставления других неразрешенными.
Если отложенный инструмент больше не доступен при возобновлении, процесс выходит с stop_reason: "tool_deferred_unavailable" и is_error: true перед срабатыванием hook. Это происходит, когда сервер MCP, который предоставил инструмент, не подключен для возобновленного сеанса. Полезная нагрузка deferred_tool_use все еще включена, чтобы вы могли определить, какой инструмент исчез.
Чтобы возобновить отложенный сеанс в режиме плана, передайте
--permission-prompt-tool вместе с --resume, чтобы Claude Code мог представить план для одобрения. Если вы передаете определенные другие флаги запуска, возобновленный запуск не возвращается в режим плана; см. Resume in plan mode with -p. Требует Claude Code v2.1.246 или позже.Когда вы возобновляете с -p, Claude Code не восстанавливает никакой другой сохраненный режим разрешений. Он запускает запуск в режиме разрешений, который новый запуск claude -p запустил бы, поэтому передайте --permission-mode или --dangerously-skip-permissions снова, если отложенный сеанс использовал один. Когда вы возобновляете с claude --resume <session-id> без -p, Claude Code восстанавливает сохраненный режим разрешений, с исключениями, перечисленными в режим разрешений при возобновлении.PermissionRequest
Запускается, когда Claude Code собирается попросить вас разрешение на использование инструмента. В сеансах, которые не могут показать подсказку, такие как фоновые подагенты в неинтерактивном режиме, Claude Code все еще запускает эти hooks, и если ни один hook не возвращает решение, он отказывает вызову инструмента. Используйте управление решением PermissionRequest для разрешения или отказа от имени пользователя. Используйте это событие, когда вам нужен сигнал в момент, когда Claude просит разрешение на использование инструмента. Claude Code запускает hook Notification с типомpermission_prompt только после того, как подсказка ждала около шести секунд.
Claude Code не запускает hooks PermissionRequest для сетевого запроса изолированной команды. Чтобы получить сигнал для этой подсказки, используйте тип уведомления permission_prompt.
Совпадает с названием инструмента, те же значения, что и PreToolUse.
Ввод PermissionRequest
Hooks PermissionRequest получают поляtool_name и tool_input, как hooks PreToolUse, но без tool_use_id. Для инструмента MCP они также получают объект mcp_server. Опциональный массив permission_suggestions содержит обновления разрешений, которые Claude Code предлагает для этого запроса, такие как добавление правила разрешения или изменение режима разрешений.
Массив permission_suggestions не является точным списком опций, которые вы видите, потому что каждый диалог разрешений строит свои собственные опции. Некоторые диалоги, такие как диалог для редактирования файлов, вообще не читают массив и получают свои опции из самого запроса. Диалог, который читает его, все еще может скрыть опцию, чье предложение остается в массиве, например, когда allowManagedPermissionRulesOnly скрывает опции сохранения правил. Он также может предложить опции, которые не имеют записи предложения, такие как Yes, and switch to auto mode, которая изменяет режим разрешений напрямую, а не через обновление разрешений.
Hooks PreToolUse запускаются перед каждым вызовом инструмента, независимо от того, нужно ли ему разрешение. Hooks PermissionRequest запускаются только, когда Claude Code собирается попросить вас разрешение, или когда он в противном случае автоматически отказал бы вызову, который не может подсказать. Ни одно событие не срабатывает для EndConversation.
Управление решением PermissionRequest
HooksPermissionRequest могут разрешить или отказать запросы разрешений. Помимо полей JSON-вывода, доступных всем hooks, ваш скрипт hook может вернуть объект decision с этими полями, специфичными для события:
Hook, который выходит 2 без объекта
decision, оставляет поток разрешений неизменным, и его stderr отбрасывается. Только объект decision может предоставить или отказать в запросе.
Записи обновления разрешений
Поле выводаupdatedPermissions и поле ввода permission_suggestions оба используют один и тот же массив объектов записей. Каждая запись имеет type, который определяет ее другие поля, и destination, который управляет тем, где записывается изменение.
setMode с bypassPermissions вступает в силу только, если вы запустили сеанс с режимом обхода, уже доступным: --dangerously-skip-permissions, --permission-mode bypassPermissions, --allow-dangerously-skip-permissions или permissions.defaultMode: "bypassPermissions" в пользовательских, --settings или управляемых параметрах. В противном случае обновление — это no-op. Обновление также является no-op, когда permissions.disableBypassPermissionsMode отключает режим или когда сеанс запускается в restricted mode.bypassPermissions никогда не сохраняется как defaultMode независимо от destination.destination на каждой записи определяет, остается ли изменение в памяти или сохраняется в файл параметров.
Hook может повторить одно из
permission_suggestions, которые он получил, как свой собственный вывод updatedPermissions.
PostToolUse
Запускается сразу после успешного завершения инструмента. Совпадает с названием инструмента, те же значения, что и PreToolUse. Совпадайте более широко, когда название инструмента не является правильным фильтром:- Чтобы запустить hook после завершения любого инструмента успешно, опустите
matcherили установите его на"*". Ваш hook может затем обнаружить, что изменилось сам, например, запустивgit status --porcelain, который также перечисляет неотслеживаемые файлы, которыеgit diffпропускает. Для вызовов инструментов, которые не удаются, добавьте тот же hook под PostToolUseFailure. - Чтобы запустить hook, когда определенный файл изменяется на диске, независимо от того, что его написало, используйте FileChanged. Claude Code не запускает hook
PostToolUse, соответствующийEdit|Write, когда командаBashили процесс вне Claude Code переписывает тот же файл.
Ввод PostToolUse
HooksPostToolUse срабатывают после того, как инструмент уже выполнился успешно. Ввод включает как tool_input, аргументы, отправленные инструменту, так и tool_response, результат, который он вернул. Точная схема для обоих зависит от инструмента. Пути tool_input инструментов файлов прибывают в том же формате, что и для PreToolUse: всегда абсолютные, с собственными разделителями платформы, поэтому обратные косые черты на Windows. Для инструмента MCP ввод также несет объект mcp_server.
Управление решением PostToolUse
HooksPostToolUse могут предоставить обратную связь Claude после выполнения инструмента. Помимо полей JSON-вывода, доступных всем hooks, ваш скрипт hook может вернуть эти поля, специфичные для события:
Пример ниже заменяет вывод вызова
Bash. Значение замены совпадает с формой вывода инструмента Bash:
Аннотирование результата для классификатора режима auto
ВернитеclassifierContext для отправки краткой заметки об этом результате вызова инструмента классификатору режима auto, а не Claude. Классификатор никогда не получает сами результаты инструментов, поэтому это поле — поддерживаемый способ рассказать ему что-то о том, что вернул вызов, перед тем как он проверит более поздние действия. Поле требует Claude Code v2.1.236 или позже.
Пример ниже говорит классификатору, откуда пришел вывод запроса:
- Hooks, настроенные в Claude Code: для hooks из файлов параметров, плагинов, skills и frontmatter агента классификатор рассматривает заметку как непроверенный, предоставленный приложением контекст. Заметка никогда не устанавливает намерение пользователя, и если она утверждает, что вы одобрили или запросили что-то, классификатор проверяет это утверждение против ваших собственных сообщений в разговоре
- In-process callbacks Agent SDK: когда приложение, встраивающее Claude Code, регистрирует hook как callback TypeScript SDK и возвращает заметку во время живого сеанса, классификатор может взвесить утверждение пользователя, переданное в заметке, как намерение пользователя. Такое утверждение может удовлетворить требование согласия, которое классификатор принял бы из сообщения, которое вы отправляете, но оно никогда не снимает блокировку, которую ваше собственное сообщение не могло бы снять. После возобновления сеанса Claude Code рассматривает восстановленные заметки как непроверенный контекст. Когда hooks из обеих групп аннотируют один и тот же вызов, классификатор рассматривает объединенную заметку как непроверенный контекст
- Длина: Claude Code ограничивает заметки для одного вызова инструмента 2000 символами и усекает остальное. Ограничение делится между каждым hook, который отвечает на этот вызов
- Только синхронные ответы: Claude Code игнорирует поле в ответе hook, который выполняется в фоновом режиме, потому что этот ответ прибывает после того, как Claude Code записывает результат инструмента
- Вызовы, которые классификатор не записывает: транскрипт классификатора опускает поиски только для чтения, такие как чтение файлов и поиски. Claude Code отбрасывает заметку, прикрепленную к одному из этих вызовов
- Взаимодействие с переписыванием: когда заметка описывает вывод, который вы заменяете с помощью
updatedToolOutput, верните оба поля в одном ответе hook. Claude Code отбрасывает заметку, если это переписывание отклонено или переписывание другого hook заменяет его. Claude Code доставляет заметку, которую вы возвращаете без переписывания, даже когда другой hook переписывает вывод
PostToolUseFailure
Запускается, когда инструмент, который начал выполняться, не удается: инструмент выбросил ошибку или инструмент MCP вернул результат ошибки. Используйте это для логирования сбоев, отправки оповещений или предоставления исправляющей обратной связи Claude. Совпадает с названием инструмента, те же значения, что и PreToolUse.Это событие не срабатывает для вызовов инструментов, отклоненных перед выполнением: неизвестное название инструмента, ввод, который не проходит проверку схемы или инструмента, или отказ в разрешении. Отказы в проверке возвращаются как результаты
tool_use_error и происходят перед выполнением hooks, поэтому они не срабатывают ни PreToolUse, ни PostToolUseFailure. Отказы в разрешении срабатывают PreToolUse, но не это событие; см. PermissionDenied.Ввод PostToolUseFailure
Hooks PostToolUseFailure получают те же поляtool_name и tool_input, что и PostToolUse, вместе с информацией об ошибке как полями верхнего уровня. Для инструмента MCP они также получают объект mcp_server. Например, неудачная команда npm test может доставить:
Строка
error обычно является тем же текстом, который Claude получает как результат неудачного инструмента. Его формат варьируется в зависимости от инструмента и сбоя. Ключ вашего hook на tool_name, is_interrupt и первой строке Exit code N; рассматривайте остальную строку как текст отображения, а не стабильный формат.
- Для Bash и PowerShell команда, которая выполнилась и вышла, создает первую строку
Exit code N, затем любой вывод, который команда создала, как один блок с stdout и stderr перемешанными - Полезная нагрузка также может нести сообщение об ошибке без строки кода выхода, когда Claude Code не мог запустить сам процесс оболочки
- Claude Code усекает длинные строки в середине вокруг маркера
... [N characters truncated] ...и может вставлять свои собственные строки, такие какCommand timed out after 2m 0s
Управление решением PostToolUseFailure
HooksPostToolUseFailure могут предоставить контекст Claude после сбоя инструмента. Помимо полей JSON-вывода, доступных всем hooks, ваш скрипт hook может вернуть эти поля, специфичные для события:
PostToolBatch
Запускается один раз после того, как каждый вызов инструмента в партии разрешится, перед тем как Claude Code отправит следующий запрос модели.PostToolUse срабатывает один раз для каждого инструмента, что означает, что он срабатывает одновременно, когда Claude делает параллельные вызовы инструментов. PostToolBatch срабатывает ровно один раз со всей партией, поэтому это правильное место для внедрения контекста, который зависит от набора инструментов, которые выполнились, а не от любого одного инструмента. Нет matcher для этого события.
Ввод PostToolBatch
Помимо общих полей ввода, hooks PostToolBatch получаютtool_calls, массив, описывающий каждый вызов инструмента в партии:
tool_response содержит то же содержимое, которое модель получает в соответствующем блоке tool_result. Значение — это сериализованная строка или массив блоков контента, ровно как инструмент выдал его. Для Read это означает текст с префиксом номера строки, а не необработанное содержимое файла. Ответы могут быть большими, поэтому анализируйте только нужные вам поля.
Форма
tool_response отличается от PostToolUse. PostToolUse передает структурированный объект Output инструмента, такой как {filePath: "...", type: "create"} для Write; PostToolBatch передает сериализованное содержимое tool_result, которое видит модель.Управление решением PostToolBatch
HooksPostToolBatch могут внедрить контекст для Claude. Помимо полей JSON-вывода, доступных всем hooks, ваш скрипт hook может вернуть эти поля, специфичные для события:
decision: "block" или continue: false останавливает агентский цикл перед следующим вызовом модели. Сообщение блокировки поступает из JSON reason или stopReason или из stderr при выходе 2. Вы видите его как предупреждение в транскрипте, и оно остается в разговоре, поэтому Claude видит его при продолжении разговора.
PermissionDenied
Запускается, когда режим auto отказывает вызову инструмента, включая когда он отказывает без вердикта классификатора, потому что проверка безопасности, отдельная от режима auto, отказала в запросе классификатора или его ответ не был проанализирован. Этот hook срабатывает только в режиме auto: он не запускается, когда вы вручную отказываете диалогу разрешений, когда hookPreToolUse блокирует вызов или когда совпадает правило deny. Используйте его для логирования отказов, настройки конфигурации или сообщения модели, что она может повторить попытку вызова инструмента.
Совпадает с названием инструмента, те же значения, что и PreToolUse.
Ввод PermissionDenied
Помимо общих полей ввода, hooks PermissionDenied получаютtool_name, tool_input, tool_use_id и reason. Для инструмента MCP они также получают объект mcp_server.
Управление решением PermissionDenied
Hooks PermissionDenied могут сказать модели, что она может повторить попытку отклоненного вызова инструмента. Верните объект JSON сhookSpecificOutput.retry, установленным на true:
retry имеет значение true, Claude Code добавляет сообщение в разговор, говорящее модели, что она может повторить попытку вызова инструмента. Claude Code не отменяет сам отказ. Если ваш hook не возвращает JSON или возвращает retry: false, отказ остается и модель получает исходное сообщение отказа.
Claude Code игнорирует retry: true, когда классификатор создал отсутствие вердикта на действие: его ответ не был проанализирован или проверка безопасности, отдельная от режима auto, отказала в запросе классификатора. Для этих отказов Claude Code уже говорит модели в сообщении отказа, повторить ли попытку позже или продолжить.
Notification
Запускается, когда Claude Code отправляет уведомления. Совпадает с типом уведомления. Опустите matcher для запуска hooks для всех типов уведомлений. Вы получаете эти события hook даже с отключенными уведомлениями рабочего стола: параметрpreferredNotifChannel, включая notifications_disabled, изменяет только то, как вас оповещают, а не запускается ли ваш hook.
Типы
agent_needs_input и agent_completed требуют Claude Code v2.1.198 или позже.
Типы quota_auto_resume_fired, quota_auto_resume_stale и quota_auto_resume_disabled требуют Claude Code v2.1.234 или позже.
В сеансах терминала permission_prompt для сетевого запроса изолированной команды требует Claude Code v2.1.246 или позже.
agent_needs_input для вопроса настройки терминала товарища требует Claude Code v2.1.248 или позже.
Типы
permission_prompt, idle_prompt, elicitation_dialog и elicitation_url_dialog делят свое время с уведомлениями рабочего стола, поэтому в сеансах терминала вы видите их только, когда вы кажетесь отсутствующим от терминала:- Ожидайте
permission_promptодин раз, когда вы не печатали около шести секунд. Таймер начинается, когда появляется подсказка разрешения, и каждый нажатие клавиши откладывает его. Чтобы запустить hook немедленно, когда Claude просит разрешение на использование инструмента, используйте вместо этого PermissionRequest. - Ожидайте
idle_promptоколо 60 секунд после того, как Claude закончит отвечать, и только если вы не печатали с тех пор. Claude Code не отправляетidle_prompt, пока ждет сброса лимита использования claude.ai. Когда ожидание заканчивается самостоятельно, один из типовquota_auto_resume_*срабатывает вместо этого. - Ожидайте
elicitation_dialogдля формы запроса илиelicitation_url_dialogдля запроса URL браузера один раз, когда вы не печатали около шести секунд. Оба делят один и тот же шестисекундный шлюз какpermission_prompt: таймер начинается, когда появляется диалог, и каждый нажатие клавиши откладывает его.
permission_prompt по-другому в сеансах, где он отправляет запросы разрешений на callback canUseTool Agent SDK, что является тем, как Claude Desktop и расширение VS Code размещают Claude Code:
- Ожидайте
permission_promptоколо шести секунд после того, как Claude просит разрешение. Claude Code не откладывает его, пока вы печатаете. - Если вы или hook PermissionRequest ответите раньше, Claude Code не запускает
permission_prompt. - Установите
CLAUDE_CODE_DISABLE_PERMISSION_PROMPT_NOTIFY_HOOKSна1, чтобы отключитьpermission_promptв этих сеансах.
permission_prompt не срабатывал в этих сеансах.
Используйте отдельные matchers для запуска разных обработчиков в зависимости от типа уведомления. Эта конфигурация запускает скрипт оповещения, специфичный для разрешения, когда Claude нуждается в одобрении разрешения, и другое уведомление, когда Claude был неактивен:
Ввод Notification
Помимо общих полей ввода, hooks Notification получаютmessage с текстом уведомления, опциональный title и notification_type, указывающий, какой тип срабатывает.
systemMessage и continue, но все еще выдает terminalSequence, на которую полагается пример уведомления рабочего стола. Hooks Notification предназначены для побочных эффектов, таких как пересылка уведомления на внешний сервис.
SubagentStart
Запускается, когда Claude порождает подагента с инструментом Agent, когда Claude возобновляет подагента и каждый раз, когда товарищ команды агентов в процессе обрабатывает новое сообщение. Поддерживает matchers для фильтрации по названию типа агента. Для встроенных агентов это имя агента, такое какgeneral-purpose, Explore или Plan. Для пользовательских подагентов это поле name из frontmatter агента, а не имя файла.
Для подагентов, поставляемых плагином, тип агента — это идентификатор с областью плагина, такой как my-plugin:reviewer, а не голое имя frontmatter. Двоеточие помещает имя с областью плагина на путь регулярного выражения, поэтому якорьте matcher с ^ и $ для точного совпадения: ^my-plugin:reviewer$.
Ввод SubagentStart
Помимо общих полей ввода, hooks SubagentStart получаютagent_id с уникальным идентификатором подагента и agent_type с названием агента, который matcher фильтрует.
SubagentStop
Запускается, когда подагент Claude Code закончил отвечать. Совпадает с типом агента, те же значения, что и SubagentStart.Ввод SubagentStop
Помимо общих полей ввода, hooks SubagentStop получаютstop_hook_active, agent_id, agent_type, agent_transcript_path и last_assistant_message. Поле agent_type — это значение, используемое для фильтрации matcher. transcript_path — это транскрипт основного сеанса, пока agent_transcript_path — это собственный транскрипт подагента, хранящийся в вложенной папке subagents/. Поле last_assistant_message содержит текстовое содержимое финального ответа подагента, поэтому hooks могут получить доступ к нему без анализа файла транскрипта.
Не каждое событие SubagentStop поступает от подагента, который Claude порождает. Claude Code также запускает внутренних агентов для некоторых своих собственных функций, таких как предложения подсказок и /btw побочные вопросы, и SubagentStop срабатывает, когда один из них завершается. Для этих событий agent_type — это имя агента, который запускает сам сеанс, такой как один, установленный с --agent или параметром agent, и пустая строка, когда сеанс запускается без одного.
matcher, который называет типы агентов, не совпадает с пустым agent_type. Hook, чей matcher опущен, "" или "*", или является регулярным выражением, которое совпадает с пустой строкой, запускается для событий с пустым agent_type тоже.
На Claude Code v2.1.271 или позже подагент, который выполняется с инструментом SubagentHandback, доставляет свой отчет через этот инструмент перед остановкой. Поле last_assistant_message затем содержит закрывающий текст подагента, если он есть, который не является доставленным отчетом. Отчет — это ввод message этого вызова, который hook PreToolUse или PostToolUse, соответствующий SubagentHandback, получает как tool_input.message.
Hooks SubagentStop также получают массивы background_tasks и session_crons, описанные в Stop input. Оба массива ограничены родительским сеансом, а не подагентом.
hookSpecificOutput.additionalContext с hookEventName, установленным на "SubagentStop", для обратной связи без ошибок, которая держит подагента работающим. Возврат decision: "block" с reason держит подагента работающим и доставляет reason подагенту как его следующую инструкцию. Hook, который блокирует выходом 2, доставляет его сообщение stderr так же. Чтобы внедрить контекст в родительский сеанс после возврата подагента, используйте вместо этого hook PostToolUse на инструменте Agent.
TaskCreated
Запускается, когда задача создается через инструментTaskCreate. Используйте это для применения соглашений об именовании, требования описаний задач или предотвращения создания определенных задач. В сеансе без инструментов Task это событие не срабатывает.
Hooks TaskCreated не поддерживают matchers и срабатывают при каждом возникновении.
Ввод TaskCreated
Помимо общих полей ввода, hooks TaskCreated получаютtask_id, task_subject и опционально task_description, teammate_name и team_name.
Управление решением TaskCreated
Hook TaskCreated может заблокировать создание двумя способами. В любом случае Claude Code удаляет задачу и возвращает ваше сообщение Claude как ошибку инструмента. Claude Code игнорируетcontinue: false из этого события и Claude продолжает работать.
- Код выхода 2: Claude Code возвращает текст stderr как сообщение.
- JSON
{"decision": "block", "reason": "..."}: Claude Code возвращаетreasonкак сообщение.
TaskCompleted
Запускается, когда задача отмечается как завершенная. Это срабатывает в двух ситуациях: когда любой агент явно отмечает задачу как завершенную через инструмент TaskUpdate или когда товарищ команды агентов завершает свой ход с выполняющимися задачами. Используйте это для применения критериев завершения, таких как прохождение тестов или проверок lint, перед закрытием задачи. Hooks TaskCompleted не поддерживают matchers и срабатывают при каждом возникновении.Ввод TaskCompleted
Помимо общих полей ввода, hooks TaskCompleted получаютtask_id, task_subject и опционально task_description, teammate_name и team_name.
Управление решением TaskCompleted
Hooks TaskCompleted поддерживают два способа управления завершением задачи:- Код выхода 2: задача не отмечается как завершенная и сообщение stderr передается обратно модели как обратная связь.
- JSON
{"continue": false, "stopReason": "..."}: когда товарищ, завершающий свой ход, запустил событие, полностью останавливает товарища, совпадая с поведением hookStop.stopReasonпоказывается пользователю. Когда инструментTaskUpdateзапустил событие, Claude Code игнорируетcontinue: false; код выхода 2 все еще блокирует завершение.
Stop
Запускается, когда основной агент Claude Code закончил отвечать. Не запускается, если остановка произошла из-за прерывания пользователем. Ошибки API срабатывают вместо этого StopFailure.Ввод Stop
Помимо общих полей ввода, hooks Stop получаютstop_hook_active, last_assistant_message, background_tasks и session_crons. Поле stop_hook_active имеет значение true, когда Claude Code уже продолжает в результате hook stop. Проверьте это значение или обработайте транскрипт, чтобы избежать блокировки на условии, которое никогда не разрешится. Claude Code переопределяет hook и заканчивает ход после 8 последовательных блокировок. Чтобы повысить ограничение, установите CLAUDE_CODE_STOP_HOOK_BLOCK_CAP.
Поле last_assistant_message содержит текстовое содержимое финального ответа Claude, поэтому hooks могут получить доступ к нему без анализа файла транскрипта. Для hooks, которые действуют на только что завершенный ход, такие как hooks чтения вслух или уведомления, используйте это поле, а не читайте transcript_path: файл транскрипта не гарантируется включать финальное сообщение во время Stop на всех версиях.
Массивы background_tasks и session_crons позволяют hooks различать “сеанс завершен” от “сеанс приостановлен, ожидая фоновой работы для пробуждения его обратно”. Оба массива присутствуют, когда реестр задач доступен и пусты, когда ничего не выполняется или не запланировано.
Каждая запись в background_tasks описывает одну выполняющуюся задачу и использует эти поля:
Каждая запись в
session_crons описывает одно запланированное пробуждение с областью сеанса, полученное из CronCreate, ScheduleWakeup и /loop:
Этот пример показывает ввод Stop с одной выполняющейся задачей shell и одним повторяющимся cron:
Управление решением Stop
HooksStop и SubagentStop могут управлять тем, продолжает ли Claude. Помимо полей JSON-вывода, доступных всем hooks, ваш скрипт hook может вернуть эти поля, специфичные для события:
Hook, который блокирует выходом 2, маршрутизируется так же, как
reason: Claude получает сообщение stderr как объяснение того, почему он должен продолжить.
additionalContext, когда hook работает как задумано и дает Claude руководство, такое как “запустить набор тестов перед завершением”. Это держит разговор идущим через те же защиты цикла, что и decision: "block", а именно ввод stop_hook_active и ограничение 8-последовательного продолжения, но транскрипт помечает его Stop hook feedback и уведомление об ошибке hook не показывается:
StopFailure
Запускается вместо Stop, когда ход заканчивается из-за ошибки API. Claude Code игнорирует вывод и код выхода hook, кромеterminalSequence. Используйте это для логирования сбоев, отправки оповещений или принятия действий восстановления, когда Claude не может завершить ответ из-за ограничений скорости, проблем аутентификации или других ошибок API.
Ввод StopFailure
Помимо общих полей ввода, hooks StopFailure получаютerror, опциональный error_details и опциональный last_assistant_message. Поле error определяет тип ошибки и используется для фильтрации matcher.
TeammateIdle
Запускается, когда товарищ команды агентов собирается перейти в режим ожидания после завершения своего хода. Используйте это для применения шлюзов качества перед остановкой товарища, такие как требование прохождения проверок lint или проверка существования выходных файлов. Hooks TeammateIdle не поддерживают matchers и срабатывают при каждом возникновении.Ввод TeammateIdle
Помимо общих полей ввода, hooks TeammateIdle получаютteammate_name и team_name.
Управление решением TeammateIdle
Hooks TeammateIdle поддерживают два способа управления поведением товарища:- Код выхода 2: товарищ получает сообщение stderr как обратную связь и продолжает работать вместо перехода в режим ожидания.
- JSON
{"continue": false, "stopReason": "..."}: полностью останавливает товарища, совпадая с поведением hookStop.stopReasonпоказывается пользователю.
ConfigChange
Запускается, когда файл конфигурации изменяется во время сеанса. Используйте это для аудита изменений параметров, применения политик безопасности или блокировки несанкционированных изменений файлов конфигурации. Claude Code запускает hooks ConfigChange, когда файл параметров, файл управляемой политики или файл skill изменяется. Для управляемой политики он запускает их только, когдаmanaged-settings.json или файл в managed-settings.d/ изменяется. Он применяет параметры, управляемые сервером и изменения в macOS управляемых предпочтениях или политике реестра Windows без их запуска. На WSL с wslInheritsWindowsSettings он также применяет измененный файл управляемых параметров Windows на его опросе политики без их запуска.
Matcher фильтрует по источнику конфигурации:
Этот пример логирует все изменения конфигурации для аудита безопасности:
Ввод ConfigChange
Помимо общих полей ввода, hooks ConfigChange получаютsource и опционально file_path. Поле source указывает, какой тип конфигурации изменился, и file_path предоставляет путь к конкретному файлу, который был изменен.
Управление решением ConfigChange
Hooks ConfigChange могут блокировать изменения конфигурации от вступления в силу. Используйте код выхода 2 или JSONdecision для предотвращения изменения. При блокировке новые параметры не применяются к работающему сеансу.
policy_settings не могут быть заблокированы. Hooks все еще срабатывают для источников policy_settings, когда файл управляемых параметров на машине изменяется, поэтому вы можете использовать их для логирования этих редактирований, но любое решение блокировки игнорируется. Это гарантирует, что параметры, управляемые предприятием, всегда вступают в силу. Claude Code не запускает hooks ConfigChange, когда прибывают или обновляются параметры, управляемые сервером.
Claude Code действует на решение блокировки из JSON-вывода hook ConfigChange и отбрасывает systemMessage и continue. Заблокированное изменение не выводит никакого сообщения вам или Claude, независимо от того, блокируете ли вы с reason или с stderr при выходе 2. Claude Code только записывает строку в debug log.
CwdChanged
Запускается, когда команда оболочки в основном разговоре изменяет рабочую директорию, например когда Claude выполняет командуcd. Используйте это для реакции на изменения директории: перезагрузка переменных окружения, активация цепочек инструментов для конкретного проекта или автоматический запуск скриптов настройки. Пары с FileChanged для инструментов, таких как direnv, которые управляют окружением для каждой директории.
Hooks CwdChanged имеют доступ к CLAUDE_ENV_FILE. Переменные, записанные в этот файл, сохраняются в последующих командах Bash до следующего события CwdChanged, когда Claude Code их очищает.
CwdChanged не поддерживает matchers и срабатывает при каждом возникновении.
Ввод CwdChanged
Помимо общих полей ввода, hooks CwdChanged получаютold_cwd и new_cwd.
Вывод CwdChanged
Помимо полей JSON-вывода, доступных всем hooks, hooks CwdChanged могут вернутьwatchPaths для динамической установки того, какие пути файлов FileChanged отслеживает:
Hooks CwdChanged не имеют управления решением. Они не могут блокировать изменение директории.
Claude Code читает
watchPaths и systemMessage из их JSON-вывода и отбрасывает continue. В интерактивных сеансах он показывает systemMessage как краткое уведомление терминала. Сообщение не достигает потока сообщений SDK.
DirectoryAdded
Запускается после добавления рабочей директории во время сеанса с командой/add-dir или после добавления клиентом SDK с запросом управления register_repo_root. Используйте это для подготовки вновь добавленного репозитория, например установки его зависимостей.
Claude Code не срабатывает это событие, когда:
- Вы передаете директорию с флагом запуска
--add-dir; SessionStart охватывает эти директории - Вы добавляете директорию на вкладку
/permissionsWorkspace - Вы добавляете директорию, которая уже является рабочей директорией или находится внутри одной
Ввод DirectoryAdded
Помимо общих полей ввода, hooks DirectoryAdded получаютdirectory и source.
continue из их JSON-вывода и выводит остальное по-разному в зависимости от источника:
slash_command: Claude Code доставляетsystemMessagehook Claude как контекст на следующем ходе разговора, а не показывает вам. Количество неудачных hooks появляется в транскрипте. Полный вывод сбоя идет в debug logregister_repo_root: Claude Code записывает выводsystemMessageи вывод сбоя только в debug log
FileChanged
Запускается, когда отслеживаемый файл изменяется на диске. Claude Code обнаруживает изменения с помощью наблюдателя файловой системы, а не путем проверки вызовов инструментов, поэтому он запускает hook независимо от того, что изменило файл: вызов инструментаEdit или Write, скрипт, который Claude запускает с Bash, или процесс вне Claude Code полностью. Обычное использование — перезагрузка переменных окружения при изменении файлов конфигурации проекта.
matcher для этого события служит двум целям:
- Построить список отслеживания: значение разделяется на
|и каждый сегмент регистрируется как буквальное имя файла в рабочей директории, поэтому".envrc|.env"отслеживает ровно эти два файла. Шаблоны regex не полезны здесь: значение, такое как^\.env, отслеживало бы файл буквально названный^\.env. - Фильтровать, какие hooks запускаются: когда отслеживаемый файл изменяется, то же значение фильтрует, какие группы hook запускаются, используя стандартные правила matcher против базового имени измененного файла.
data.csv после любого изменения, включая команду Bash или внешний скрипт, переписывающий файл:
file_path JSON-ввода на stdin. Его охрана grep тестирует то же самое, что perl удаляет, CR в конце строки, поэтому запуск после нормализации выходит без касания файла. Более слабая охрана зацикливается навсегда, потому что perl -i переписывает файл, даже когда он ничего не заменяет, и Claude Code запускает hook снова после каждой переписи. Сохраните этот скрипт в /path/to/normalize-line-endings.sh и сделайте его исполняемым:
data.csv с командой Bash. Claude Code запускает hook и файл заканчивается с окончаниями LF.
Чтобы отслеживать файлы, которые вы не можете назвать заранее, верните watchPaths из hook для динамического обновления списка отслеживания. Claude Code запускает наблюдатель только, когда что-то называет файл для отслеживания, поэтому заполните список группой FileChanged, чей matcher называет по крайней мере один файл, или с hook SessionStart или CwdChanged, который возвращает watchPaths. Matcher все еще фильтрует, какие группы hook запускаются, когда отслеживаемый файл изменяется, поэтому дайте группе, которая обрабатывает динамические пути, опущенный matcher, который совпадает с каждым отслеживаемым файлом и ничего не добавляет в список отслеживания. Matcher "*" также совпадает с каждым файлом, но Claude Code регистрирует его в списке отслеживания, как любое другое значение, как буквальный файл названный *.
Hooks FileChanged имеют доступ к CLAUDE_ENV_FILE. Переменные, записанные в этот файл, сохраняются в последующих командах Bash до следующего события CwdChanged, когда Claude Code их очищает.
Ввод FileChanged
Помимо общих полей ввода, hooks FileChanged получаютfile_path и event.
Вывод FileChanged
Помимо полей JSON-вывода, доступных всем hooks, hooks FileChanged могут вернутьwatchPaths для динамического обновления того, какие пути файлов отслеживаются:
Hooks FileChanged не имеют управления решением. Они не могут блокировать изменение файла от возникновения.
Claude Code читает
watchPaths и systemMessage из их JSON-вывода и отбрасывает continue. В интерактивных сеансах он показывает systemMessage как краткое уведомление терминала. Сообщение не достигает потока сообщений SDK.
WorktreeCreate
Запускается, когда создается worktree, будь то изclaude --worktree, из подагента, использующего isolation: "worktree", или для фонового сеанса, который Claude Code изолирует в своем собственном worktree. По умолчанию Claude Code создает изолированную рабочую копию с git worktree. Настройка hook WorktreeCreate заменяет это поведение git по умолчанию, позволяя вам использовать другую систему контроля версий, такую как SVN, Perforce или Mercurial.
Поскольку hook заменяет поведение по умолчанию полностью, .worktreeinclude не обрабатывается. Если вам нужно скопировать локальные файлы конфигурации, такие как .env, в новый worktree, сделайте это внутри вашего скрипта hook.
Hook должен вернуть путь к созданной директории worktree. Claude Code использует этот путь как рабочую директорию для изолированного сеанса. См. WorktreeCreate output для того, как каждый тип hook возвращает путь.
Claude Code действует на успех hook и возвращенный путь и отбрасывает systemMessage и continue.
Этот пример создает рабочую копию SVN и выводит путь для использования Claude Code. Замените URL репозитория на свой собственный:
name worktree из JSON-ввода на stdin, проверяет свежую копию в новую директорию и выводит путь директории. echo на последней строке — это то, что Claude Code читает как путь worktree. Перенаправьте любой другой вывод в stderr, чтобы он не мешал пути.
Ввод WorktreeCreate
Помимо общих полей ввода, hooks WorktreeCreate получают полеname. Это идентификатор slug для нового worktree, либо указанный пользователем, либо автоматически сгенерированный, например bold-oak-a3f2.
Вывод WorktreeCreate
Hooks WorktreeCreate не используют стандартную модель решения разрешить/блокировать. Вместо этого успех или сбой hook определяет результат. Hook должен вернуть путь к созданной директории worktree:- Command hooks (
type: "command"): выведите путь как последнюю непустую строку stdout. Claude Code удаляет коды ANSI перед чтением этой строки, поэтому баннеры запуска оболочки, выведенные перед вашимecho, игнорируются. Перенаправьте любой другой вывод hook в stderr. - HTTP hooks (
type: "http"): верните{ "hookSpecificOutput": { "hookEventName": "WorktreeCreate", "worktreePath": "/absolute/path" } }в теле ответа.
. или .. в нем. Если результирующий путь не является директорией, которую Claude Code может ввести, сеанс выводит ошибку с названием пути и выходит с кодом 1.
Claude Code отказывает абсолютному пути, который содержит сегменты . или .., и любому пути, который проходит через символическую ссылку ниже корня репозитория, потому что символическая ссылка, зафиксированная в репозитории, может перенаправить worktree вне его. Ошибка называет отклоненный компонент. Верните нормализованный путь, который не проходит через символическую ссылку внутри репозитория. До версии 2.1.216 создание worktree следовало пути hook без этого скрининга.
WorktreeRemove
Запускается, когда worktree удаляется. Это очистка, соответствующая WorktreeCreate. Событие срабатывает, когда:- вы выходите из сеанса
--worktreeи выбираете его удаление - подагент с
isolation: "worktree"завершается - вы удаляете фоновый сеанс, чей worktree создал hook
git worktree remove. Если вы настроили hook WorktreeCreate для системы контроля версий, не основанной на git, свяжите его с hook WorktreeRemove для обработки очистки. Без него директория worktree остается на диске.
Claude Code отбрасывает поля JSON-вывода hook WorktreeRemove, такие как systemMessage и continue.
Для удаления фонового сеанса Claude Code проверяет сохраненный путь worktree перед запуском hook и отказывает пути, который является символической ссылкой или проходит через одну ниже корня репозитория. Hook запускается для worktree, который все еще содержит файлы только, когда вы подтверждаете удаление в agent view; для такого worktree claude rm сохраняет сеанс и worktree вместо этого. До версии 2.1.216 hook запускался на сохраненном пути без этих проверок.
Claude Code передает путь, возвращенный WorktreeCreate, как worktree_path в ввод hook. Этот пример читает этот путь и удаляет директорию:
Ввод WorktreeRemove
Помимо общих полей ввода, hooks WorktreeRemove получают полеworktree_path, которое является абсолютным путем к удаляемому worktree.
worktree_path все еще существует после этого, удаление не удается:
- Worktree остается на диске, и команда hook и stderr идут в debug log.
- Если вы удаляли фоновый сеанс, сеанс остается тоже. Сообщение отказа в agent view сообщает, как закончился hook, такой как
exited 1, цитирует начало его stderr и говорит, удаляет ли удаление сеанса снова директорию в любом случае.
PreCompact
Запускается перед тем, как Claude Code собирается запустить операцию compact. Значение matcher указывает, было ли сжатие запущено вручную или автоматически:
Выйдите с кодом 2 для блокировки сжатия. Для ручного
/compact сообщение stderr показывается пользователю. Вы также можете блокировать, возвращая JSON с "decision": "block".
Блокировка автоматического сжатия имеет разные эффекты в зависимости от того, когда оно срабатывает. Если сжатие было запущено упреждающе перед пределом контекста, Claude Code пропускает его и разговор продолжается несжатым. Если сжатие было запущено для восстановления от ошибки лимита контекста, уже возвращенной API, основная ошибка выводится и текущий запрос не удается.
Claude Code отбрасывает поля systemMessage и continue hook PreCompact.
Ввод PreCompact
Помимо общих полей ввода, hooks PreCompact получаютtrigger и custom_instructions. Для manual, custom_instructions содержит то, что пользователь передает в /compact и имеет значение null, когда они ничего не передают. Для auto, custom_instructions имеет значение null.
PostCompact
Запускается после завершения операции compact Claude Code. Используйте это событие для реакции на новое сжатое состояние, например для логирования сгенерированного резюме или обновления внешнего состояния. Claude Code отбрасывает поляsystemMessage и continue hook PostCompact.
Те же значения matcher применяются, как для PreCompact:
Ввод PostCompact
Помимо общих полей ввода, hooks PostCompact получаютtrigger и compact_summary. Поле compact_summary содержит резюме разговора, сгенерированное операцией compact.
PreModelSwitch
Запускается перед применением переключения модели, которое вы или клиент запросили. Используйте это для блокировки переключения, требования подтверждения или показа стоимости переключения перед его выполнением. PreModelSwitch требует Claude Code v2.1.251 или позже. Claude Code запускает его для этих запросов:/model <name>и средство выбора/model- Средство выбора модели
Option+PилиAlt+P - Параметр Model в
/config - Включение fast mode, когда это изменяет модель сеанса
- Запрос
set_modelили изменение модели в запросеapply_flag_settingsот хоста Agent SDK или Remote Control
[1m]. Псевдоним, такой как opus, датированный ID модели и ID, специфичный для поставщика, такой как ID модели Amazon Bedrock, все совпадают с одним каноническим именем, на которое они разрешаются, поэтому claude-opus-5 охватывает каждое написание Opus 5.
Когда Claude Code не может определить каноническое имя для цели, например пользовательский ID модели, который знает только ваш LLM gateway, он запускает каждый hook PreModelSwitch независимо от matcher. Hook, который блокирует, должен поэтому проверить to_model из своего ввода, а не полагаться только на matcher.
Напишите matcher как точное имя, список, разделенный |, такой как claude-opus-4-6|claude-opus-5, или регулярное выражение, такое как .*opus.*. Этот пример использует matcher точного имени и также проверяет to_model из ввода hook, поэтому он отказывает переключению на Opus 4.6 выходом 2 и позволяет любой другой цели пройти:
- macOS/Linux
- Windows (PowerShell)
Команда проверяет
to_model с jq:/model claude-opus-4-6 из сеанса, работающего на другой модели. Claude Code сохраняет текущую модель и сообщает, что hook PreModelSwitch заблокировал переключение, с вашим сообщением как причиной.
Ввод PreModelSwitch
Помимо общих полей ввода, hooks PreModelSwitch получают поля в этой таблице. Последние пять описывают, что стоит повторная отправка разговора на новую модель, поэтому hook может показать эту цифру перед переключением.
Этот пример показывает ввод для
/model opus в сеансе, работающем на Sonnet 5:
Управление решением PreModelSwitch
HooksPreModelSwitch могут отменить переключение, попросить пользователя подтвердить его или позволить ему продолжить. Код выхода 2 или decision: "block" верхнего уровня отменяет переключение.
Для более тонкого управления, верните permissionDecision и permissionDecisionReason в объекте hookSpecificOutput, как на PreToolUse. PreModelSwitch принимает "allow", "deny" и "ask". Он не принимает "defer", updatedInput или additionalContext. Таблица ниже описывает оба поля:
Только
/model в интерактивном сеансе может показать подсказку "ask". На каждой другой поверхности, включая неинтерактивный режим с флагом -p, /config и запросы set_model, Claude Code рассматривает "ask" как отказ.
Этот пример просит пользователя подтвердить и цитирует количество токенов из context_tokens:
deny > ask > allow.
Claude Code показывает пользователю любой systemMessage, который возвращает ваш hook, независимо от решения, поэтому hook отчета стоимости может вернуть {"systemMessage": "..."} и выйти 0.
Hook PreModelSwitch, который не отвечает перед своим тайм-аутом, блокирует переключение. На PreToolUse, в отличие от этого, тайм-аут command hook позволяет вызову инструмента продолжить. Тайм-аут по умолчанию для этого события составляет 30 секунд. PreModelSwitch запускает только hooks command, http и mcp_tool, поэтому стандарты prompt и agent не применяются.
Hook, который выходит с кодом, отличным от 0 или 2, и не выводит JSON решение, не блокирует: Claude Code показывает его stderr и применяет переключение, как описано в Other exit codes.
PostModelSwitch
Запускается после изменения модели сеанса. Используйте это для предоставления руководства, специфичного для модели, без редактирования каждого CLAUDE.md, например организационной инструкции, которая применяется на определенных моделях. PostModelSwitch требует Claude Code v2.1.251 или позже. Он не может блокировать, потому что модель уже изменилась. Claude Code запускает hooks PostModelSwitch после любого из этих изменений:- Переключение, которое вы или клиент запросили
- Автоматический fallback модели, который изменяет модель сеанса
- Параметр, такой как
opusplan, входящий или выходящий из режима плана - Claude Code восстанавливает модель при возобновлении сеанса
/model opus из сеанса Sonnet, затем спросите Claude, какое руководство оно имеет о текущей модели.
Ввод PostModelSwitch
Hooks PostModelSwitch получают те же поля, что и PreModelSwitch, сhook_event_name, установленным на "PostModelSwitch", и двумя дополнительными значениями source: "auto" для автоматического fallback или другого изменения, которое Claude Code сделал самостоятельно, и "resume" для модели, восстановленной при возобновлении сеанса.
requested_model имеет значение null, когда source имеет значение "auto". Когда source имеет значение "resume", это сохраненный параметр модели, который Claude Code восстановил.
Управление решением PostModelSwitch
Claude Code берет ваш простой текст stdout hook при выходе 0 илиadditionalContext из JSON-вывода и доставляет его Claude со следующим запросом после переключения. Помимо полей JSON-вывода, доступных всем hooks, вы можете вернуть:
Если hook не завершится в течение пяти секунд после отправки следующей подсказки, Claude Code отправляет этот запрос без вывода и прикрепляет его к следующему запросу вместо этого. Если модель изменяется несколько раз перед следующим запросом, Claude Code доставляет только вывод для переключения целевой модели последнего.
SessionEnd
Запускается, когда сеанс Claude Code заканчивается. Полезно для задач очистки, логирования статистики сеанса или сохранения состояния сеанса. Поддерживает matchers для фильтрации по причине выхода. Полеreason в ввод hook указывает, почему сеанс закончился:
Ввод SessionEnd
Помимо общих полей ввода, hooks SessionEnd получают полеreason, указывающее, почему сеанс закончился. См. таблицу причин выше для всех значений.
systemMessage.
Hooks SessionEnd имеют тайм-аут по умолчанию 1.5 секунды. Он применяется, когда вы выходите, запускаете /clear или переключаете сеансы с интерактивным /resume. Вы можете дать hook больше времени двумя способами:
- Per-hook
timeout: установитеtimeoutв конфигурации этого hook. Общий бюджет автоматически повышается, чтобы совпадать с наивысшимtimeoutper-hook в ваших файлах параметров, до 60 секунд. Если вы повышаете бюджет таким образом, hook без своего собственногоtimeoutвсе еще сохраняет стандарт. Тайм-ауты, установленные на hooks, предоставленные плагином, не повышают бюджет. CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS: установите эту переменную окружения в миллисекундах для явного переопределения бюджета. Значение, которое вы установили, также становится тайм-аутом для каждого hook без своего собственногоtimeout.
CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS повышал только общий бюджет, и hook без своего собственного timeout все еще отменялся через 1.5 секунды.
Elicitation
Запускается, когда сервер MCP запрашивает ввод пользователя во время задачи. По умолчанию Claude Code показывает интерактивный диалог для ответа пользователя. Hooks могут перехватить этот запрос и ответить программно, полностью пропустив диалог. Поле matcher совпадает с названием сервера MCP.Ввод Elicitation
Помимо общих полей ввода, hooks Elicitation получаютmcp_server_name, message и опциональные mode, url, elicitation_id и requested_schema поля.
Для запроса в режиме формы, наиболее распространенный случай:
Вывод Elicitation
Чтобы ответить программно без показа диалога, верните объект JSON сhookSpecificOutput:
Код выхода 2 отклоняет запрос. Claude Code не показывает ваше сообщение stderr нигде.
Claude Code действует на
hookSpecificOutput из JSON-вывода hook Elicitation и отбрасывает systemMessage и continue.
ElicitationResult
Запускается после того, как пользователь ответит на запрос MCP. Hooks могут наблюдать, изменять или блокировать ответ перед его отправкой обратно на сервер MCP. Поле matcher совпадает с названием сервера MCP.Ввод ElicitationResult
Помимо общих полей ввода, hooks ElicitationResult получаютmcp_server_name, action и опциональные mode, elicitation_id и content поля.
Вывод ElicitationResult
Чтобы переопределить ответ пользователя, верните объект JSON сhookSpecificOutput:
Код выхода 2 блокирует ответ, изменяя эффективное действие на
decline. Claude Code не показывает ваше сообщение stderr нигде.
Claude Code действует на hookSpecificOutput из JSON-вывода hook ElicitationResult и отбрасывает systemMessage и continue.
Prompt-based hooks
В дополнение к command, HTTP и MCP tool hooks, Claude Code поддерживает prompt-based hooks (type: "prompt"), которые используют LLM для оценки разрешения или блокировки действия, и agent hooks (type: "agent"), которые порождают агентного верификатора с доступом к инструментам. Не все события поддерживают каждый тип hook.
События, которые поддерживают все пять типов hook (command, http, mcp_tool, prompt и agent):
PermissionDeniedPostToolBatchPostToolUsePostToolUseFailurePreToolUseStopSubagentStopTaskCompletedTaskCreatedTeammateIdleUserPromptExpansionUserPromptSubmit
PermissionRequest поддерживает command, http, mcp_tool и prompt hooks, но не agent hooks. Если вы настроите agent hook на этом событии, Claude Code пропустит его и поток разрешений продолжится без изменений. Чтобы разрешить или отклонить из hook, верните объект решения из command или HTTP hook.
События, которые поддерживают command, http и mcp_tool hooks, но не prompt или agent:
ConfigChangeCwdChangedDirectoryAddedElicitationElicitationResultFileChangedInstructionsLoadedMessageDisplayNotificationPostCompactPostModelSwitchPreCompactPreModelSwitchSessionEndStopFailureSubagentStartWorktreeCreateWorktreeRemove
SessionStart и Setup поддерживают command и mcp_tool hooks, и MCP tool hook fields описывает, когда их mcp_tool hooks запускаются. Они не поддерживают http, prompt или agent hooks.
How prompt-based hooks work
Вместо выполнения команды Bash, prompt-based hooks:- Отправляют входные данные hook и вашу подсказку модели Claude, по умолчанию той, которую Claude Code использует для фоновой функциональности
- LLM отвечает структурированным JSON, содержащим решение
- Claude Code автоматически обрабатывает решение
Prompt hook configuration
Установитеtype на "prompt" и предоставьте строку prompt вместо command. Используйте заполнитель $ARGUMENTS для внедрения данных JSON входа hook в текст вашей подсказки.
Этот hook Stop просит LLM оценить, должен ли Claude остановиться перед разрешением Claude закончить:
Response schema
LLM должен ответить JSON, содержащим:
Что происходит при
ok: false, зависит от события:
StopиSubagentStop: причина передаётся обратно Claude как его следующая инструкция и ход продолжается, если только ответ также не устанавливаетimpossible: true, в этом случае Claude Code позволяет остановке и ход заканчиваетсяPreToolUse: вызов инструмента отклоняется; по умолчанию ход заканчивается и причина отказа появляется в чате как строка предупреждения. УстановитеcontinueOnBlock: trueдля возврата причины Claude как ошибки инструмента, чтобы он мог скорректировать и продолжить, эквивалентноpermissionDecision: "deny"из command hook. До v2.1.210 причина отказа возвращалась Claude как ошибка инструмента и ход продолжалсяPostToolUse: по умолчанию ход заканчивается и причина появляется в чате как строка предупреждения. УстановитеcontinueOnBlock: trueдля передачи причины обратно Claude и продолжения хода вместо этогоPostToolBatch,UserPromptSubmitиUserPromptExpansion: ход заканчивается и причина появляется как строка предупреждения. Эти события заканчивают ход наdecision: "block"независимо отcontinuePostToolUseFailureиTaskCreated: причина возвращается Claude как ошибка инструмента и ход продолжается, независимо отcontinueOnBlockTaskCompleted: когда он срабатывает, потому что задача отмечена как завершённая во время хода, причина возвращается Claude как ошибка инструмента и ход продолжается, независимо отcontinueOnBlock. Когда он срабатывает, потому что товарищ по команде останавливается, он ведёт себя какTeammateIdleи останавливает товарища по команде по умолчаниюTeammateIdle: по умолчанию товарищ по команде останавливается и причина появляется как строка предупреждения. УстановитеcontinueOnBlock: trueдля передачи причины обратно товарищу по команде и продолжения его работы вместо этогоPermissionRequest:ok: falseне имеет эффекта. Чтобы отклонить одобрение из hook, используйте command hook, возвращающийhookSpecificOutput.decision.behavior: "deny"PermissionDenied:ok: falseне имеет эффекта, потому что отказ уже произошёл. Единственный результат, который это событие читает, этоhookSpecificOutput.retry, который prompt и agent hooks не могут установить. Они запускаются на этом событии, но их результат отбрасывается. Используйте command hook для возвратаretry
Check multiple conditions before stopping
Этот hookStop использует подробную подсказку для проверки трёх условий перед разрешением Claude остановиться. Hooks SubagentStop используют тот же формат для оценки, должен ли subagent остановиться. Если модель возвращает "ok": false, потому что условие ещё не выполнено, Claude продолжает работать с предоставленной причиной как своей следующей инструкцией:
Agent-based hooks
Agent-based hooks (type: "agent") похожи на prompt-based hooks, но с многооборотным доступом к инструментам. Вместо одного вызова LLM, agent hook порождает subagent, который может читать файлы, искать код и проверять кодовую базу для проверки условий. Agent hooks поддерживают те же события, что и prompt-based hooks, за исключением PermissionRequest.
How agent hooks work
Когда срабатывает agent hook:- Claude Code порождает subagent с вашей подсказкой и JSON входом hook
- Subagent может использовать инструменты, такие как Read, Grep и Glob, для исследования
- После до 50 оборотов subagent возвращает структурированное решение
{ "ok": true/false } - Claude Code разрешает действие, если
okимеет значениеtrue. Еслиokимеет значениеfalse, Claude Code обрабатывает блокировку так же, как prompt hook сcontinueOnBlock: trueна этом событии, как указано в разделе Response schema
Agent hook configuration
Установитеtype на "agent" и предоставьте строку prompt, используя $ARGUMENTS как заполнитель для JSON входа hook. Поля конфигурации те же, что и prompt hooks, за исключением того, что agent hooks имеют более длинный таймаут по умолчанию в 60 секунд и не имеют поля continueOnBlock.
Схема ответа — это { "ok": true } для разрешения или { "ok": false, "reason": "..." } для блокировки. При ok: false, Claude Code обрабатывает agent hook так же, как он обрабатывает prompt hook с continueOnBlock: true на том же событии; agent hooks не имеют поля continueOnBlock и не поддерживают поле impossible из prompt hook.
Этот hook Stop проверяет, что все модульные тесты проходят перед разрешением Claude закончить:
Запуск hooks в фоне
По умолчанию hooks блокируют выполнение Claude до их завершения. Для долгоживущих задач, таких как развёртывания, наборы тестов или вызовы внешних API, установите"async": true для запуска hook в фоне, пока Claude продолжает работать. Асинхронные hooks не могут блокировать или управлять поведением Claude: поля ответа, такие как decision, permissionDecision и continue, не имеют эффекта, потому что действие, которое они контролировали, уже завершено.
Настройка асинхронного hook
Добавьте"async": true к конфигурации command hook для запуска его в фоне без блокировки Claude. Это поле доступно только на hooks type: "command".
Этот hook запускает скрипт тестирования после каждого вызова инструмента Write. Claude продолжает работать немедленно, пока run-tests.sh выполняется. Когда скрипт завершается, его выход доставляется на следующий ход разговора:
timeout к нему. Claude Code по-прежнему применяет timeout к hook, который вы запускаете с asyncRewake.
Claude Code доставляет результаты асинхронного hook только во время работы сеанса:
- В неинтерактивном режиме с флагом
-pClaude Code завершает любой асинхронный hook, который всё ещё работает при завершении, и завершает его с результатомcancelled - Если работа вашего hook должна пережить сеанс
claude -p, запустите полностью отделённый процесс из него
Как выполняются асинхронные hooks
Когда срабатывает асинхронный hook, Claude Code запускает процесс hook и немедленно продолжает без ожидания его завершения. Hook получает те же JSON входные данные через stdin, что и синхронный hook. После выхода фонового процесса Claude Code доставляет поляadditionalContext и systemMessage из JSON ответа hook к Claude на следующем ходу разговора. В отличие от systemMessage синхронного hook, ни одно из этих полей не показывается вам.
Claude Code проверяет, что JSON ответ соответствует той же схеме выходных данных, что и синхронные hooks, и отбрасывает любое поле, значение которого имеет неправильный тип, например systemMessage, который не является строкой, вместо его доставки. Запустите с --debug для просмотра предупреждения, называющего каждое отброшенное поле. До версии v2.1.202 неправильно сформированный JSON выход из асинхронного hook мог привести к сбою сеанса, и сбой повторялся каждый раз при возобновлении сеанса.
Уведомления о завершении асинхронного hook подавляются по умолчанию. Чтобы их увидеть, включите подробный режим с помощью Ctrl+O или запустите Claude Code с --verbose.
Запуск тестов после изменения файлов
Этот hook запускает набор тестов в фоне всякий раз, когда Claude пишет файл, затем сообщает результаты обратно Claude при завершении тестов. Сохраните этот скрипт в.claude/hooks/run-tests-async.sh в вашем проекте и сделайте его исполняемым с помощью chmod +x:
.claude/settings.json в корне вашего проекта. Флаг async: true позволяет Claude продолжать работу, пока тесты запускаются:
Ограничения
Асинхронные hooks имеют дополнительные ограничения по сравнению с синхронными hooks:- Выход hook доставляется на следующий ход разговора. Если сеанс неактивен, ответ ждёт до следующего взаимодействия пользователя. Исключение: hook
asyncRewake, который выходит с кодом 2, пробуждает Claude немедленно даже когда сеанс неактивен. - Каждое выполнение создаёт отдельный фоновый процесс. Нет дедупликации между несколькими срабатываниями одного и того же асинхронного hook.
Соображения безопасности
Отказ от ответственности
Доверие рабочей области
Claude Code проверяет доверие рабочей области перед запуском любого hook из файла параметров. Что считается доверенным, зависит от типа сеанса:- Интерактивный сеанс: Claude Code удерживает hooks из каждого файла параметров, включая ваш собственный
~/.claude/settings.json, пока вы не примете диалог доверия рабочей области для папки или для родительского каталога, чьё доверие распространяется на неё - Сеанс
-pили SDK: Claude Code никогда не показывает диалог и рассматривает папку как доверенную, поэтому hooks, зафиксированные в.claude/settings.jsonрепозитория, запускаются в папке, которой вы никогда не доверяли
claude -p над репозиторием, который вы не писали, проверьте его файлы параметров .claude/, начните с --bare или отключите hooks для этого запуска с помощью --settings '{"disableAllHooks": true}'. Frontmatter hooks в проектном подагенте следуют более строгому правилу, чем hooks файлов параметров. Что запускается перед доверием папке перечисляет каждый вид содержимого репозитория по типу сеанса.
Лучшие практики безопасности
Помните об этих практиках при написании hooks:- Проверяйте и санитизируйте входные данные: никогда не доверяйте входным данным вслепую
- Всегда заключайте переменные оболочки в кавычки: используйте
"$VAR"не$VAR - Блокируйте обход пути: проверяйте наличие
..в путях файлов - Используйте абсолютные пути: указывайте полные пути для скриптов. В форме exec используйте
${CLAUDE_PROJECT_DIR}и путь не требует кавычек. В форме shell оберните его в двойные кавычки - Пропускайте чувствительные файлы: избегайте
.env,.git/, ключей и т. д.
Windows PowerShell tool
На Windows вы можете запустить отдельные hooks в PowerShell, установив"shell": "powershell" на command hook. Claude Code автоматически обнаруживает pwsh.exe, исполняемый файл PowerShell 7 и более поздних версий, и переходит на powershell.exe для Windows PowerShell 5.1.
${CLAUDE_PROJECT_DIR} или $env:CLAUDE_PROJECT_DIR. Начиная с версии 2.1.198, Claude Code переписывает заполнители ${CLAUDE_PROJECT_DIR}, ${CLAUDE_PLUGIN_ROOT} и ${CLAUDE_PLUGIN_DATA} в команде PowerShell в форме shell в форму ${env:NAME} PowerShell, независимо от того, определён ли hook в settings.json, плагине или навыке. PowerShell затем разрешает значение из экспортированного окружения после анализа, поэтому заполнитель работает внутри строк в двойных кавычках, но не внутри строк в одинарных кавычках, где PowerShell никогда не расширяет переменные.
До версии 2.1.198 эта переписка применялась только к plugin hooks. В более ранних версиях hook в settings.json требует формы $env: или exec form, где ${CLAUDE_PROJECT_DIR} подставляется в каждый элемент args независимо от того, где определён hook.
Не пишите простое написание $CLAUDE_PROJECT_DIR в hook PowerShell. PowerShell анализирует его как неопределённую локальную переменную и разрешает её в $null, что оставляет путь скрипта без префикса корневого каталога проекта. Claude Code не переписывает эту форму; вместо этого она регистрирует предупреждение в debug log.
Пример ниже показывает hook в settings.json, который запускает скрипт проекта с формой $env:, которая работает на каждой версии:
Debug hooks
Детали выполнения hooks записываются в файл отладочного журнала. Запустите Claude Code сclaude --debug-file <path> для записи журнала в известное расположение, или запустите claude --debug и прочитайте журнал в ~/.claude/debug/<session-id>.txt. Флаг --debug не выводит на терминал.
Например, hook PostToolUse на Write, чья команда выводит hook-ran, создаёт записи вроде:
CLAUDE_CODE_DEBUG_LOG_LEVEL=verbose для просмотра дополнительных строк логирования, таких как количество совпадений фильтра hook и совпадение запроса.
Для устранения неполадок распространённых проблем, таких как hooks, которые не срабатывают, Stop hooks, которые продолжают блокировать, или ошибки конфигурации, см. Limitations and troubleshooting в руководстве. Для более широкого диагностического пошагового руководства, охватывающего /context, /doctor и приоритет параметров, см. Debug your config.