16 Жизненный цикл hook16 Жизненный цикл hook
17</h2>17</h2>
18 18
19Hooks срабатывают в определённых точках во время сеанса Claude Code. Когда событие срабатывает и совпадает с фильтром, Claude Code передаёт JSON-контекст события вашему обработчику hook. Для command hooks входные данные поступают на stdin. Для HTTP hooks они поступают как тело POST-запроса. Ваш обработчик может затем проверить входные данные, выполнить действие и опционально вернуть решение. События срабатывают в трёх ритмах: один раз за сеанс (`SessionStart`, `SessionEnd`), один раз за ход (`UserPromptSubmit`, `Stop`, `StopFailure`) и при каждом вызове инструмента внутри агентного цикла (`PreToolUse`, `PostToolUse`):19Hooks срабатывают в определённых точках во время сеанса Claude Code. Когда событие срабатывает и совпадает с фильтром, Claude Code передаёт JSON-контекст события вашему обработчику hook. Для command hooks входные данные поступают на stdin. Для HTTP hooks они поступают как тело POST-запроса. Ваш обработчик может затем проверить входные данные, выполнить действие и опционально вернуть решение.
20
21События срабатывают в трёх ритмах:
22
23* один раз за сеанс: `SessionStart` и `SessionEnd`
24* один раз за ход: `UserPromptSubmit`, `Stop` и `StopFailure`
25* при каждом вызове инструмента внутри агентного цикла: `PreToolUse` и `PostToolUse`
20 26
21<div style={{maxWidth: "500px", margin: "0 auto"}}>27<div style={{maxWidth: "500px", margin: "0 auto"}}>
22 <Frame>28 <Frame>
214| `SessionStart` | как сеанс начался | `startup`, `resume`, `clear`, `compact` |220| `SessionStart` | как сеанс начался | `startup`, `resume`, `clear`, `compact` |
215| `Setup` | какой флаг CLI запустил setup | `init`, `maintenance` |221| `Setup` | какой флаг CLI запустил setup | `init`, `maintenance` |
216| `SessionEnd` | почему сеанс закончился | `clear`, `resume`, `logout`, `prompt_input_exit`, `bypass_permissions_disabled`, `other` |222| `SessionEnd` | почему сеанс закончился | `clear`, `resume`, `logout`, `prompt_input_exit`, `bypass_permissions_disabled`, `other` |
217| `Notification` | тип уведомления | `permission_prompt`, `idle_prompt`, `auth_success`, `elicitation_dialog`, `elicitation_complete`, `elicitation_response` |223| `Notification` | тип уведомления | `permission_prompt`, `idle_prompt`, `auth_success`, `elicitation_dialog`, `elicitation_complete`, `elicitation_response`, `agent_needs_input`, `agent_completed` |
218| `SubagentStart` | тип агента | `general-purpose`, `Explore`, `Plan`, пользовательские имена агентов или имена с областью плагина, такие как `^my-plugin:reviewer$` |224| `SubagentStart` | тип агента | `general-purpose`, `Explore`, `Plan`, пользовательские имена агентов или имена с областью плагина, такие как `^my-plugin:reviewer$` |
219| `PreCompact`, `PostCompact` | что вызвало компактирование | `manual`, `auto` |225| `PreCompact`, `PostCompact` | что вызвало компактирование | `manual`, `auto` |
220| `SubagentStop` | тип агента | те же значения, что и `SubagentStart` |226| `SubagentStop` | тип агента | те же значения, что и `SubagentStart` |
317 323
318Все совпадающие hooks запускаются параллельно, и идентичные обработчики автоматически дедублируются. Command hooks дедублируются по строке команды и `args`, а HTTP hooks дедублируются по URL.324Все совпадающие hooks запускаются параллельно, и идентичные обработчики автоматически дедублируются. Command hooks дедублируются по строке команды и `args`, а HTTP hooks дедублируются по URL.
319 325
320Обработчики запускаются в текущем каталоге с окружением Claude Code. Переменная окружения `$CLAUDE_CODE_REMOTE` устанавливается на `"true"` в удалённых веб-окружениях и не устанавливается в локальном CLI.326Обработчики запускаются в текущем каталоге с окружением Claude Code. Переменная окружения `$CLAUDE_CODE_REMOTE` устанавливается на `"true"` в удалённых веб-окружениях и не устанавливается в локальном CLI. {/* min-version: 2.1.199 */}Начиная с v2.1.199, [`$CLAUDE_CODE_BRIDGE_SESSION_ID`](/ru/env-vars) устанавливается на ID сеанса [Remote Control](/ru/remote-control) пока локальный сеанс имеет активное соединение Remote Control.
321 327
322<h4 id="common-fields">328<h4 id="common-fields">
323 Common fields329 Common fields
704Exit code 2 — это способ hook сигнализировать "стоп, не делай этого". Эффект зависит от события, потому что некоторые события представляют действия, которые могут быть заблокированы (например, вызов инструмента, который ещё не произошёл), а другие представляют вещи, которые уже произошли или не могут быть предотвращены.710Exit code 2 — это способ hook сигнализировать "стоп, не делай этого". Эффект зависит от события, потому что некоторые события представляют действия, которые могут быть заблокированы (например, вызов инструмента, который ещё не произошёл), а другие представляют вещи, которые уже произошли или не могут быть предотвращены.
705 711
706| Hook событие | Может блокировать? | Что происходит при exit 2 |712| Hook событие | Может блокировать? | Что происходит при exit 2 |
707| :-------------------- | :----------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------- |713| :-------------------- | :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
708| `PreToolUse` | Да | Блокирует вызов инструмента |714| `PreToolUse` | Да | Блокирует вызов инструмента |
709| `PermissionRequest` | Да | Отклоняет разрешение |715| `PermissionRequest` | Да | Отклоняет разрешение |
710| `UserPromptSubmit` | Да | Блокирует обработку подсказки и стирает подсказку |716| `UserPromptSubmit` | Да | Блокирует обработку подсказки и стирает подсказку |
711| `UserPromptExpansion` | Да | Блокирует расширение |717| `UserPromptExpansion` | Да | Блокирует расширение |
712| `Stop` | Да | Предотвращает остановку Claude, продолжает разговор |718| `Stop` | Да | Предотвращает остановку Claude, продолжает разговор |
713| `SubagentStop` | Да | Предотвращает остановку subagent |719| `SubagentStop` | Да | Предотвращает остановку subagent |
714| `TeammateIdle` | Да | Предотвращает переход товарища в режим ожидания (товарищ продолжает работать) |720| `TeammateIdle` | Да | Предотвращает переход товарища в режим ожидания, так что он продолжает работать |
715| `TaskCreated` | Да | Откатывает создание задачи |721| `TaskCreated` | Да | Откатывает создание задачи |
716| `TaskCompleted` | Да | Предотвращает отметку задачи как завершённой |722| `TaskCompleted` | Да | Предотвращает отметку задачи как завершённой |
717| `ConfigChange` | Да | Блокирует применение изменения конфигурации (кроме `policy_settings`) |723| `ConfigChange` | Да | Блокирует применение изменения конфигурации (кроме `policy_settings`) |
718| `StopFailure` | Нет | Выход и код выхода игнорируются |724| `StopFailure` | Нет | Выход и код выхода игнорируются |
719| `PostToolUse` | Нет | Показывает stderr Claude (инструмент уже запустился) |725| `PostToolUse` | Нет | Показывает stderr Claude; инструмент уже запустился |
720| `PostToolUseFailure` | Нет | Показывает stderr Claude (инструмент уже не удался) |726| `PostToolUseFailure` | Нет | Показывает stderr Claude; инструмент уже не удался |
721| `PostToolBatch` | Да | Останавливает цикл агента перед следующим вызовом модели |727| `PostToolBatch` | Да | Останавливает цикл агента перед следующим вызовом модели |
722| `PermissionDenied` | Нет | Код выхода и stderr игнорируются (отказ уже произошёл). Используйте JSON `hookSpecificOutput.retry: true` для сообщения модели, что она может повторить попытку |728| `PermissionDenied` | Нет | Код выхода и stderr игнорируются, потому что отказ уже произошёл. Используйте JSON `hookSpecificOutput.retry: true` для сообщения модели, что она может повторить попытку |
723| `Notification` | Нет | Показывает stderr только пользователю |729| `Notification` | Нет | Показывает stderr только пользователю |
724| `SubagentStart` | Нет | Показывает stderr только пользователю |730| `SubagentStart` | Нет | Показывает stderr только пользователю |
725| `SessionStart` | Нет | Показывает stderr только пользователю |731| `SessionStart` | Нет | Показывает stderr только пользователю |
736| `InstructionsLoaded` | Нет | Код выхода игнорируется |742| `InstructionsLoaded` | Нет | Код выхода игнорируется |
737| `MessageDisplay` | Нет | Исходный текст отображается |743| `MessageDisplay` | Нет | Исходный текст отображается |
738 744
745Для `SessionStart`, `Setup` и `SubagentStart` stderr exit code 2 отображается в транскрипте как уведомление об ошибке `<hook name> hook error`, так же как [неблокирующая ошибка](#exit-code-output). Claude не видит это, и сеанс или subagent продолжается. Для `SubagentStart` уведомление появляется в собственном транскрипте subagent, а не в родительском разговоре.
746
747Начиная с Claude Code v2.1.199, `SessionStart`, `Setup` и `SubagentStart` показывают stderr exit code 2 в транскрипте. Более ранние версии записывали это только в журнал отладки.
748
739<h3 id="http-response-handling">749<h3 id="http-response-handling">
740 Обработка HTTP ответа750 Обработка HTTP ответа
741</h3>751</h3>
963 SessionStart input973 SessionStart input
964</h4>974</h4>
965 975
966В дополнение к [общим полям входа](#common-input-fields), SessionStart hooks получают `source` и опционально `model`, `agent_type` и `session_title`. Поле `source` указывает, как был запущен сеанс: `"startup"` для новых сеансов, `"resume"` для возобновлённых сеансов, `"clear"` после `/clear` или `"compact"` после компактирования. Поле `model` содержит идентификатор активной модели. Оно может быть опущено, например после `/clear` или когда сеанс восстанавливается через восстановление разговора, поэтому проверьте поле перед его чтением. Если вы запустите Claude Code с `claude --agent <name>`, поле `agent_type` содержит имя агента. Поле `session_title` содержит текущее название сеанса, если оно уже установлено, например через `--name` или `/rename`. Hook, который выдаёт `sessionTitle`, может сначала проверить `session_title`, чтобы избежать перезаписи названия, которое пользователь установил явно.976В дополнение к [общим полям входа](#common-input-fields), SessionStart hooks получают `source` и опционально `model`, `agent_type` и `session_title`:
977
978| Поле | Описание |
979| :-------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
980| `source` | Как был запущен сеанс: `"startup"` для новых сеансов, `"resume"` для возобновлённых сеансов, `"clear"` после `/clear` или `"compact"` после компактирования |
981| `model` | Идентификатор активной модели. Может быть опущено, например после `/clear` или когда сеанс восстанавливается через восстановление разговора, поэтому проверьте поле перед его чтением |
982| `agent_type` | Имя агента, присутствует при запуске Claude Code с `claude --agent <name>` |
983| `session_title` | Текущее название сеанса, если оно уже установлено, например через `--name` или `/rename`. Hook, который выдаёт `sessionTitle`, может сначала проверить `session_title`, чтобы избежать перезаписи названия, которое пользователь установил явно |
967 984
968```json theme={null}985```json theme={null}
969{986{
983Любой текст, который ваш скрипт hook выводит на stdout, добавляется как контекст для Claude. В дополнение к [JSON полям выхода](#json-output), доступным для всех hooks, вы можете вернуть эти поля, специфичные для события:1000Любой текст, который ваш скрипт hook выводит на stdout, добавляется как контекст для Claude. В дополнение к [JSON полям выхода](#json-output), доступным для всех hooks, вы можете вернуть эти поля, специфичные для события:
984 1001
985| Поле | Описание |1002| Поле | Описание |
986| :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1003| :------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
987| `additionalContext` | Строка, добавленная в контекст Claude в начале разговора, перед первой подсказкой. См. [Add context for Claude](#add-context-for-claude) для того, как текст доставляется и что в него поместить |1004| `additionalContext` | Строка, добавленная в контекст Claude в начале разговора, перед первой подсказкой. См. [Add context for Claude](#add-context-for-claude) для того, как текст доставляется и что в него поместить |
988| `initialUserMessage` | Строка, используемая как первое сообщение пользователя сеанса. Применяется в [неинтерактивном режиме](/ru/headless) (`-p`), где оно становится первым ходом, даже если подсказка не предоставлена. Если подсказка предоставлена, она следует как следующий ход. В отличие от `additionalContext`, который присоединяется к существующему ходу, это создаёт ход |1005| `initialUserMessage` | Строка, используемая как первое сообщение пользователя сеанса. Применяется в [неинтерактивном режиме](/ru/headless) с флагом `-p`, где оно становится первым ходом, даже если подсказка не предоставлена. Если подсказка предоставлена, она следует как следующий ход. В отличие от `additionalContext`, который присоединяется к существующему ходу, это создаёт ход |
989| `sessionTitle` | Устанавливает название сеанса, с тем же эффектом, что и `/rename`. Используйте для автоматического именования сеансов из папки запуска, ветки git или имени worktree. Применяется только когда `source` равен `"startup"` или `"resume"`; игнорируется на `"clear"` и `"compact"` |1006| `sessionTitle` | Устанавливает название сеанса, с тем же эффектом, что и `/rename`. Используйте для автоматического именования сеансов из папки запуска, ветки git или имени worktree. Применяется только когда `source` равен `"startup"` или `"resume"`; игнорируется на `"clear"` и `"compact"` |
990| `watchPaths` | Массив абсолютных путей для отслеживания событий [FileChanged](#filechanged) во время этого сеанса |1007| `watchPaths` | Массив абсолютных путей для отслеживания событий [FileChanged](#filechanged) во время этого сеанса |
991| `reloadSkills` | Логическое значение. Когда `true`, Claude Code повторно сканирует каталоги [skill](/ru/skills) и команд после завершения SessionStart hooks, поэтому skills, которые установил hook, доступны в том же сеансе, начиная с первой подсказки |1008| `reloadSkills` | Логическое значение. Когда `true`, Claude Code повторно сканирует каталоги [skill](/ru/skills) и команд после завершения SessionStart hooks, поэтому skills, которые установил hook, доступны в том же сеансе, начиная с первой подсказки |
1062 Setup1079 Setup
1063</h3>1080</h3>
1064 1081
1065Срабатывает только при запуске Claude Code с `--init-only` или с `--init` или `--maintenance` в режиме печати (`-p`). Не срабатывает при нормальном запуске. Используйте это для одноразовой установки зависимостей или запланированной очистки, которую вы запускаете явно из CI или скриптов, отдельно от нормального запуска сеанса. Для инициализации для каждого сеанса используйте [SessionStart](#sessionstart) вместо этого.1082Срабатывает только при запуске Claude Code с `--init-only` или с `--init` или `--maintenance` в [неинтерактивном режиме](/ru/headless) с флагом `-p`. Не срабатывает при нормальном запуске. Используйте это для одноразовой установки зависимостей или запланированной очистки, которую вы запускаете явно из CI или скриптов, отдельно от нормального запуска сеанса. Для инициализации для каждого сеанса используйте [SessionStart](#sessionstart) вместо этого.
1066 1083
1067Значение фильтра соответствует флагу CLI, который запустил hook:1084Значение фильтра соответствует флагу CLI, который запустил hook:
1068 1085
1071| `init` | `claude --init-only` или `claude -p --init` |1088| `init` | `claude --init-only` или `claude -p --init` |
1072| `maintenance` | `claude -p --maintenance` |1089| `maintenance` | `claude -p --maintenance` |
1073 1090
1074`--init-only` запускает Setup hooks и SessionStart hooks с фильтром `startup`, затем выходит без запуска разговора. `--init` и `--maintenance` срабатывают Setup hooks только при объединении с `-p` (режим печати); в интерактивном сеансе эти два флага в настоящее время не срабатывают Setup hooks.1091`--init-only` запускает Setup hooks и SessionStart hooks с фильтром `startup`, затем выходит без запуска разговора. `--init` и `--maintenance` срабатывают Setup hooks только при объединении с `-p`; в интерактивном сеансе эти два флага в настоящее время не срабатывают Setup hooks.
1075 1092
1076Поскольку Setup не срабатывает при каждом запуске, плагин, которому нужна установленная зависимость, не может полагаться только на Setup. Практический паттерн — проверить зависимость при первом использовании и установить при отсутствии, например hook или skill, который проверяет `${CLAUDE_PLUGIN_DATA}/node_modules` и запускает `npm install` при отсутствии. См. [persistent data directory](/ru/plugins-reference#persistent-data-directory) для того, где хранить установленные зависимости.1093Поскольку Setup не срабатывает при каждом запуске, плагин, которому нужна установленная зависимость, не может полагаться только на Setup. Практический паттерн — проверить зависимость при первом использовании и установить при отсутствии, например hook или skill, который проверяет `${CLAUDE_PLUGIN_DATA}/node_modules` и запускает `npm install` при отсутствии. См. [persistent data directory](/ru/plugins-reference#persistent-data-directory) для того, где хранить установленные зависимости.
1077 1094
1095 Setup decision control1112 Setup decision control
1096</h4>1113</h4>
1097 1114
1098Setup hooks не могут блокировать. При exit code 2 stderr показывается пользователю; при любом другом ненулевом exit code stderr появляется только при запуске с `--verbose`. В обоих случаях выполнение продолжается. Чтобы передать информацию в контекст Claude, верните `additionalContext` в JSON выходе; простой stdout записывается только в журнал отладки. В дополнение к [JSON полям выхода](#json-output), доступным для всех hooks, вы можете вернуть эти поля, специфичные для события:1115Setup hooks не могут блокировать. При exit code 2 stderr показывается пользователю как уведомление об ошибке hook, и выполнение продолжается. В [неинтерактивном режиме](/ru/headless) выход hook появляется только при запуске с `--verbose`. Чтобы передать информацию в контекст Claude, верните `additionalContext` в JSON выходе; простой stdout записывается только в журнал отладки. В дополнение к [JSON полям выхода](#json-output), доступным для всех hooks, вы можете вернуть эти поля, специфичные для события:
1099 1116
1100| Поле | Описание |1117| Поле | Описание |
1101| :------------------ | :---------------------------------------------------------------------------- |1118| :------------------ | :---------------------------------------------------------------------------- |
1191* **Простой текст stdout**: любой текст, не являющийся JSON, написанный на stdout, добавляется как контекст1208* **Простой текст stdout**: любой текст, не являющийся JSON, написанный на stdout, добавляется как контекст
1192* **JSON с `additionalContext`**: используйте формат JSON ниже для большего управления. Поле `additionalContext` добавляется как контекст1209* **JSON с `additionalContext`**: используйте формат JSON ниже для большего управления. Поле `additionalContext` добавляется как контекст
1193 1210
1194Простой stdout показывается как выход hook в транскрипте. Поле `additionalContext` добавляется более дискретно.1211Простой stdout показывается как выход hook в транскрипте. Значение `additionalContext` внедряется как системное напоминание, которое Claude читает без видимой записи в транскрипте.
1195 1212
1196Чтобы заблокировать подсказку, верните JSON объект с `decision`, установленным на `"block"`:1213Чтобы заблокировать подсказку, верните JSON объект с `decision`, установленным на `"block"`:
1197 1214
1215}1232}
1216```1233```
1217 1234
1218<Note>
1219 Формат JSON не требуется для простых случаев использования. Чтобы добавить контекст, вы можете вывести простой текст на stdout с exit code 0. Используйте JSON, когда вам нужно блокировать подсказки или вам нужно более структурированное управление.
1220</Note>
1221
1222<h3 id="userpromptexpansion">1235<h3 id="userpromptexpansion">
1223 UserPromptExpansion1236 UserPromptExpansion
1224</h3>1237</h3>
1545В `PostToolUse`, `tool_response` для завершённого вызова Agent содержит финальный текст subagent вместе с телеметрией использования. Читайте эти поля для записи затрат для каждого subagent из hook:1558В `PostToolUse`, `tool_response` для завершённого вызова Agent содержит финальный текст subagent вместе с телеметрией использования. Читайте эти поля для записи затрат для каждого subagent из hook:
1546 1559
1547| Поле | Тип | Пример | Описание |1560| Поле | Тип | Пример | Описание |
1548| :------------------ | :----- | :---------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------- |1561| :------------------ | :----- | :---------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1549| `status` | string | `"completed"` | `"completed"` для синхронных вызовов, `"async_launched"` для `run_in_background: true` |1562| `status` | string | `"completed"` | `"completed"` для синхронных вызовов, `"async_launched"` для фоновых subagents. {/* min-version: 2.1.198 */}Начиная с v2.1.198, subagents запускаются в фоне по умолчанию, поэтому опущенный `run_in_background` также производит `"async_launched"` |
1550| `agentId` | string | `"a4d2c8f1e0b3a297"` | Идентификатор для запуска subagent |1563| `agentId` | string | `"a4d2c8f1e0b3a297"` | Идентификатор для запуска subagent |
1551| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | Финальные текстовые блоки subagent |1564| `content` | array | `[{"type": "text", "text": "Found 12 endpoints..."}]` | Финальные текстовые блоки subagent |
1552| `resolvedModel` | string | `"claude-sonnet-4-5"` | Модель, на которой запустился subagent, которая может отличаться от запрошенной модели. {/* min-version: 2.1.174 */}Требует Claude Code v2.1.174 или позже |1565| `resolvedModel` | string | `"claude-sonnet-4-5"` | Модель, на которой запустился subagent, которая может отличаться от запрошенной модели. {/* min-version: 2.1.174 */}Требует Claude Code v2.1.174 или позже |
1555| `totalToolUseCount` | number | `7` | Количество вызовов инструментов, которые сделал subagent |1568| `totalToolUseCount` | number | `7` | Количество вызовов инструментов, которые сделал subagent |
1556| `usage` | object | `{"input_tokens": 8320, ...}` | Разбор токенов по типам: `input_tokens`, `output_tokens`, `cache_creation_input_tokens`, `cache_read_input_tokens` |1569| `usage` | object | `{"input_tokens": 8320, ...}` | Разбор токенов по типам: `input_tokens`, `output_tokens`, `cache_creation_input_tokens`, `cache_read_input_tokens` |
1557 1570
1558Для вызовов `run_in_background: true`, инструмент возвращается сразу после запуска subagent, поэтому `tool_response` не содержит полей использования. Он имеет `status: "async_launched"`, `agentId`, `description`, `prompt`, `outputFile` и `resolvedModel` вместо этого.1571Для фоновых subagents инструмент возвращается сразу после запуска, поэтому `tool_response` не содержит полей использования. Он имеет `status: "async_launched"`, `agentId`, `description`, `prompt`, `outputFile` и `resolvedModel` вместо этого.
1559 1572
1560Поле `resolvedModel` называет модель, на которой subagent фактически запустился, что может отличаться от значения `model` в `tool_input`. Оно требует Claude Code v2.1.174 или позже.1573Поле `resolvedModel` называет модель, на которой subagent фактически запустился, что может отличаться от значения `model` в `tool_input`. Оно требует Claude Code v2.1.174 или позже.
1561 1574
1593Hooks `PreToolUse` могут управлять тем, продолжается ли вызов инструмента. В отличие от других hooks, которые используют верхнеуровневое поле `decision`, PreToolUse возвращает своё решение внутри объекта `hookSpecificOutput`. Это даёт ему более богатое управление: четыре результата (разрешить, отклонить, спросить или отложить) плюс возможность изменить входные данные инструмента перед выполнением.1606Hooks `PreToolUse` могут управлять тем, продолжается ли вызов инструмента. В отличие от других hooks, которые используют верхнеуровневое поле `decision`, PreToolUse возвращает своё решение внутри объекта `hookSpecificOutput`. Это даёт ему более богатое управление: четыре результата (разрешить, отклонить, спросить или отложить) плюс возможность изменить входные данные инструмента перед выполнением.
1594 1607
1595| Поле | Описание |1608| Поле | Описание |
1596| :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |1609| :------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1597| `permissionDecision` | `"allow"` пропускает диалог разрешения. `"deny"` предотвращает вызов инструмента. `"ask"` предлагает пользователю подтвердить. `"defer"` выходит корректно, чтобы инструмент мог быть возобновлён позже. [Правила отклонения и запроса](/ru/permissions#manage-permissions) всё ещё применяются независимо от того, что возвращает hook |1610| `permissionDecision` | `"allow"` пропускает диалог разрешения, кроме [инструментов, требующих взаимодействия пользователя](#pretooluse-decision-control). `"deny"` предотвращает вызов инструмента. `"ask"` предлагает пользователю подтвердить. `"defer"` выходит корректно, чтобы инструмент мог быть возобновлён позже. [Правила отклонения и запроса](/ru/permissions#manage-permissions) всё ещё применяются независимо от того, что возвращает hook |
1598| `permissionDecisionReason` | Для `"allow"` и `"ask"`, показывается пользователю, но не Claude. Для `"deny"`, показывается Claude. Для `"defer"`, игнорируется |1611| `permissionDecisionReason` | Для `"allow"` и `"ask"`, показывается пользователю, но не Claude. Для `"deny"`, показывается Claude. Для `"defer"`, игнорируется |
1599| `updatedInput` | Изменяет параметры входа инструмента перед выполнением. Заменяет весь объект входа, поэтому включите неизменённые поля наряду с изменёнными. Объедините с `"allow"` для автоматического одобрения или `"ask"` для показа изменённого входа пользователю. Для `"defer"`, игнорируется |1612| `updatedInput` | Изменяет параметры входа инструмента перед выполнением. Заменяет весь объект входа, поэтому включите неизменённые поля наряду с изменёнными. Объедините с `"allow"` для автоматического одобрения или `"ask"` для показа изменённого входа пользователю. Для `"defer"`, игнорируется |
1600| `additionalContext` | Строка, добавленная в контекст Claude наряду с результатом инструмента. Игнорируется при `permissionDecision` равном `"defer"`. См. [Add context for Claude](#add-context-for-claude) |1613| `additionalContext` | Строка, добавленная в контекст Claude наряду с результатом инструмента. Игнорируется при `permissionDecision` равном `"defer"`. См. [Add context for Claude](#add-context-for-claude) |
1619 1632
1620`AskUserQuestion` и `ExitPlanMode` требуют взаимодействия пользователя и обычно блокируют в [неинтерактивном режиме](/ru/headless) с флагом `-p`. Возврат `permissionDecision: "allow"` вместе с `updatedInput` удовлетворяет этому требованию: hook читает входные данные инструмента из stdin, собирает ответ через ваш собственный UI и возвращает его в `updatedInput`, чтобы инструмент запустился без запроса. Возврат только `"allow"` недостаточен для этих инструментов. Для `AskUserQuestion` повторите исходный массив `questions` и добавьте объект [`answers`](#askuserquestion), соответствующий тексту каждого вопроса выбранному ответу.1633`AskUserQuestion` и `ExitPlanMode` требуют взаимодействия пользователя и обычно блокируют в [неинтерактивном режиме](/ru/headless) с флагом `-p`. Возврат `permissionDecision: "allow"` вместе с `updatedInput` удовлетворяет этому требованию: hook читает входные данные инструмента из stdin, собирает ответ через ваш собственный UI и возвращает его в `updatedInput`, чтобы инструмент запустился без запроса. Возврат только `"allow"` недостаточен для этих инструментов. Для `AskUserQuestion` повторите исходный массив `questions` и добавьте объект [`answers`](#askuserquestion), соответствующий тексту каждого вопроса выбранному ответу.
1621 1634
1635Начиная с v2.1.199, инструмент MCP, чей сервер помечает его с помощью [`_meta["anthropic/requiresUserInteraction"]`](/ru/mcp#require-approval-for-a-specific-tool), более строг: hook не может пропустить его диалог одобрения с помощью `"allow"`, с `updatedInput` или без, потому что Claude Code не может подтвердить, что hook собрал взаимодействие, которое нужно инструменту.
1636
1622<Note>1637<Note>
1623 PreToolUse ранее использовал верхнеуровневые поля `decision` и `reason`, но они устарели для этого события. Используйте `hookSpecificOutput.permissionDecision` и `hookSpecificOutput.permissionDecisionReason` вместо этого. Устаревшие значения `"approve"` и `"block"` соответствуют `"allow"` и `"deny"` соответственно. Другие события, такие как PostToolUse и Stop, продолжают использовать верхнеуровневые `decision` и `reason` как их текущий формат.1638 PreToolUse ранее использовал верхнеуровневые поля `decision` и `reason`, но они устарели для этого события. Используйте `hookSpecificOutput.permissionDecision` и `hookSpecificOutput.permissionDecisionReason` вместо этого. Устаревшие значения `"approve"` и `"block"` соответствуют `"allow"` и `"deny"` соответственно. Другие события, такие как PostToolUse и Stop, продолжают использовать верхнеуровневые `decision` и `reason` как их текущий формат.
1624</Note>1639</Note>
2016 Notification2031 Notification
2017</h3>2032</h3>
2018 2033
2019Запускается при отправке Claude Code уведомлений. Совпадает с типом уведомления: `permission_prompt`, `idle_prompt`, `auth_success`, `elicitation_dialog`, `elicitation_complete`, `elicitation_response`. Опустите фильтр для запуска hooks для всех типов уведомлений.2034Запускается при отправке Claude Code уведомлений. Совпадает с типом уведомления. Опустите фильтр для запуска hooks для всех типов уведомлений.
2035
2036| Фильтр | Когда он срабатывает |
2037| :--------------------- | :------------------------------------------------------------------------------------------------------------------ |
2038| `permission_prompt` | Claude нуждается в одобрении использования инструмента |
2039| `idle_prompt` | Claude завершил работу и ждёт вашей следующей подсказки |
2040| `auth_success` | Аутентификация завершена |
2041| `elicitation_dialog` | MCP сервер открывает форму запроса |
2042| `elicitation_complete` | Форма запроса MCP отправлена или отклонена |
2043| `elicitation_response` | Ответ на запрос MCP отправлен обратно на сервер |
2044| `agent_needs_input` | Фоновый сеанс начинает ждать вашего ввода. Срабатывает только при открытом [agent view](/ru/agent-view) в терминале |
2045| `agent_completed` | Фоновый сеанс завершается или не удаётся. Срабатывает только при открытом [agent view](/ru/agent-view) в терминале |
2046
2047Типы `agent_needs_input` и `agent_completed` требуют Claude Code v2.1.198 или позже.
2020 2048
2021Используйте отдельные фильтры для запуска разных обработчиков в зависимости от типа уведомления. Эта конфигурация запускает скрипт оповещения, специфичный для разрешения, когда Claude нуждается в одобрении разрешения, и другое уведомление, когда Claude был неактивен:2049Используйте отдельные фильтры для запуска разных обработчиков в зависимости от типа уведомления. Эта конфигурация запускает скрипт оповещения, специфичный для разрешения, когда Claude нуждается в одобрении разрешения, и другое уведомление, когда Claude был неактивен:
2022 2050
2079 SubagentStart input2107 SubagentStart input
2080</h4>2108</h4>
2081 2109
2082В дополнение к [общим полям входа](#common-input-fields), SubagentStart hooks получают `agent_id` с уникальным идентификатором для subagent и `agent_type` с именем агента (встроенные агенты, такие как `"general-purpose"`, `"Explore"`, `"Plan"` или пользовательские имена агентов).2110В дополнение к [общим полям входа](#common-input-fields), SubagentStart hooks получают `agent_id` с уникальным идентификатором для subagent и `agent_type` с именем агента, которое фильтр использует для фильтрации.
2083 2111
2084```json theme={null}2112```json theme={null}
2085{2113{
2561В дополнение к [JSON полям выхода](#json-output), доступным для всех hooks, CwdChanged hooks могут вернуть `watchPaths` для динамической установки, какие пути файлов [FileChanged](#filechanged) отслеживает:2589В дополнение к [JSON полям выхода](#json-output), доступным для всех hooks, CwdChanged hooks могут вернуть `watchPaths` для динамической установки, какие пути файлов [FileChanged](#filechanged) отслеживает:
2562 2590
2563| Поле | Описание |2591| Поле | Описание |
2564| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2592| :----------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
2565| `watchPaths` | Массив абсолютных путей. Заменяет текущий динамический список наблюдения (пути из конфигурации `matcher` всегда отслеживаются). Возврат пустого массива очищает динамический список, что типично при входе в новый каталог |2593| `watchPaths` | Массив абсолютных путей. Заменяет текущий динамический список наблюдения. Пути из конфигурации `matcher` всегда отслеживаются. Возврат пустого массива очищает динамический список, что типично при входе в новый каталог |
2566 2594
2567CwdChanged hooks не имеют управления решением. Они не могут блокировать изменение каталога.2595CwdChanged hooks не имеют управления решением. Они не могут блокировать изменение каталога.
2568 2596
2586В дополнение к [общим полям входа](#common-input-fields), FileChanged hooks получают `file_path` и `event`.2614В дополнение к [общим полям входа](#common-input-fields), FileChanged hooks получают `file_path` и `event`.
2587 2615
2588| Поле | Описание |2616| Поле | Описание |
2589| :---------- | :------------------------------------------------------------------------------------------- |2617| :---------- | :---------------------------------------------------------------------------------------------------------------- |
2590| `file_path` | Абсолютный путь к файлу, который изменился |2618| `file_path` | Абсолютный путь к файлу, который изменился |
2591| `event` | Что произошло: `"change"` (файл изменён), `"add"` (файл создан) или `"unlink"` (файл удалён) |2619| `event` | Что произошло: `"change"` для изменённого файла, `"add"` для созданного файла или `"unlink"` для удалённого файла |
2592 2620
2593```json theme={null}2621```json theme={null}
2594{2622{
2608В дополнение к [JSON полям выхода](#json-output), доступным для всех hooks, FileChanged hooks могут вернуть `watchPaths` для динамического обновления, какие пути файлов отслеживаются:2636В дополнение к [JSON полям выхода](#json-output), доступным для всех hooks, FileChanged hooks могут вернуть `watchPaths` для динамического обновления, какие пути файлов отслеживаются:
2609 2637
2610| Поле | Описание |2638| Поле | Описание |
2611| :----------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |2639| :----------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2612| `watchPaths` | Массив абсолютных путей. Заменяет текущий динамический список наблюдения (пути из конфигурации `matcher` всегда отслеживаются). Используйте это, когда ваш скрипт hook обнаруживает дополнительные файлы для отслеживания на основе изменённого файла |2640| `watchPaths` | Массив абсолютных путей. Заменяет текущий динамический список наблюдения. Пути из конфигурации `matcher` всегда отслеживаются. Используйте это, когда ваш скрипт hook обнаруживает дополнительные файлы для отслеживания на основе изменённого файла |
2613 2641
2614FileChanged hooks не имеют управления решением. Они не могут блокировать изменение файла от возникновения.2642FileChanged hooks не имеют управления решением. Они не могут блокировать изменение файла от возникновения.
2615 2643
2617 WorktreeCreate2645 WorktreeCreate
2618</h3>2646</h3>
2619 2647
2620Когда вы запускаете `claude --worktree` или [subagent использует `isolation: "worktree"`](/ru/sub-agents#choose-the-subagent-scope), Claude Code создаёт изолированную рабочую копию, используя `git worktree`. Если вы настроите hook WorktreeCreate, он заменяет поведение git по умолчанию, позволяя вам использовать другую систему контроля версий, такую как SVN, Perforce или Mercurial.2648Запускается при создании worktree, либо из `claude --worktree`, либо из [subagent, использующего `isolation: "worktree"`](/ru/sub-agents#choose-the-subagent-scope). По умолчанию Claude Code создаёт изолированную рабочую копию с помощью `git worktree`. Настройка hook WorktreeCreate заменяет это поведение git по умолчанию, позволяя вам использовать другую систему контроля версий, такую как SVN, Perforce или Mercurial.
2621 2649
2622Потому что hook заменяет поведение по умолчанию полностью, [`.worktreeinclude`](/ru/worktrees#copy-gitignored-files-into-worktrees) не обрабатывается. Если вам нужно скопировать локальные файлы конфигурации, такие как `.env`, в новый worktree, сделайте это внутри вашего скрипта hook.2650Потому что hook заменяет поведение по умолчанию полностью, [`.worktreeinclude`](/ru/worktrees#copy-gitignored-files-into-worktrees) не обрабатывается. Если вам нужно скопировать локальные файлы конфигурации, такие как `.env`, в новый worktree, сделайте это внутри вашего скрипта hook.
2623 2651
2648 WorktreeCreate input2676 WorktreeCreate input
2649</h4>2677</h4>
2650 2678
2651В дополнение к [общим полям входа](#common-input-fields), WorktreeCreate hooks получают поле `name`. Это идентификатор slug для нового worktree, либо указанный пользователем, либо автоматически сгенерированный (например, `bold-oak-a3f2`).2679В дополнение к [общим полям входа](#common-input-fields), WorktreeCreate hooks получают поле `name`. Это идентификатор slug для нового worktree, либо указанный пользователем, либо автоматически сгенерированный, например `bold-oak-a3f2`.
2652 2680
2653```json theme={null}2681```json theme={null}
2654{2682{
2675 WorktreeRemove2703 WorktreeRemove
2676</h3>2704</h3>
2677 2705
2678Аналог очистки для [WorktreeCreate](#worktreecreate). Этот hook срабатывает при удалении worktree, либо при выходе из сеанса `--worktree` и выборе его удаления, либо при завершении subagent с `isolation: "worktree"`. Для git-based worktrees Claude обрабатывает очистку автоматически с `git worktree remove`. Если вы настроили hook WorktreeCreate для системы контроля версий, не основанной на git, объедините его с hook WorktreeRemove для обработки очистки. Без него каталог worktree остаётся на диске.2706Запускается при удалении worktree, либо при выходе из сеанса `--worktree` и выборе его удаления, либо при завершении subagent с `isolation: "worktree"`. Это аналог очистки для [WorktreeCreate](#worktreecreate).
2707
2708Для git-based worktrees Claude Code обрабатывает очистку автоматически с помощью `git worktree remove`. Если вы настроили hook WorktreeCreate для системы контроля версий, не основанной на git, объедините его с hook WorktreeRemove для обработки очистки. Без него каталог worktree остаётся на диске.
2679 2709
2680Claude Code передаёт путь, который WorktreeCreate вывел на stdout, как `worktree_path` во входных данных hook. Этот пример читает этот путь и удаляет каталог:2710Claude Code передаёт путь, который WorktreeCreate вывел на stdout, как `worktree_path` во входных данных hook. Этот пример читает этот путь и удаляет каталог:
2681 2711
2801 SessionEnd input2831 SessionEnd input
2802</h4>2832</h4>
2803 2833
2804В дополнение к [общим полям входа](#common-input-fields), SessionEnd hooks получают поле `reason`, указывающее, почему сеанс закончился. См. таблиц выше для всех значений.2834В дополнение к [общим полям входа](#common-input-fields), SessionEnd hooks получают поле `reason`, указывающее, почему сеанс закончился. См. таблицу выше для всех значений.
2805 2835
2806```json theme={null}2836```json theme={null}
2807{2837{
2815 2845
2816SessionEnd hooks не имеют управления решением. Они не могут блокировать завершение сеанса, но могут выполнять задачи очистки.2846SessionEnd hooks не имеют управления решением. Они не могут блокировать завершение сеанса, но могут выполнять задачи очистки.
2817 2847
2818SessionEnd hooks имеют таймаут по умолчанию 1,5 секунды. Это применяется как к выходу из сеанса, так и к `/clear` и переключению сеансов через интерактивный `/resume`. Если hook нуждается в большем времени, установите поле `timeout` в per-hook конфигурации hook. Общий бюджет автоматически повышается до наибольшего per-hook таймаута, настроенного в файлах настроек, до 60 секунд. Таймауты, установленные на hooks, предоставленные плагинами, не повышают бюджет. Чтобы явно переопределить бюджет, установите переменную окружения `CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` в миллисекундах.2848SessionEnd hooks имеют таймаут по умолчанию 1,5 секунды. Это применяется как к выходу из сеанса, так и к `/clear` и переключению сеансов через интерактивный `/resume`. Если hook нуждается в большем времени, установите поле `timeout` в конфигурации hook. Общий бюджет автоматически повышается до наибольшего per-hook таймаута, настроенного в файлах настроек, до 60 секунд. Таймауты, установленные на hooks, предоставленные плагинами, не повышают бюджет. Чтобы явно переопределить бюджет, установите переменную окружения `CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` в миллисекундах.
2819 2849
2820```bash theme={null}2850```bash theme={null}
2821CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude2851CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude
3060* `PostToolUseFailure`, `TaskCreated` и `TaskCompleted`: причина возвращается Claude как ошибка инструмента, аналогично `PreToolUse`3090* `PostToolUseFailure`, `TaskCreated` и `TaskCompleted`: причина возвращается Claude как ошибка инструмента, аналогично `PreToolUse`
3061* `TeammateIdle`: по умолчанию товарищ по команде останавливается и причина появляется как строка предупреждения. Установите `continueOnBlock: true` для передачи причины обратно товарищу по команде и продолжения его работы вместо этого3091* `TeammateIdle`: по умолчанию товарищ по команде останавливается и причина появляется как строка предупреждения. Установите `continueOnBlock: true` для передачи причины обратно товарищу по команде и продолжения его работы вместо этого
3062* `PermissionRequest`: `ok: false` не имеет эффекта. Чтобы отклонить одобрение из hook, используйте [command hook](#command-hook-fields), возвращающий `hookSpecificOutput.decision.behavior: "deny"`3092* `PermissionRequest`: `ok: false` не имеет эффекта. Чтобы отклонить одобрение из hook, используйте [command hook](#command-hook-fields), возвращающий `hookSpecificOutput.decision.behavior: "deny"`
3063* `PermissionDenied`: `ok: false` не имеет эффекта, потому что отказ уже произошёл. Единственный результат, который это событие читает, это `hookSpecificOutput.retry`, который prompt и agent hooks не могут установить — они запускаются на этом событии, но их результат отбрасывается. Используйте [command hook](#command-hook-fields) для возврата `retry`3093* `PermissionDenied`: `ok: false` не имеет эффекта, потому что отказ уже произошёл. Единственный результат, который это событие читает, это `hookSpecificOutput.retry`, который prompt и agent hooks не могут установить. Они запускаются на этом событии, но их результат отбрасывается. Используйте [command hook](#command-hook-fields) для возврата `retry`
3064 3094
3065Если вам нужен более точный контроль над любым событием, используйте [command hook](#command-hook-fields) с полями для каждого события, описанными в [Decision control](#decision-control).3095Если вам нужен более точный контроль над любым событием, используйте [command hook](#command-hook-fields) с полями для каждого события, описанными в [Decision control](#decision-control).
3066 3096
3067<h3 id="example-multi-criteria-stop-hook">3097<h3 id="check-multiple-conditions-before-stopping">
3068 Example: Multi-criteria Stop hook3098 Check multiple conditions before stopping
3069</h3>3099</h3>
3070 3100
3071Этот hook `Stop` использует подробную подсказку для проверки трёх условий перед разрешением Claude остановиться. Если `"ok"` равно `false`, Claude продолжает работать с предоставленной причиной как своей следующей инструкцией. Hooks `SubagentStop` используют тот же формат для оценки, должен ли [subagent](/ru/sub-agents) остановиться:3101Этот hook `Stop` использует подробную подсказку для проверки трёх условий перед разрешением Claude остановиться. Hooks `SubagentStop` используют тот же формат для оценки, должен ли [subagent](/ru/sub-agents) остановиться. Если `"ok"` равно `false`, Claude продолжает работать с предоставленной причиной как своей следующей инструкцией:
3072 3102
3073```json theme={null}3103```json theme={null}
3074{3104{
3192 3222
3193Уведомления о завершении асинхронного hook подавляются по умолчанию. Чтобы их увидеть, включите подробный режим с помощью `Ctrl+O` или запустите Claude Code с `--verbose`.3223Уведомления о завершении асинхронного hook подавляются по умолчанию. Чтобы их увидеть, включите подробный режим с помощью `Ctrl+O` или запустите Claude Code с `--verbose`.
3194 3224
3195<h3 id="example-run-tests-after-file-changes">3225<h3 id="run-tests-after-file-changes">
3196 Пример: запуск тестов после изменения файлов3226 Запуск тестов после изменения файлов
3197</h3>3227</h3>
3198 3228
3199Этот hook запускает набор тестов в фоне всякий раз, когда Claude пишет файл, затем сообщает результаты обратно Claude при завершении тестов. Сохраните этот скрипт в `.claude/hooks/run-tests-async.sh` в вашем проекте и сделайте его исполняемым с помощью `chmod +x`:3229Этот hook запускает набор тестов в фоне всякий раз, когда Claude пишет файл, затем сообщает результаты обратно Claude при завершении тестов. Сохраните этот скрипт в `.claude/hooks/run-tests-async.sh` в вашем проекте и сделайте его исполняемым с помощью `chmod +x`:
3287 Windows PowerShell tool3317 Windows PowerShell tool
3288</h2>3318</h2>
3289 3319
3290На Windows вы можете запустить отдельные hooks в PowerShell, установив `"shell": "powershell"` на command hook. Hooks порождают PowerShell напрямую, поэтому это работает независимо от того, установлен ли `CLAUDE_CODE_USE_POWERSHELL_TOOL`. Claude Code автоматически обнаруживает `pwsh.exe` (PowerShell 7+) с резервным вариантом на `powershell.exe` (5.1).3320На Windows вы можете запустить отдельные hooks в PowerShell, установив `"shell": "powershell"` на command hook. Hooks порождают PowerShell напрямую, поэтому это работает независимо от того, установлен ли `CLAUDE_CODE_USE_POWERSHELL_TOOL`. Claude Code автоматически обнаруживает `pwsh.exe`, исполняемый файл PowerShell 7 и более поздних версий, и переходит на `powershell.exe` для Windows PowerShell 5.1.
3291 3321
3292```json theme={null}3322```json theme={null}
3293{3323{
3308}3338}
3309```3339```
3310 3340
3311Чтобы ссылаться на корневой каталог проекта из команды PowerShell в форме shell, прочитайте его как переменную окружения с помощью `$env:CLAUDE_PROJECT_DIR`. PowerShell рассматривает простую форму `${CLAUDE_PROJECT_DIR}` как локальную переменную, а не как поиск в окружении, и Claude Code подставляет этот заполнитель в форме shell только для [plugin hooks](#reference-scripts-by-path). Для hook, определённого в `settings.json`, либо используйте форму `$env:`, либо переключитесь на [exec form](#exec-form-and-shell-form), где `${CLAUDE_PROJECT_DIR}` подставляется в каждый элемент `args` независимо от того, где определён hook.3341Чтобы ссылаться на корневой каталог проекта из команды PowerShell в форме shell, напишите `${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 никогда не расширяет переменные.
3342
3343До версии 2.1.198 эта переписка применялась только к plugin hooks. В более ранних версиях hook в `settings.json` требует формы `$env:` или [exec form](#exec-form-and-shell-form), где `${CLAUDE_PROJECT_DIR}` подставляется в каждый элемент `args` независимо от того, где определён hook.
3344
3345Не пишите простое написание `$CLAUDE_PROJECT_DIR` в hook PowerShell. PowerShell анализирует его как неопределённую локальную переменную и разрешает её в `$null`, что оставляет путь скрипта без префикса корневого каталога проекта. Claude Code не переписывает эту форму; вместо этого она регистрирует предупреждение в [debug log](#debug-hooks).
3312 3346
3313Пример ниже показывает hook в `settings.json`, который запускает скрипт проекта с формой `$env:`:3347Пример ниже показывает hook в `settings.json`, который запускает скрипт проекта с формой `$env:`, которая работает на каждой версии:
3314 3348
3315```json theme={null}3349```json theme={null}
3316{3350{