Хуки Claude Code: 5 готовых настроек, которые блокируют rm -rf, защищают файлы и пишут журнал команд (октябрь 2026)

Хуки Claude Code: 5 готовых настроек, которые блокируют rm -rf, защищают файлы и пишут журнал команд (октябрь 2026)

Конфиги и скрипты собраны по образцам из документации Anthropic, скрипты прогнаны 23 октября 2026 года.

Хук — это команда оболочки, которую Claude Code запускает сам в определённый момент работы: до или после вызова инструмента, при уведомлении, при смене настроек. В отличие от строчки в CLAUDE.md, хук срабатывает всегда: по описанию Anthropic, это «детерминированный контроль», а не просьба к модели. Ниже пять настроек, которые закрывают самые частые риски. Для скриптов нужен jq (на macOS — brew install jq, на Debian и Ubuntu — apt-get install jq).

1. Блокировка rm -rf до запуска

Событие PreToolUse срабатывает до вызова инструмента и умеет его остановить. Скрипт читает команду из JSON на stdin, ищет в ней rm -rf и завершается с кодом 2 — это сигнал «заблокировать». Текст из stderr Claude получает как объяснение и может выбрать другой путь. Скрипт собран по образцу блокировки drop table из документации. Сохранить как .claude/hooks/block-rm-rf.sh:

#!/bin/bash INPUT=$(cat) COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command') if echo "$COMMAND" | grep -q "rm -rf"; then echo "Blocked: rm -rf is not allowed" >&2 exit 2 fi exit 0

Сделать скрипт исполняемым (без этого Claude Code его не запустит): chmod +x .claude/hooks/block-rm-rf.sh. Подключить в .claude/settings.json в корне проекта:

{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-rm-rf.sh" } ] } ] } }

Блокировка работает и в режиме bypassPermissions, и с --dangerously-skip-permissions: по документации, PreToolUse-хуки срабатывают раньше проверки режима разрешений. Ограничение: это поиск подстроки, поэтому rm -fr или rm -r -f он не поймает. Для надёжного запрета в правила разрешений добавляют deny-правило.

2. Защита .env, package-lock.json и .git

Тот же приём, но для инструментов Edit и Write. Скрипт сверяет путь файла со списком защищённых шаблонов. Сохранить как .claude/hooks/protect-files.sh:

#!/bin/bash # protect-files.sh INPUT=$(cat) FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty') # Normalize Windows backslash separators so the patterns below match FILE_PATH="${FILE_PATH//\\//}" PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/") for pattern in "${PROTECTED_PATTERNS[@]}"; do if [[ "$FILE_PATH" == *"$pattern"* ]]; then echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2 exit 2 fi done exit 0

Сделать исполняемым: chmod +x .claude/hooks/protect-files.sh. Регистрация — тот же PreToolUse, но с другим матчером:

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

Проверка: попросить Claude добавить комментарий в .env. Правка не выполнится, а сообщение Blocked: уйдёт модели. Оговорка из документации: файлы можно изменить и через shell-команды, поэтому для полного покрытия Anthropic предлагает добавить матчер Bash или хук Stop, который сканирует рабочее дерево.

3. Журнал всех команд Bash

Событие PostToolUse срабатывает после команды, и в tool_input.command лежит то, что реально выполнилось. Одна строка добавляет каждую команду в файл. Добавить в ~/.claude/settings.json (для всех проектов) или в .claude/settings.json:

{ "hooks": { "PostToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "jq -r '.tool_input.command' >> ~/.claude/command-log.txt" } ] } ] } }

Хуки на одно событие выполняются параллельно, поэтому журнал и блокировку можно повесить на Bash вместе: в документации так и показан пример с логом и скриптом block-rm-rf.sh. Запрещённая команда в журнал всё равно попадёт, если запись идёт в PreToolUse, — запись из PostToolUse фиксирует только выполненное.

4. Журнал изменений настроек

Событие ConfigChange срабатывает, когда внешний процесс или редактор меняет файл настроек или скиллов во время сессии. Хук дописывает в лог время, источник и путь. Добавить в ~/.claude/settings.json:

{ "hooks": { "ConfigChange": [ { "matcher": "", "hooks": [ { "type": "command", "command": "jq -c '{timestamp: now | todate, source: .source, file: .file_path}' >> ~/claude-config-audit.log" } ] } ] } }

Матчер фильтрует по типу настроек: user_settings, project_settings, local_settings, policy_settings или skills. Чтобы запретить изменение, а не только записать его, хук должен завершиться кодом 2 или вернуть {"decision": "block"}. Справочник по хукам уточняет: изменение policy_settings заблокировать нельзя, а при коде 2 Claude сообщения не видит.

5. Блокировка при сбое самого хука

Слабое место защитных хуков — их собственные поломки. По документации, на большинстве событий упавший или завершившийся по таймауту хук не мешает действию: неверный путь к скрипту или падение — и проверка молча пропускает всё. Поле "onFailure": "block" меняет это: сбой считается блокировкой, как код 2. Требуется Claude Code v2.1.295 или новее, работает для хуков типов command и http:

{ "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "node", "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/check-command.js"], "onFailure": "block" } ] } ] } }

Сбоем считаются: хук не запустился, вышел с кодом, отличным от 0 и 2, превысил таймаут или вернул некорректный вывод; для HTTP-хука — ещё ошибка или ответ не 2xx. На событиях Stop, SubagentStop, TaskCompleted и TeammateIdle поле ничего не меняет, потому что код 2 там отправляет Claude работать дальше. Не действует оно и на фоновые хуки с async или asyncRewake.

Как проверить, что хук подключён

  • Команда /hooks в Claude Code открывает список всех хуков по событиям. Нужный хук должен быть под своим событием.
  • Проверить скрипт без Claude Code: echo '{"tool_name":"Bash","tool_input":{"command":"rm -rf /tmp/build"}}' | .claude/hooks/block-rm-rf.sh; echo $? — скрипт должен вернуть 2.
  • Хук не срабатывает: матчеры чувствительны к регистру, поэтому bash не совпадёт с Bash.
  • Итог выполнения видно в транскрипте по Ctrl+O; подробный лог — при запуске claude --debug-file /tmp/claude.log.
  • Если JSON-ответ хука не действует, причина часто в лишнем выводе профиля оболочки перед JSON: echo в ~/.zshrc или ~/.bashrc нужно обернуть в проверку интерактивной сессии.

Что где лежит

  • ~/.claude/settings.json — все проекты, только на этой машине.
  • .claude/settings.json — один проект, можно коммитить в репозиторий.
  • .claude/settings.local.json — один проект, не для коммита.
  • Примеры из документации Anthropic также лежат в репозитории claude-code: полный валидатор команд Bash на Python.

Всё самое интересное — в нашем Telegram-канале «Claude без воды».

22