Хуки в Claude Code: 7 примеров для settings.json
MarkdownПрактическая инструкция по хукам Claude Code: настройка через .claude/settings.json, 4 типа обработчиков, 31 событие и 7 примеров для защиты .env, форматирования, Git и контекста сессии.
Читать статью полностью
Хуки Claude Code — это shell-команды, HTTP-запросы или короткие проверки с помощью LLM, которые автоматически запускаются до или после действия Claude. Они помогают обеспечить правила, на которые нельзя полагаться в одном лишь CLAUDE.md: например, запретить удаление .env, блокировать force-push в main, форматировать изменённый код или добавлять актуальный контекст при старте сессии. В статье разобраны 4 типа обработчиков, 31 событие жизненного цикла, способ определить, какое правило стоит вынести в hook, 7 готовых примеров для .claude/settings.json и 3 частые проблемы.
Документация Ailoot: API, ключи и подключение.
Что такое хуки в Claude Code?
Ключевой вывод
Хук — это shell-команда, HTTP-запрос, короткий LLM-промпт или субагент, запускаемый Claude Code при определённом событии жизненного цикла. В отличие от текста в CLAUDE.md, который модель может упустить из внимания, хук при наступлении события выполняется по заданным правилам: это код, а не просьба.
Правило «не редактировать .env напрямую» долго оставалось у меня в CLAUDE.md, но в продолжительных сессиях Claude иногда его забывал. Однажды в файл попал лишний токен, а в другой раз переменная с повторяющимся именем перезаписала рабочую.
При совпавшем прямом Edit с путём .env hook отклоняет этот вызов. Перенаправление Bash, скрипты, MCP и другие пути требуют отдельных ограничений. Файл не становится неизменяемым.
Хуки — это заданные вами shell-команды, HTTP-endpoints или LLM-prompts, которые автоматически запускаются в определённых точках жизненного цикла Claude Code.
Проще говоря, хук — ваша команда, которую Claude Code запускает при заданном событии. Таким событием может быть редактирование файла, запуск Bash, начало сессии или завершение субагента.
Хуки добавляют проверки отдельных событий, форматирование после правки и свежий контекст сессии. Совпадающий PreToolUse может отклонить вызов; regex-примеры — удобные ограничения конкретных путей, не полная защита доступа к файлам и Git. Примеры:
- Защищать файлы с секретами от случайных изменений.
- Запускать prettier или eslint после генерации кода.
- Запрещать
git push --forceв main без явного разрешения. - Добавлять свежий контекст при старте каждой сессии.
- Записывать действия Claude для последующего аудита.
CLAUDE.md задаёт контекст, а хуки управляют действиями. Это разные механизмы, и смешивать их назначение — распространённая ошибка.
Чем хуки отличаются от CLAUDE.md и скиллов?
Ключевой вывод
CLAUDE.md содержит текст, который модель читает в начале сессии и старается учитывать. Хук — команда, запускаемая процессом Claude Code при событии, независимо от модели. Скилл — набор инструкций с именем, который Claude может вызвать через инструмент Skill. У каждого из этих механизмов своя задача.
Anthropic отдельно объясняет различие между CLAUDE.md и хуками:
Содержимое CLAUDE.md поступает как user message после system prompt, а не включается в system prompt. Claude читает его и старается следовать указаниям, однако строгой гарантии соблюдения нет.
Иными словами, содержимое CLAUDE.md приходит Claude как начальное сообщение пользователя, а не как системная инструкция. Модель прочитает его и постарается учесть, но гарантировать выполнение нельзя. В длинной сессии контекст увеличивается, и ранние инструкции могут потеряться.
Hook запускается процессом Claude Code по событию. PreToolUse может проверить и отклонить ещё не выполненный вызов, PostToolUse обрабатывает результат уже выполненного действия. Не приравнивайте обратную связь после записи к запрету самой записи.
| Признак | CLAUDE.md | Hook | Skill |
|---|---|---|---|
| Где хранится | CLAUDE.md в корне проекта | .claude/settings.json | Папка .claude/skills/ |
| Кто запускает | Модель читает как часть user message | Процесс Claude Code при событии | Модель через инструмент Skill |
| Насколько гарантирован запуск | Нет, выполнение зависит от модели | Совпавший настроенный command-hook выполняет код; отказ и exit-поведение зависят от события | Вызывается моделью; грант есть, но на уровне shell гарантий нет |
| Для чего подходит | Контекст проекта, тон, стиль, маршрутизация | Запреты, форматирование и проверки отдельных файлов | Сложные многоэтапные процедуры с параметрами |
| Когда срабатывает | При каждом сообщении модели в сессии | При событии жизненного цикла | По вызову модели |
| Может ли заблокировать действие | Нет | Совпавший PreToolUse с exit2; PostToolUse только сообщает после выполнения | Нет |
Шаблон CLAUDE.md и правила его поддержки приведены в гайде Как настроить CLAUDE.md в 2026: готовый шаблон и 6 правил. О создании именованных навыков читайте в статье Claude Code Skills: как собрать библиотеку под себя.
Хук работает на нижнем уровне: это обычная shell-команда, которой не требуется интерпретация модели.
Хуки — один из инструментов контекст-инжиниринга, наряду с Plan Mode и /compact.
4 типа хуков: Command, HTTP, Prompt, Agent — какой выбрать?
Ключевой вывод
В Claude Code доступны 4 типа обработчиков. Command запускает shell-скрипт и подходит для большинства проверок. HTTP отправляет POST-запрос на заданный URL — например, для командных интеграций. Prompt передаёт короткий запрос модели Haiku для семантической оценки. Agent запускает субагента с доступом к инструментам для более глубокой проверки. Для начала обычно достаточно Command и Prompt.
| Тип | Что делает | Когда подходит | Сложность |
|---|---|---|---|
| Command | Передаёт JSON через stdin shell-команде; результат задаётся exit code и stdout | Проверка путей, форматирование, поиск по содержимому, lsof и операции Git | низкая |
| HTTP | Отправляет JSON в теле POST-запроса на заданный URL и получает JSON-ответ | Для командных процессов и интеграций: общий валидатор, панель статусов или удалённый аудит | средняя (нужен сервер) |
| Prompt | Отправляет короткий промпт в Haiku (по умолчанию) и получает ответ для семантической оценки | Когда поиска по текстовому шаблону недостаточно, например для оценки корпоративного тона | низкая |
| Agent | Запускает субагента с доступом к Read/Grep/Glob для проверки в несколько шагов | Для сложных задач, например проверки соответствия изменённых файлов тестам | высокая |
Частая ошибка — пытаться решить с помощью Command задачу, требующую семантической оценки. Правило «не использовать длинное тире в .md» можно проверить через grep, поэтому здесь подходит Command. А оценка «не писать корпоративным тоном» требует понимания смысла и лучше подходит для Prompt.
Для начала попробуйте Command: все 7 примеров ниже относятся к этому типу. HTTP, Prompt и Agent можно подключить позже, когда возникнет подходящая задача.
Где находится settings.json и какие есть 4 уровня конфигурации?
Ключевой вывод
Claude Code использует конфигурации четырёх уровней: корпоративную, распространяемую через MDM; пользовательскую (~/.claude/settings.json); проектную (.claude/settings.json в корне репозитория); локальную (.claude/settings.local.json, не включаемую в Git). При запуске сессии файлы объединяются, а при конфликте приоритет получает более низкий уровень.
| Уровень | Путь | Где применяется | В git? |
|---|---|---|---|
| Корпоративный | /Library/Application Support/ClaudeCode/settings.json (Mac), /etc/claude-code/settings.json (Linux) | Для команды через MDM | нет |
| Пользовательский | ~/.claude/settings.json | Во всех проектах пользователя | нет |
| Проектный | .claude/settings.json в корне репозитория | В текущем проекте для всей команды | да |
| Локальный | .claude/settings.local.json | Только в этом проекте и для этого пользователя | нет (в .gitignore) |
Я размещаю все 7 описанных ниже хуков в проектном .claude/settings.json. Тогда при клонировании репозитория настройки доступны команде, и Claude применяет общие правила. Личные эксперименты храню в .claude/settings.local.json.
Все четыре файла объединяются при запуске сессии. Если настройки конфликтуют, приоритет у более низкого уровня: локальный важнее проектного, а проектный — пользовательского.
Самый быстрый способ добавить первый хук — открыть в Claude Code меню /hooks. Выберите событие и matcher, например Bash или Edit, затем задайте команду. Claude Code сохранит корректную структуру JSON в settings.json.
31 событие жизненного цикла: что пригодится начинающим?
Ключевой вывод
В Claude Code указано 31 событие жизненного цикла. Они происходят с разной частотой: один раз за сессию (SessionStart/SessionEnd), один раз за ход (UserPromptSubmit/Stop) или при вызове инструмента (PreToolUse/PostToolUse). Для начала обратите внимание на четыре: PreToolUse для запретов, PostToolUse для изменений после действия, SessionStart для загрузки контекста и Stop для финальной проверки.
События возникают с тремя частотами: один раз за сессию (SessionStart, SessionEnd), один раз за turn (UserPromptSubmit, Stop, StopFailure) и при каждом tool call внутри agentic loop (PreToolUse, PostToolUse).
Чтобы выбрать подходящее событие, полезно различать три частоты срабатывания:
- Один раз за сессию —
SessionStart,SessionEnd,Setup. Эти события возникают при открытии или закрытии Claude Code и подходят для инициализации контекста или очистки временных файлов. - Один раз за ход —
UserPromptSubmit,UserPromptExpansion,Stop,StopFailure. Они срабатывают при отправке сообщения и остановке модели; их можно использовать для записи диалога и итоговой проверки результата. - При каждом вызове инструмента —
PreToolUse,PostToolUse,PostToolUseFailure,PermissionRequest,PermissionDenied,PostToolBatch,SubagentStart,SubagentStop. Такие события возникают при действиях вроде редактирования файла, запуска Bash, чтения и поиска. Здесь размещают запреты, форматирование и проверки.
Среди 31 события есть также асинхронные и реактивные: TeammateIdle, PreCompact, PostCompact, Elicitation, ElicitationResult, InstructionsLoaded, ConfigChange, CwdChanged, FileChanged, WorktreeCreate, WorktreeRemove, Notification. Они нужны для более специализированных сценариев.
Проверка из 5 вопросов: когда правило переносить в hook, а когда оставить в CLAUDE.md?
Ключевой вывод
Переносите правило в хук, если оно относится к действиям, касается безопасности, денег или данных, поддаётся проверке через grep или regex, а нарушение сложно отменить либо Claude уже забывал это правило. Если утвердительно ответили менее чем на три из пяти вопросов, оставьте его в CLAUDE.md. При разборе своего файла на 80 строк автор перенёс в хуки 5 правил.
Я использую пять вопросов, чтобы решить, где хранить правило — в CLAUDE.md или в хуке. Если набирается не менее трёх ответов «да», правило подходит для хука. При меньшем числе ответов его можно оставить в текстовом файле.
Проверьте, стоит ли перенести правило в hook:
- Оно задаёт действие, а не описывает контекст? («не запускай
rm -rf» — действие; «проект написан на TypeScript» — контекст.) - Оно связано с безопасностью, деньгами или данными? Например, «не меняй
.env» или «не публикуй ключи». - Его можно проверить через grep, regex или exit code shell-команды? Например, проверить длинное тире после редактирования
.md. - Нарушение будет сложно исправить? Например, force push в main отменить сложнее, чем пропущенную точку в конце предложения.
- Вы уже замечали, что Claude забывает это правило?
Пример: «не используй длинное тире, пиши обычный дефис». Это правило о действии — да. О безопасности — нет. Проверяется через grep — да. Последствия сложно отменить — нет. Нарушение уже встречалось — да. 3 ответа из 5: правило подходит для хука.
Контрпример: «пиши без сленга для пользователей, которые не занимаются разработкой». Это скорее контекст, чем действие. К безопасности не относится. Надёжно проверить regex сложно. Нарушение легко исправить. Даже если оно уже случалось, получается 1 ответ из 5 — правило остаётся в CLAUDE.md.
В описанном примере проверку прошли 5 правил, которые автор перенёс в хуки. Остальные 75% остались в текстовом файле.
7 готовых хуков для копирования
Ключевой вывод
Ниже приведены 7 примеров для .claude/settings.json: запрет на изменение .env, запуск prettier, блокировка force-push в main, проверка длинного тире, освобождение порта перед npm run dev, автоматический коммит после успешных тестов и добавление свежих сведений при старте сессии. Вставьте выбранный пример в файл настроек и перезапустите Claude Code.
Все семь хуков размещаются в .claude/settings.json в корне проекта. Каждый содержит событие, фильтр инструмента (matcher) и shell-команду. Exit2 отклоняет совпавший PreToolUse до исполнения. В PostToolUse действие уже произошло: hook сообщает обратную связь, не отменяя его.
Для большинства событий блокировку вызывает только exit code 2. Claude Code считает exit code 1 неблокирующей ошибкой и продолжает действие, хотя в Unix-контексте 1 обычно означает ошибку.
exit 0 означает успешное выполнение. exit 1 сообщает об ошибке, но не останавливает Claude — это первая ловушка, описанная ниже. exit 2 зависит от события: PreToolUse может блокироваться, а PostToolUse сообщает о уже выполненном действии.
Хук1. Проверка прямой правки .env (PreToolUse, exit2)
Этот хук блокирует прямое редактирование файлов .env, .env.local, .env.production и других имён, соответствующих шаблону.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '(^|/)\\.env(\\.|$)' && { echo 'Запрещено редактировать .env напрямую. Скажи мне какую переменную добавить, я сам открою файл.' >&2; exit 2; } || exit 0"
}
]
}
]
}
}
Как работает: перед Edit, Write или MultiEdit команда получает путь, проверяет его через grep и при совпадении с шаблоном .env возвращает exit 2 с пояснением. Claude получает stderr и сообщает, что попытка изменения заблокирована.
Хук 2. Запуск prettier после редактирования кода (PostToolUse, exit 0)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '\\.(ts|tsx|js|jsx|json)$' && npx prettier --write \"$FILE\" 2>/dev/null & exit 0"
}
]
}
]
}
}
Как работает: после Edit или Write команда проверяет расширение файла. Для .ts, .tsx, .js, .jsx и .json она запускает prettier в фоне через &. Хук всегда возвращает exit 0: форматирование не должно блокировать действие. Если prettier завершится с ошибкой, исходный файл останется без этой дополнительной обработки.
Хук 1 срабатывает на PreToolUse и exit 2, поэтому блокирует действие до его выполнения. Хук 2 запускается на PostToolUse и возвращает exit 0, чтобы обработать результат после редактирования. Эти режимы предназначены для разных задач.
Хук 3. Запрет git push --force в main (PreToolUse, exit 2)
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "CMD=$(jq -r '.tool_input.command // empty'); [ -z \"$CMD\" ] && exit 0; echo \"$CMD\" | grep -qE 'git[[:space:]]+push' && echo \"$CMD\" | grep -qE '(\\-\\-force|\\-\\-force-with-lease|[[:space:]]-f([[:space:]]|$))' && echo \"$CMD\" | grep -qE '([[:space:]/:])main([[:space:]/:]|$)' && { echo 'Force push в main запрещён. Сделай новую ветку или попроси меня вручную.' >&2; exit 2; } || exit 0"
}
]
}
]
}
}
Как работает: перед запуском Bash проверяется, содержит ли команда push, флаг --force, --force-with-lease или -f, а также указание на main. Если совпали все три условия, хук останавливает действие и сообщает причину.
В исходном примере автор хранил это правило в CLAUDE.md, но Claude иногда его нарушал при просьбе выполнить force push для отката неудачного коммита. Hook ловит показанные буквальные команды. Алиасы, скрипты, неявная ветка назначения и другой Git-клиент обходят строковую проверку. Защитите main на сервере и ограничьте ключи агента.
Хук 4. Поиск длинного тире в текстовых файлах (PostToolUse, exit 2)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '\\.(md|mdx|tsx?)$' && grep -q $'\\xe2\\x80\\x94' \"$FILE\" && { echo \"В файле $FILE найдено длинное тире (U+2014). Замени на обычный дефис (U+002D).\" >&2; exit 2; } || exit 0"
}
]
}
]
}
}
Как работает: PostToolUse ищет длинное тире после уже выполненной правки. Exit2 сообщает Claude об ошибке последующей проверки, но не отменяет и не предотвращает запись. Затем можно исправить символ.
Команда ищет именно символ U+2014 через bash-запись $'\xe2\x80\x94', задающую его байты в UTF-8. Если искать обычный дефис с помощью grep -q '-', проверка будет срабатывать на каждом файле, где есть дефис.
Хук 5. Освобождение порта 3000 перед npm run dev (PreToolUse, exit 0)
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "CMD=$(jq -r '.tool_input.command // empty'); [ -z \"$CMD\" ] && exit 0; echo \"$CMD\" | grep -qE '(npm|pnpm|yarn)[[:space:]]+run[[:space:]]+dev' && { lsof -ti:3000 | xargs -r kill -9 2>/dev/null; echo 'Порт 3000 освобождён перед запуском' >&2; }; exit 0"
}
]
}
]
}
}
Как работает: перед командой npm run dev, pnpm run dev или yarn run dev хук завершает процесс, занимающий порт 3000. Он всегда возвращает exit 0, поскольку подготавливает среду, а не запрещает действие. Это помогает избежать ситуации, когда запущенный ранее сервер мешает новому запуску.
Хук 6. Автоматический коммит после успешных тестов (PostToolUse, exit 0)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); CMD=$(printf '%s' \"$INPUT\" | jq -r '.tool_input.command // empty') || exit 1; EXIT=$(printf '%s' \"$INPUT\" | jq -r '.tool_response.exit_code // empty') || exit 1; case \"$CMD\" in 'npm test'|'pnpm test'|'yarn test') ;; *) exit 0 ;; esac; [ \"$EXIT\" = \"0\" ] || exit 0; git diff --cached --quiet || { echo 'Existing staged changes: review manually' >&2; exit 0; }; git add -- src/orders.ts tests/orders.test.ts || exit 1; git diff --cached --quiet && exit 0; git commit -m 'tests: checkpoint after successful run'"
}
]
}
]
}
}
Как работает: читает JSON stdin один раз, принимает только показанные точные команды тестов и продолжает лишь при явном tool_response.exit_code=0. При отсутствии поля в вашей версии пропускает коммит, не угадывая успех. Замените src/orders.ts и tests/orders.test.ts точными файлами задачи. Уже добавленные в индекс изменения останавливают рецепт, ошибка git add тоже; пустой diff не создаёт коммит. Обычные проверки коммита включены. До активации офлайн испытайте успех, отказ и отсутствующий результат.
Не добавляйте git commit --no-verify к каждому Edit. Проверки коммита оставьте включёнными. При рекурсии сузьте триггер или измените проверку вместо стандартного обхода. До автокоммитов изучите индекс и владение задачей.
Хук 7. Добавление актуального контекста при запуске (SessionStart и additionalContext)
{
"hooks": {
"SessionStart": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo 'no-branch'); STATUS=$(git status --short 2>/dev/null | head -10); echo \"{\\\"additionalContext\\\":\\\"Текущая ветка: $BRANCH. Незакоммиченные изменения:\\n$STATUS\\\"}\""
}
]
}
]
}
}
Как работает: при старте сессии команда получает текущую ветку и первые десять строк списка незакоммиченных изменений. Результат возвращается в JSON в поле additionalContext, которое Claude Code добавляет в контекст сессии.
Используйте additionalContext для сведений о текущем состоянии среды или только что выполненной операции. Например, передавайте текущую ветку, цель развёртывания, активные feature flags, правила проекта для тестирования изменённого файла или внешние данные — открытые issues и последние результаты CI.
В этот хук также можно добавить сведения о последнем коммите, статусе GitHub Actions, текущем спринте в Linear или Jira и открытых задачах репозитория.
3 частые ошибки при настройке хуков
Ключевой вывод
Первая проблема: exit 1 может не остановить действие, и Claude продолжит работу. Вторая: длительная команда может превысить таймаут в 60 секунд. Третья: хук получает окружение процесса Claude Code, но не обязательно переменные из .env проекта. Учитывайте эти особенности при настройке и проверке команд.
Ошибка 1. Хук с exit 1 не блокирует действие
Если hook-команда завершилась с exit 1, Claude Code может воспринять это как неблокирующую ошибку и продолжить действие. Например, проверка пути через jq -r '.tool_input.file_path' может завершиться ошибкой, если значение пустое или равно null. Тогда защитный хук не остановит редактирование .env.
Чтобы избежать этого, проверяйте входные значения и заранее задавайте поведение для пустого поля. Не рассчитывайте, что exit 1 заблокирует действие: для блокировки используйте предусмотренный для неё exit code.
# Шаблон безопасного начала и конца:
FILE=$(jq -r '.tool_input.file_path // empty')
[ -z "$FILE" ] && exit 0
# ... твоя логика ...
exit 0 # или || exit 0 в одну строку
Ошибка 2. Хук превышает таймаут
Если после редактирования запускать eslint --fix для большого файла, обработка может занять несколько секунд. В документации Claude Code указан стандартный таймаут хука в 60 секунд. При серии действий длительные проверки могут задержать работу и завершиться по таймауту.
Для тяжёлой фоновой задачи можно запустить команду с &, чтобы хук не ждал её завершения:
# Тяжёлая операция в background:
npx eslint --fix "$FILE" &
exit 0
Ошибка 3. Хук не получает переменные из окружения проекта автоматически
Хук запускается в shell-процессе Claude Code. Он видит переменные окружения, доступные этому процессу, но значения из .env проекта автоматически не появляются. Если команда зависит, например, от OPENAI_API_KEY из .env, файл нужно загрузить явно.
Решение: подключите .env в команде хука или используйте инструмент загрузки переменных окружения.
# Прокидывание env проекта в hook:
cd "$PWD" && source .env && curl -H "Authorization: Bearer $OPENAI_API_KEY" ...
# Или через dotenv:
dotenv -e .env -- node my-validator.js
В монорепозитории разные пакеты могут использовать отдельные .env. В таком случае укажите рабочую папку явно и выполните cd "$PWD" в начале команды.
Как проверить хуки до коммита?
Ключевой вывод
Хук можно запустить как обычную shell-команду: передать тестовый JSON через stdin и проверить exit code и stderr. Такая проверка помогает обнаружить ошибки до того, как команда будет запущена Claude Code.
Простейшая ручная проверка. Скопируйте команду из JSON, откройте терминал и передайте ей JSON, аналогичный входным данным Claude Code:
# Тест хука 1 (защита .env):
echo '{"tool_input":{"file_path":".env"}}' | bash -c '
FILE=$(jq -r ".tool_input.file_path // empty")
[ -z "$FILE" ] && exit 0
echo "$FILE" | grep -qE "(^|/)\.env(\.|$)" && {
echo "BLOCKED" >&2
exit 2
} || exit 0
'
echo "Exit code: $?"
Ожидаемый результат — BLOCKED в stderr и Exit code: 2. Если команда вернула exit 0, проверьте шаблон grep.
Проверьте три ситуации:
- Ожидаемая блокировка —
.envдля хука 1 иgit push --force mainдля хука 3. - Допустимое действие —
README.mdдля хука 1 иgit push origin feature-branchдля хука 3. - Граничные случаи — пустой ввод, null и неожиданные символы. Хук должен завершиться с подходящим кодом или выдать понятную ошибку, а не молча пропустить проблему.
Где проверять экспериментальные хуки. Для проб используйте .claude/settings.local.json, который не включается в Git. Например, временно добавьте в PostToolUse команду с echo, чтобы выяснить, срабатывает ли matcher, прежде чем включать настоящее действие в проектный settings.json.
// Эксперимент в settings.local.json - пишет в /tmp/hook-debug.log:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "echo \"[hook fired] $(date) $(jq -r '.tool_input.file_path // \"?\"')\" >> /tmp/hook-debug.log"
}
]
}
]
}
}
После нескольких правок проверьте /tmp/hook-debug.log. В нём должны появиться файлы, для которых сработал хук. Если журнал пуст, проверьте matcher и настройки события.
Что делать дальше?
Ключевой вывод
Начните с PostToolUse и exit 0: такие хуки выполняют действие после инструмента, не блокируя его. Позже добавьте PreToolUse и exit 2 для ограничений вроде защиты .env или запрета force-push. По мере переноса проверяемых ограничений в хуки CLAUDE.md можно оставить для описания контекста проекта.
На ближайшую неделю можно запланировать пять шагов:
- Просмотрите
CLAUDE.mdи найдите слова «никогда», «запрещено», «всегда» и «обязательно». Такие формулировки могут указывать на правила, которые стоит проверять автоматически. - Начните с
PostToolUseи exit 0. Это более мягкий вариант: он выполняет действие после инструмента и не блокирует его. Примеры — prettier (хук 2), освобождение порта (хук 5) и коммит после тестов (хук 6). - Добавляйте
PreToolUseс exit 2, когда готовы проверять блокировки. Например, можно запретить изменение.env(хук 1) или force-push (хук 3). Перед использованием тщательно проверьте grep: ошибочное условие может остановить допустимое действие. - Проверяйте команды вручную перед коммитом, как описано выше. Это помогает находить ошибки до запуска через Claude Code.
- Используйте
settings.local.jsonдля экспериментов. На первых этапах замените настоящее действие командойecho.
После настройки хуков можно прочитать, как откатить изменения в Claude Code, если проверка пропустила нежелательное изменение. Для работы с контекстом проекта между сессиями см. Второй мозг в Claude Code. Переиспользуемые инструкции проекта описаны в гайде Claude Code Skills.
Источники
Если вам нужен доступ к нейросетям через Ailoot, ознакомьтесь с Ailoot.
Подробнее
Вопросы и ответы
Почему hook должен прочитать входной JSON только один раз?
Stdin — поток: первый jq потребляет его, следующие получают EOF. Сохраните вход и извлекайте поля команды и результата из копии. Неизвестный или отсутствующий результат непроверен: автокоммит нужно пропустить.
Создают ли regex-примеры hooks границу безопасности?
Нет. Они проверяют отдельные события и узнаваемые строки. Перенаправления оболочки, алиасы, скрипты, MCP и другой путь записи могут обойти их. Для жёстких пределов нужны права файлов, ограниченные ключи, sandbox и защищённые ветки.