# Хуки Claude Code: правило, которое нельзя забыть

Канонический URL: https://zero2claude.ru/blog/claude-code-hooks-pretooluse
Дата: 2026-10-15
Теги: claude-code, автоматизация, безопасность

Строчка в CLAUDE.md — совет, хук — закон. Разбираем хук PreToolUse, который блокирует правку защищённого файла кодом выхода 2, три полезных рецепта на PostToolUse, Notification и Stop, и границу, о которой забывают даже опытные.

Ты пишешь в [CLAUDE.md](/glossary/claude-md): «никогда не трогай package-lock.json». Claude слушается. Почти всегда. Но длинная сессия, сжатый контекст, срочная правка зависимостей — и однажды файл всё-таки меняется. Модель не нарушила правило назло: строчка в памяти для неё контекст, а не приказ.

Если правило должно выполняться **всегда**, ему место не в памяти, а в хуке. Вот как это устроено и как сделать первый хук, который не подведёт.

<Cover src="/blog/claude-code-hooks-pretooluse.jpg" alt="Робот с кистью остановился перед закрытыми воротами, за которыми стоит банка на пьедестале" />

## Хук — это твоя команда, а не просьба к модели

[Хук](/glossary/hooks) — это команда, которую Claude Code сам запускает в заданный момент сессии, что бы ни решил Claude. Модель не может его «забыть» или «не заметить»: он стоит на пути у самого инструмента.

Каждый хук привязан к событию. Главные события такие:

| Событие | Когда срабатывает |
|---|---|
| `SessionStart` | при старте сессии |
| `UserPromptSubmit` | когда ты отправил запрос |
| `PreToolUse` | перед каждым вызовом инструмента |
| `PostToolUse` | после успешного вызова инструмента |
| `Stop` | когда Claude закончил отвечать |
| `Notification` | когда Claude Code нужно твоё внимание |

Из них только `PreToolUse` умеет **остановить** действие до того, как оно случилось. С него и начнём.

## Охранник на PreToolUse

Перед вызовом инструмента Claude Code запускает твой скрипт и подаёт ему на вход JSON с описанием события — например, какой файл собираются править. Дальше всё решает код выхода:

- **0** — всё в порядке, действие идёт дальше;
- **2** — вызов заблокирован, а то, что скрипт напечатал в stderr, уходит Claude как причина.

Claude видит объяснение и меняет план, вместо того чтобы молча упереться в ошибку. Важная деталь: `PreToolUse` срабатывает **до** проверки режима разрешений. Поэтому блок держится в любом режиме, даже в Auto.

Простой охранник может выглядеть так — сохрани его в `.claude/hooks/protect-files.sh` и сделай исполняемым (`chmod +x`):

```bash
#!/bin/bash
file=$(jq -r '.tool_input.file_path // empty')
case "$file" in
  */package-lock.json|*/.env)
    echo "Blocked: $file защищён, не правь его" >&2
    exit 2 ;;
esac
exit 0
```

