✻ Claude Code по-русски
🎧 Аудиокурс
🎧 Слушать урок9:32 · голос Russian_BrightHeroine

#Закрепите правило хуком

Средний уровень · Урок 5 из 8 · около 20 минут · Нужно: Разрешения, области настроек и песочница · Сверено с Claude Code v2.1.285 (stable) 06.10.2026

#Цель

К концу урока вы сможете добавить хук, который применяет правило каждый раз, когда Claude правит файл, и показать, что он срабатывает.

#Что понадобится

#Идея

Правило в CLAUDE.md — это совет, который Claude может пропустить. Хук — это ваша собственная команда, которую Claude Code запускает в определённый момент сессии каждый раз, что бы ни решил Claude. Claude Code передаёт хуку JSON с описанием события на stdin. Хук PreToolUse запускается перед вызовом инструмента; если он завершается с кодом 2, вызов блокируется, а то, что хук вывел в stderr, уходит Claude как причина (Hooks reference, Block edits to protected files).

Вот события, которые использует этот урок, и их место в ходе:

flowchart LR
  accTitle: Где в ходе срабатывают события хуков
  accDescr: Сессия начинается с SessionStart. Каждый промпт вызывает UserPromptSubmit. Перед каждым вызовом инструмента запускается PreToolUse; код выхода 2 блокирует вызов. После успешного вызова запускается PostToolUse, затем Claude может вызвать следующий инструмент. Когда Claude заканчивает отвечать, срабатывает Stop. Notification срабатывает отдельно — всякий раз, когда Claude Code нужно ваше внимание.
  S[SessionStart] --> U[UserPromptSubmit]
  U --> P[PreToolUse]
  P -->|exit 2| B[Вызов заблокирован, stderr уходит Claude]
  P -->|exit 0| T[Проверка разрешений, затем инструмент работает]
  T --> Q[PostToolUse]
  Q -->|следующий вызов| P
  Q --> E[Stop]
  N[Notification — когда Claude Code нужны вы]

Матчер выбирает инструменты, за которыми следит хук: Edit|Write запускает его только для этих двух инструментов (Filter hooks with matchers). Хуки PreToolUse срабатывают до проверки режима разрешений, поэтому блокировка действует в любом режиме (Hooks and permission modes).

#Разбор примера

  1. Скачайте в свой репозиторий два примера хуков из этого руководства и сделайте их исполняемыми. Прочитайте их, прежде чем использовать:
mkdir -p .claude/hooks
for f in protect-files format-after-edit; do
  curl -fsSL "https://raw.githubusercontent.com/wesammustafa/Claude-Code-Everything-You-Need-to-Know/main/examples/intermediate/05-hooks/dot-claude/hooks/$f.sh" -o ".claude/hooks/$f.sh"
done
chmod +x .claude/hooks/*.sh

protect-files.sh — скрипт из руководства по хукам, блокирующий правки .env, package-lock.json и .git/. format-after-edit.sh убирает пробелы в конце строк исходного файла после того, как Claude его отредактировал. 2. Зарегистрируйте их в .claude/settings.json рядом с блоком permissions из урока 4:

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

С "args": [] Claude Code запускает скрипт напрямую, без оболочки, поэтому путь не нужно брать в кавычки (Exec form and shell form). 3. Проверьте хук без Claude, подав на вход JSON, который отправил бы вызов Edit. Edit и Write всегда передают абсолютный путь (PreToolUse input), поэтому соберите его из $PWD:

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

Скрипт выведет строку Blocked: и exit 2. 4. Запустите claude и выполните /hooks: ваши хуки появятся в разделах PreToolUse и PostToolUse (Debug your configuration). 5. Попросите правку, от которой защищает хук. В шаблоне для практики есть package-lock.json; в своём репозитории назовите защищённый файл, который в нём есть:

Use your Edit tool, not a shell command, to change the top-level version in package-lock.json to 1.0.1.

Правка блокируется: Claude Code передаёт сообщение Blocked: вашего скрипта Claude как обратную связь (Exit code output). Здесь просите инструмент Edit по имени: Claude может отредактировать файл и командой оболочки, а её хук Edit|Write не видит.

#Ваша очередь

Скрипт из руководства сравнивает подстроки. *".env"* блокирует и .env.example, который команды коммитят намеренно, и файл вроде src/config.envelope.ts; а папку secrets/ не блокирует ничто. Замените .claude/hooks/protect-files.sh этой заготовкой — она сохраняет блокировки package-lock.json и .git/ из руководства — и допишите её:

#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
FILE_PATH="${FILE_PATH//\\//}"
NAME=$(basename "$FILE_PATH")

case "/$FILE_PATH" in
  */package-lock.json | */.git/*)
    echo "Blocked: $FILE_PATH is protected" >&2
    exit 2
    ;;
esac

# TODO: block a file named .env, or .env. followed by anything except example
# TODO: block any file inside a secrets/ folder

exit 0
  1. Каждая блокировка выводит причину Blocked: в stderr и завершается с кодом 2; всё остальное завершается с кодом 0.
  2. Прогоняйте таблицу тестов из раздела «Проверка», пока каждая строка не даст ожидаемый код выхода.
  3. В сессии попросите Claude создать secrets/test.key инструментом Write. Ваш хук это заблокирует.
  4. Закоммитьте скрипт и .claude/settings.json. Скрипт должен остаться исполняемым: вывод git ls-files -s .claude/hooks/protect-files.sh начинается с 100755.

#Проверка

Урок пройден, когда выполнено всё это:

for p in .env config/.env.local .env.example secrets/api.key src/config.envelope.ts src/app.js package-lock.json .git/config; do
  printf '%s ' "$p"; echo "{\"tool_input\":{\"file_path\":\"$PWD/$p\"}}" | .claude/hooks/protect-files.sh 2>/dev/null; echo $?
done

Запустите npm run check -- i-5 --dir <your repo> из своей копии для практики или npm run check -- i-5 в самой копии.

Если какая-то строка неверна, проверьте этот путь отдельно и выведите имя, которое видит скрипт: basename от .env.local — это .env.local, поэтому шаблон case .env.* с ним совпадает. Проверка запускает закоммиченный скрипт, поэтому коммитьте каждое исправление перед запуском. Если второй пункт не проходит из-за режима файла, выполните chmod +x .claude/hooks/protect-files.sh, затем git add и закоммитьте снова.

#Осторожно

#Что дальше


Источники: Automate actions with hooks · Hooks reference · Configure permissions · Debug your configuration

← Разрешения, области настроек и песочница · Оглавление Среднего уровня · Делегируйте задачу своему субагенту → · Тема: Хуки · Застряли на уроке?