Что такое хук Claude Code и как защитить файл с его помощью?
Если цель - сделать хук для конкретной опасной правки, не начинай с большого набора автоматизаций. Нужна одна проверка:
- Claude собирается вызвать
EditилиWrite. - Claude Code запускает
PreToolUse. - Локальный скрипт читает путь файла.
- Скрипт сравнивает его с защищённым шаблоном.
- При совпадении скрипт возвращает
exit 2. - Вызов инструмента останавливается.
Anthropic описывает хуки как способ получить детерминированный контроль: команда запускается в фиксированной точке жизненного цикла. Это отличается от строки в CLAUDE.md или от сообщения в чате. Такая строка остаётся частью контекста модели. Модель может не выбрать нужное действие, неправильно понять исключение или перестать внимательно читать длинные инструкции.
По документации Anthropic, command hooks являются пользовательскими командами оболочки: Claude Code запускает их в определённых местах работы, поэтому ими можно задавать повторяемую проверку. Для правила с точным путём я использую именно такой детерминированный hook.
- Anthropic, Automate actions with hooks
Обычное правило подходит для предпочтений: форматировать код, использовать определённый стиль, запускать проверку после правки. Жёсткий запрет лучше вынести из текста. Например, если файл нельзя менять без отдельного решения, проверка пути должна находиться в скрипте.
Хук не делает Claude Code умнее. Он ставит маленькую заслонку перед конкретным действием. Если заслонка настроена на неправильное событие или возвращает неправильный код, защиты нет.
Почему Claude Code может ошибиться даже после предупреждения?
Я бы разделял две задачи.
| Механизм | Что делает | Зависит от решения модели | Когда применять |
|---|---|---|---|
| Инструкция | Объясняет правило словами | Да | Для предпочтений и пояснений |
| Хук | Проверяет конкретный вызов до действия | Нет, если скрипт настроен верно | Для запрета изменения выбранного пути |
Поэтому инструкция объясняет, что делать, а хук проверяет, что действие действительно разрешено.
Модель может ошибиться по нескольким причинам:
- правило затерялось среди других сообщений;
- текущая задача выглядит похожей на разрешённую;
- путь файла передан в неожиданном виде;
- модель решила, что предупреждение относится к другой операции;
- после нескольких ходов контекст стал длиннее, и правило перестало влиять на решение.
У детерминированного command hook другая логика: он не рассуждает о задаче и не решает, хорошая ли правка. Он получает конкретный вызов инструмента. Если путь совпал с шаблоном, скрипт возвращает отказ. Prompt- и agent-hooks используют модельную оценку, поэтому это уточнение относится именно к command hook.
В руководстве Anthropic хуки описаны как механизм повторяемой технической проверки, которая не должна зависеть от выбора LLM.
- Anthropic, Automate actions with hooks
Там же Anthropic формулирует смысл механизма ещё жёстче: определённые действия должны происходить всегда. Их выполнение задаётся правилом и не зависит от решения LLM.
Поэтому маленький локальный сторож полезнее ещё одного длинного абзаца в инструкции. Чем уже правило, тем проще его проверить. Для сценария «этот файл не трогать» не нужен агент, который анализирует весь проект. Достаточно команды, которая сравнивает путь.
Какой файл можно поставить под защиту?
Запрос защищенный режим файла здесь означает не режим просмотра и не пароль. Claude Code получает запрет на конкретное действие с конкретным путём.
Начни с одного файла. Например:
src/config/production.jsonСкрипт не обязан читать этот файл и разбирать его содержимое. Ему достаточно получить путь из JSON, который Claude Code передаёт через стандартный ввод. Совпадение с заданным шаблоном означает блокировку.
В документации Claude Code в качестве примеров защищаемых путей рассматриваются .env, package-lock.json и .git/. Это варианты, а не обязательная последовательность: я начинаю с одного конкретного файла, а затем добавляю остальные пути только после проверки.
Можно выбрать и шаблон пути:
src/config/*.jsonНо широкое правило требует осторожности. Если закрыть слишком много файлов, Claude Code начнёт получать отказ на обычные действия. Слишком широкий matcher может блокировать больше операций, чем планировалось, поэтому сначала тестируй правило на одном пути.
Я бы двигался так:
- Выбери один файл, который уже однажды было опасно менять.
- Проверь точное написание пути относительно корня проекта.
- Подключи защиту только к
EditиWrite. - Проверь безопасный файл.
- Проверь настоящий защищённый путь.
- Только после этого добавляй
.env,.git/или шаблон каталога.
Путь и содержимое - разные проверки. В минимальном сценарии не надо искать запрещённый текст внутри файла. Цель проще: не пропустить вызов инструмента, если он направлен на выбранный путь. Если хочешь собрать такой процесс вместе с другими правилами работы агента, посмотри практикум по вайб-кодингу для специалистов и фрилансеров. Пройти практикум: собери проверку на практике и сначала проверь безопасный файл, затем защищённый путь. Только после успешного теста расширяй правило.
Практикум «Старт»
Три дня живой практики: от идеи до работающего проекта по ссылке
2 000 ₽старт 5 августа, 18:00 МСК
Как настроить хук для защиты файла по шагам?

Выбери защищённый файл.
Выбирай путь относительно корня проекта, но помни: в JSON хук получает абсолютный
tool_input.file_path. Сравнивай нормализованный абсолютный путь. В примере защищён файлsrc/config/production.json.Не добавляй сразу несколько каталогов. Сначала проверь одну строку. Так проще понять, сработала ли именно нужная часть правила.
Создай локальный скрипт.
В проекте создай каталог
.claude/hooks, а внутри файлprotect-file.sh.Скрипт читает весь JSON из стандартного ввода. Затем достаёт поле
tool_input.file_path. Если путь совпал с защищённым, команда пишет короткое сообщение и возвращаетexit 2.bash#!/usr/bin/env bash input="$(cat)" file_path="$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty')" file_path="${file_path//\\//}" project_dir="${CLAUDE_PROJECT_DIR//\\//}" protected_path="$project_dir/src/config/production.json" if [[ "$file_path" == "$protected_path" || "$file_path" == "src/config/production.json" ]]; then printf '%s\n' "Blocked: protected file. Ask before editing." >&2 exit 2 fi exit 0Для простого правила подходит
commandhook. Не подключай prompt- или agent-hook: здесь не требуется оценка смысла правки. Путь можно сравнить обычным условием.Сделай скрипт исполняемым.
На macOS или Linux выполни команду из корня проекта.
bashchmod +x .claude/hooks/protect-file.shЕсли команда не подходит среде, сохрани сам скрипт и используй способ запуска, который принят в установленной оболочке. Формат конфигурации при этом остаётся тем же, но путь к команде должен реально запускаться в системе.
Подключи `PreToolUse`.
Открой проектную конфигурацию
.claude/settings.jsonи добавь секциюhooks.json{ "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-file.sh" } ] } ] } }PreToolUseсрабатывает до разрешения и выполнения вызова инструмента.matcherограничивает проверку инструментамиEditиWrite. Остальные действия этот скрипт не ловит.Проверь путь из входного JSON.
В скрипте должно читаться именно поле
tool_input.file_path.Путь в настройке выбирай относительно корня проекта, но в JSON хук получает абсолютный
tool_input.file_path; сравнивай нормализованный абсолютный путь. Содержимое файла и полный текст запроса для этой проверки не нужны. Хук должен работать с адресом файла, который передал инструмент. Так правило привязано к вызову инструмента, к его реальному пути.Верни блокировку через `exit 2`.
Для остановки опасного вызова оставь в запрещённой ветке именно
exit 2.
В запрещённой ветке оставь именно exit 2: одного exit 1 для нужной блокировки недостаточно.
В разделе о кодах завершения руководства Claude Code по хукам код 2 описан как способ остановить вызов инструмента до проверки правил разрешений. Проверь это поведение на тестовом файле.
-
Сохрани короткое сообщение. Оставь одну понятную строку в stderr:
Blocked: protected file. Ask before editing.Не печатай полный лог, трассировку и лишний JSON. При
exit 2причина блокировки может передаваться Claude как feedback, поэтому я держу сообщение коротким. Оно объясняет причину и не засоряет следующие ходы. -
Проверь конфигурацию и запусти Claude Code. Убедись, что JSON не содержит лишних запятых и команда указывает на существующий файл. После этого открой интерфейс
/hooksи посмотри, видит ли Claude Code подключённыйPreToolUse.Затем попроси Claude изменить безопасный тестовый файл. После этого отдельно попроси изменить
src/config/production.json. Первый вызов должен пройти, второй - остановиться сообщением из скрипта.
Измени безопасный тестовый файл и покажи результат. Затем отдельно попробуй изменить src/config/production.json. Если хук заблокирует второе действие, не обходи блокировку и сообщи точный текст отказа.
-
Расширяй список после теста. Когда один файл защищён и проверка проходит, добавляй новые шаблоны в условие скрипта.
Для
.env,package-lock.jsonи.git/понадобятся отдельные сравнения пути. Не превращай условие в универсальный анализатор всего проекта. Узкое правило проще поддерживать и диагностировать.
Как понять, что хук действительно установился?

Запрос установить хук закрывается только после проверки поведения. Файл с правильными скобками - ещё не работающая защита.
Порядок проверки:
- Выполни
claude --version. - Запусти Claude Code из корня нужного проекта.
- Открой
/hooks. - Найди
PreToolUseи matcherEdit|Write. - Попроси изменить безопасный тестовый файл.
- Попроси изменить защищённый файл.
- Убедись, что второе действие остановлено.
Безопасный тест проверяет, что команда вообще может пройти через событие. Реальный Edit или Write проверяет саму защиту. Это разные проверки, и одна не заменяет другую.
Проверка синтаксиса не равна проверке регистрации: открой /hooks и выполни тестовый вызов по безопасному и защищённому пути.
Если безопасный файл меняется, а защищённый тоже меняется, остановись. Не добавляй новые условия наугад. Сначала проверь PreToolUse, matcher, путь и код завершения.
Практикум «Старт»
Три дня живой практики: от идеи до работающего проекта по ссылке
2 000 ₽старт 5 августа, 18:00 МСК
Что ломается, если хук вроде бы настроен, но файл всё равно меняется?

exit 1 вместо exit 2
Коротко: Для защиты файла через PreToolUse в запрещённой ветке оставь именно exit 2. В официальном руководстве Claude Code по хукам этот код описан как способ остановить вызов инструмента, тогда как exit 1 сообщает об ошибке hook и сам по себе не задаёт нужную блокировку. Я проверяю оба результата на тестовом файле: безопасный путь получает exit 0, защищённый путь останавливается с exit 2.
printf '%s\n' "Blocked: protected file. Ask before editing." >&2
exit 2Не делай так:
printf '%s\n' "Blocked: protected file." >&2
exit 1Один из практических разборов о хуках Claude Code предупреждает, что новички ошибочно используют exit 1 вместо exit 2. Я поэтому проверяю код возврата отдельно на безопасном и защищённом пути.
Выбран не тот event
Коротко: Если выбран PostToolUse, запрет не сработает до изменения. Для защиты файла используй PreToolUse.
PostToolUse запускается после вызова. Он может сообщить о результате, но не должен быть основой запрета до изменения.
Проверяй именно тот event, который участвует в правиле. Другой hook может работать, пока PreToolUse не запускается.
Matcher слишком широкий или не работает
Коротко: Matcher Edit|Write ограничивает защиту нужными инструментами. Если убрать фильтр, скрипт начнёт получать лишние вызовы, поэтому для первого варианта оставь простой matcher и проверяй путь внутри скрипта.
Для первого варианта не полагайся на поздние фильтры. Оставь простой matcher и проверяй путь внутри скрипта.
JSON читается неправильно
Коротко: Проверь поле tool_input.file_path: если скрипт ищет путь в другом месте, переменная file_path останется пустой, условие не совпадёт, и скрипт вернёт exit 0.
Как сделать сообщение об ошибке коротким?
Коротко: При exit 2 причина блокировки может передаваться Claude как feedback, поэтому сообщение лучше делать коротким. Я оставляю в stderr одну строку с причиной отказа, проверяю её на защищённом пути и не добавляю трассировку, полный JSON или отладочные данные.
При exit 2 причина блокировки может передаваться Claude как feedback, поэтому сообщение лучше делать коротким.
Поэтому блокирующее сообщение должно быть коротким. Причина, действие и ничего лишнего:
Blocked: protected file. Ask before editing.Ненулевой код сам по себе не означает блокировку. Для остановки вызова оставь exit 2, а перед этим проверь, что сработал именно PreToolUse.
Как не превратить защиту файла в новую дыру?
Чужой проект может содержать .claude/settings.json с командой, которую Claude Code запустит при старте. Официальная инструкция по безопасному допуску Claude Code к проекту предупреждает: настройки проекта и команды hooks нужно проверить до запуска чужой папки.
В материале о сдерживании Claude Anthropic рекомендует учитывать, какие настройки и команды запускаются при работе с проектом. Поэтому перед запуском чужого проекта проверь настройки и команды hooks.
Перед запуском чужого проекта проверь:
.claude/settings.json..claude/settings.local.json.- Команды внутри секции
hooks. - Файлы скриптов, на которые ссылается конфигурация.
Для своей защиты оставь маленький command hook с одной понятной проверкой. В документации Claude Code по хукам agent-hooks помечены как экспериментальные; для проверки точного пути я использую command hook.
Один hook не закрывает всю систему. Он защищает выбранный вызов в Claude Code. Для настройки разрешений перед подключением GitHub смотри отдельную инструкцию по разрешениям Claude Code. Права операционной системы и сетевые ограничения решают другие задачи. Если агент получил лишний доступ, запрет на один путь не исправит остальные риски.
Проверяй собственный hook так же, как проверяешь сторонний код. Он запускается с правами текущего пользователя и может выполнять команды.
Вопросы и ответы
Вопросы и ответы
Как остановить изменение файла хуком?
Создай локальный command hook на событии PreToolUse. Ограничь matcher значениями Edit|Write, прочитай tool_input.file_path, сравни путь с защищённым шаблоном и верни exit 2. После настройки проверь безопасный файл и отдельный вызов по настоящему защищённому пути.
Что добавить в конфигурацию?
В .claude/settings.json нужна секция hooks с событием PreToolUse, matcher Edit|Write и command hook, который запускает локальный скрипт. Сам скрипт читает JSON из стандартного ввода и проверяет поле tool_input.file_path.
Как проверить, что хук загрузился?
Выполни claude --version, открой /hooks и найди подключённый PreToolUse. Затем проверь изменение тестового файла и отдельно попробуй изменить защищённый файл через Edit или Write. Валидный JSON без такого теста не подтверждает загрузку.
Нужен ли для этого отдельный агент?
Нет. Для сравнения пути подходит простой command hook. Prompt- и agent-hooks не нужны для правила с точным совпадением. Документация Claude Code помечает agent-hooks как экспериментальные, а здесь достаточно command hook, который сравнивает путь без модельной оценки.
Что именно проверяет скрипт?
Скрипт проверяет путь файла из tool_input.file_path, а не содержимое. Под защиту можно поставить один выбранный файл, .env, package-lock.json, .git/ или шаблон пути. Начинать безопаснее с одного конкретного файла.
Каким должен быть хороший хук?
Хороший hook узкий и проверяемый. Он ловит только нужные инструменты, читает конкретное поле JSON, выводит короткую причину и возвращает exit 2. Такой hook проще проверить и сложнее случайно применить к лишним действиям.
Какое событие использовать для защиты файла?
Для этой задачи нужен PreToolUse. Он запускается до вызова инструмента и способен заблокировать его. В статье используются Edit и Write. Другие события не нужны для минимальной защиты конкретного пути.
Где посмотреть хук официальный сайт Claude Code?
Актуальное описание находится на странице хук официальный сайт Claude Code: там PreToolUse описан как событие до выполнения вызова, способное его заблокировать. Проверяй версию документации перед настройкой. Перед публикацией я сначала проверяю безопасный файл, затем защищённый путь через Edit и Write. Только после успешного теста добавляю новые шаблоны. > Пройти практикум. Собери такой инструмент на практике: практикум по вайб-кодингу для специалистов и фрилансеров.
Источники
Практикум «Старт»
Три дня живой практики: от идеи до работающего проекта по ссылке
2 000 ₽старт 5 августа, 18:00 МСК