И зарегистрируй в `.claude/settings.json`:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          { "type": "command", "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/protect-files.sh", "args": [] }
        ]
      }
    ]
  }
}
```

Что здесь происходит:

- `matcher` выбирает инструменты: `Edit|Write` — только правки и запись файлов;
- `${CLAUDE_PROJECT_DIR}` подставляет путь к проекту, чтобы хук находился, откуда бы ты ни запустил Claude;
- с `"args": []` скрипт запускается напрямую, без оболочки, и путь не нужно брать в кавычки.

Внутри сессии команда `/hooks` покажет, какие хуки подхватились.

## Проверь хук без Claude

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

```bash
echo "{\"tool_input\":{\"file_path\":\"$PWD/package-lock.json\"}}" | .claude/hooks/protect-files.sh; echo "exit $?"
```

Видишь `exit 2` — значит, хук сработает и в сессии. Видишь `exit 0` на защищённом файле — ищи ошибку в скрипте до того, как она молча сломает тебе каждую сессию.

## Три рецепта, которые окупаются сразу

Блокировать — не единственное, что умеют хуки.

**Прибраться после правки — PostToolUse.** Повесь его на `Edit|Write`, и после каждой правки файла запустится форматтер или линтер. Целый класс просьб «а теперь поправь отступы» исчезает.

**Позвать тебя — Notification.** Ты ушёл за чаем, а Claude давно ждёт подтверждения. Хук на `Notification` покажет системное уведомление или проиграет звук. Такой хук — про тебя, а не про проект: на Mac и Linux уведомления делаются по-разному. Поэтому регистрируй его в своём `~/.claude/settings.json`, а не в настройках репозитория.

**Проверить в конце — Stop.** `Stop` срабатывает, когда Claude закончил отвечать. Это лучшее место, чтобы одним махом проверить всё рабочее дерево: не изменились ли защищённые файлы, проходят ли быстрые тесты.

<Callout type="tip" title="Быстрое — в PostToolUse, тяжёлое — в Stop">
Хук выполняется на каждом событии. Полный прогон тестов в PostToolUse замедлит каждую правку. Туда клади быстрое: форматирование, проверку одного файла. Тяжёлые проверки ставь на Stop — один раз на ответ.
</Callout>

## Граница, о которой забывают

Охранник с `matcher: "Edit|Write"` видит **только инструменты редактирования**. Если Claude изменит файл командой оболочки — `echo X >> .env`, `sed -i`, `rm`, — хук ничего не заметит: команды идут через инструмент `Bash`.

Закрыть эту дыру можно двумя способами:

- отдельный хук с `matcher: "Bash"`, который разбирает команду;
- хук на `Stop`, который в конце ответа проверяет рабочее дерево. Ему всё равно, *как* сделано изменение, — он смотрит на результат.

Для действительно важных файлов разумно иметь оба: охранник на `PreToolUse` останавливает очевидную правку сразу, а проверка на `Stop` ловит всё остальное.

<Callout type="warning" title="Хуки — это код с твоими правами">
Хуки выполняются с правами твоего пользователя: в интерактивной сессии — после того как ты доверил папку, а в claude -p — без всякого вопроса. Прежде чем доверять чужому репозиторию или запускать в нём Claude из скрипта, открой его .claude/settings.json и посмотри, какие хуки там прописаны.
</Callout>

## Частые вопросы

<Faq>
<FaqItem q="Чем хук отличается от правила в CLAUDE.md?">

CLAUDE.md — это контекст, который модель учитывает, но может упустить. Хук — команда, которую Claude Code запускает сам на заданном событии, всегда. Всё, что должно выполняться без исключений, оформляй хуком.

</FaqItem>
<FaqItem q="Как хук PreToolUse блокирует действие?">

Скрипт хука завершается с кодом выхода 2. Вызов инструмента отменяется, а текст из stderr уходит Claude как причина. Код 0 пропускает действие дальше.

</FaqItem>
<FaqItem q="Работает ли блокировка в режиме Auto?">

Да. PreToolUse срабатывает до проверки режима разрешений, поэтому блок держится в любом режиме.

</FaqItem>
<FaqItem q="Почему хук на Edit|Write не заметил изменение .env?">

Скорее всего, файл поменяли командой оболочки, например `echo X >> .env`. Такие команды идут через инструмент Bash. Для них нужен отдельный хук с matcher Bash или хук на Stop, который проверяет рабочее дерево.

</FaqItem>
</Faq>

## Где потренироваться

Второй уровень курса «Claude Code: уровень профи» начинается именно с этого: урок [«Хуки: правило, которое нельзя забыть»](/learn/claude-code-pro/2-1-huki-pretooluse) и урок [«Рецепты хуков»](/learn/claude-code-pro/2-2-recepty-hukov), оба с тренажёром в браузере. Если хочешь начать с самых основ, загляни в наш ранний разбор [«Hooks в Claude Code»](/blog/claude-hooks), а все события и флаги в одном месте собраны в [шпаргалке по Claude Code](/claude-code-shpargalka).
