Тема: Часть 17. Хуки Qwen Code: автоматизация рабочего процесса
Уровень сложности: Средний
Расчётное время изучения: 4-6 часов (теория: 1.5 часа, практика: 2.5-4.5 часа)
Предварительные требования: Базовое понимание архитектуры Qwen Code и работы сессий
Знание JSON-формата и умение редактировать конфигурационные файлы
Навыки программирования на Python (уровень написания скриптов)
Понимание концепции SDD (Specification-Driven Development) из предыдущих частей курса
Опыт работы с командной строкой и базовыми командами shell
Знакомство с файлами QWEN.md, specs/mission.md, specs/tech-stack.md, specs/roadmap.md
Цели обучения: Настроить и подключить минимальный набор хуков (PreToolUse, PostToolUse, SessionStart, UserPromptSubmit) в учебном проекте согласно примерам курса
Различать ситуации, когда хук уместен, и когда правило достаточно записать в QWEN.md или validation.md
Реализовать защитный хук для блокировки опасных команд с понятным объяснением причины остановки
Организовать журналирование событий инструментов в формате JSONL с асинхронным режимом работы
Применить правила безопасности при работе с хуками: ревью кода, таймауты, изоляция секретов, проверка доверенных директорий
Обзор: Хуки Qwen Code — это механизм автоматизации рабочего процесса, позволяющий запускать сценарии в ключевые моменты сессии: при старте, после запроса пользователя, перед и после использования инструмента, при ошибке или перед завершением ответа. В контексте SDD хуки не заменяют спецификации, а делают процесс менее зависимым от человеческой памяти: напоминают правила, фиксируют события, блокируют опасные действия, добавляют короткий контекст и собирают следы для ретроспективы. Ключевой принцип: хук должен быть маленьким, понятным и решать одну задачу. Если нельзя объяснить его назначение одной фразой — он делает слишком много. Курс охватывает три основных типа хуков (command, http, function), шесть ключевых событий, практику подключения примеров и критически важные правила безопасности.
Ключевые концепции: Событие (event): Триггер, активирующий хук. Ключевые события: SessionStart (старт сессии), UserPromptSubmit (после запроса пользователя), PreToolUse (перед использованием инструмента), PostToolUse (после успешного использования), PostToolUseFailure (после ошибки инструмента), Stop (перед завершением ответа), PreCompact (перед сжатием контекста). Каждое событие имеет свою семантику в SDD-процессе.
Фильтр matcher: Компонент, определяющий, должен ли хук сработать для конкретного события. Позволяет прицельно настраивать хуки: например, PreToolUse только для инструмента Bash, а не для всех инструментов.
Исполнитель хука (command/http/function): Тип запускаемого сценария. Command — локальная команда (Python-скрипт, shell-скрипт), основной вариант для проектов. HTTP — отправка на внешний адрес для централизованного журналирования. Function — внутренняя JS-функция сессии, редко нужна в обычных проектах.
Входной json хука: Данные, передаваемые хуку через stdin: идентификатор сессии, текущая директория, имя события, время, для инструментов — имя инструмента, входные данные, результат или ошибка.
Выходной json хука: Результат работы хука через stdout. Три ключевых варианта: пустой ответ (ничего не меняет), additionalContext (добавляет короткое сообщение в контекст), блокировка действия с объяснением причины.
Код завершения хука: 0 — успешная работа, 2 — блокирующая ошибка (останавливает действие), другие коды — неблокирующая ошибка (видна в отладке, но процесс продолжается).
Асинхронный режим: Режим, при котором хук не блокирует основной ход работы Qwen Code. Критически важен для журналирования и фоновых проверок, чтобы сессия не ждала завершения побочной задачи.
Защитный хук (pretooluse guard): Хук, блокирующий опасные действия перед их выполнением. Примеры опасных шаблонов: rm -rf / или ~, git reset --hard, git clean -fd, запуск скачанных скриптов через sh. Не заменяет песочницу, но служит последней проверкой.
Журналирование инструментов (posttooluse/posttoolusefailure): Фиксация фактов использования инструментов для последующей ретроспективы: частота падений, изменённые файлы, ручные проверки, кандидаты для переноса в validation.md или QWEN.md.
Инъекция sdd-контекста: Добавление короткой памятки о проекте через SessionStart и UserPromptSubmit, особенно после /clear. Хук проверяет наличие ключевых файлов (QWEN.md, specs/mission.md и др.) и направляет агента к источнику истины, не дублируя его содержимое.
Timeout хука: Максимальное время выполнения хука, предотвращающее блокировку сессии зависшим скриптом.
Правила безопасности хуков: Хуки выполняются с правами пользователя в его среде. Требования: ревью кода хуков, таймауты, асинхронный режим для фоновых задач, изоляция секретов, явный список разрешённых переменных для HTTP, запрет молчаливого изменения файлов, понятные сообщения при блокировке, проверка доверенности директории перед автозапуском.
Практические упражнения: Название: Установка и базовое подключение хуков
Проблема: Скопируйте примеры хуков из репозитория курса в учебный проект, настройте права на выполнение и подключите settings-hooks.example.json без перезаписи существующих настроек модели, авторизации и MCP-серверов.
Решение: 1. Создайте директорию: mkdir -p .qwen/hooks
- Скопируйте три хука: cp sdd-qwen-code-ru/examples/hooks/pre_tool_guard.py .qwen/hooks/; cp sdd-qwen-code-ru/examples/hooks/log_tool_result.py .qwen/hooks/; cp sdd-qwen-code-ru/examples/hooks/inject_sdd_context.py .qwen/hooks/
- Установите права на выполнение: chmod +x .qwen/hooks/*.py
- Скопируйте пример настроек отдельно: cp sdd-qwen-code-ru/examples/hooks/settings-workflow.example.json .qwen/settings-hooks.example.json
- Вручную объедините содержимое settings-hooks.example.json с существующим .qwen/settings.json, сохранив секции model, auth, mcp
- Проверьте валидность JSON: python -m json.tool .qwen/settings.json
Сложность: beginner
Название: Настройка защитного хука для Bash
Проблема: Подключите pre_tool_guard.py только к событию PreToolUse для инструмента Bash. Проверьте работу на безопасной тестовой команде, содержащей опасный шаблон (например, git reset --hard в тестовом репозитории). Убедитесь, что хук объясняет причину блокировки, а не просто запрещает.
Решение: 1. В .qwen/settings.json добавьте в секцию hooks запись с matcher: {"event": "PreToolUse", "tool": "Bash"}, исполнитель: {"type": "command", "command": ".qwen/hooks/pre_tool_guard.py"}
- Создайте тестовый git-репозиторий: mkdir /tmp/test-guard && cd /tmp/test-guard && git init && echo 'test' > file.txt && git add . && git commit -m 'init'
- В Qwen Code попробуйте выполнить через Bash: git reset --hard HEAD~
- Проверьте, что хук вернул код 2, Qwen Code показал причину остановки с объяснением конкретного опасного шаблона
- Попробуйте безопасную альтернативу: git log --oneline -5 и убедитесь, что она проходит
- Проверьте, что другие инструменты (Read, Edit) не затронуты хуком
Сложность: intermediate
Название: Журналирование с асинхронным режимом
Проблема: Подключите log_tool_result.py к событиям PostToolUse и PostToolUseFailure. Настройте асинхронный режим, чтобы журналирование не замедляло сессию. Выполните несколько операций с инструментами и проанализируйте полученный журнал.
Решение: 1. Добавьте два хука в settings.json с одинаковым исполнителем, но разными событиями: PostToolUse и PostToolUseFailure, command: .qwen/hooks/log_tool_result.py
- Установите "async": true для обоих хуков
- Запустите Qwen Code, выполните /clear, попросите агента прочитать roadmap и предложить следующую фичу
- Проверьте создание журнала: ls -la .qwen/hooks/logs/tool-events.jsonl
- Проанализируйте записи: jq . .qwen/hooks/logs/tool-events.jsonl | head -20
- Убедитесь, что записи компактные: содержат event_type, tool_name, timestamp, success/failure, но не полные дампы окружения и не секреты
- Проверьте, что при ошибке инструмента (например, чтение несуществующего файла) запись отличается от успешной
Сложность: intermediate
Название: Инъекция контекста после /clear
Проблема: Подключите inject_sdd_context.py к SessionStart и UserPromptSubmit. Проверьте, что после команды /clear агент получает короткую памятку о ключевых файлах проекта, но не полные тексты спецификаций.
Решение: 1. Добавьте хуки в settings.json для SessionStart и UserPromptSubmit с командой .qwen/hooks/inject_sdd_context.py
- Убедитесь, что в проекте есть хотя бы QWEN.md и specs/mission.md
- Запустите сессию, выполните /clear
- В следующем запросе спросите: «Какие спецификации есть в проекте?»
- Проверьте, что агент упоминает наличие файлов, но не цитирует их содержимое полностью
- Проверьте логи хука или вывод additionalContext в отладочном режиме Qwen Code
- Убедитесь, что при отсутствии specs/roadmap.md хук корректно обрабатывает ситуацию, не падает и не добавляет лишнего
Сложность: intermediate
Название: Анализ и рефакторинг хуков после практики
Проблема: После выполнения упражнений 1-4 ответьте письменно на четыре вопроса: какой хук реально помог процессу; какой оказался шумным; что лучше перенести в QWEN.md; что лучше оставить ручным шагом в validation.md. На основе ответов скорректируйте конфигурацию.
Решение: 1. Ведите заметки во время выполнения упражнений: фиксируйте моменты, когда хук сработал полезно, и когда создал помеху
- Пример полезного срабатывания: pre_tool_guard предотвратил git reset --hard — оставить
- Пример шума: inject_sdd_context срабатывает при каждом UserPromptSubmit и дублирует информацию из QWEN.md — рассмотреть перенос правила «сначала читай QWEN.md» в сам QWEN.md, оставив хук только для SessionStart
- Пример для QWEN.md: «После /clear обращай внимание на specs/roadmap.md» — это правило поведения, не требующее автоматизации
- Пример для validation.md: «Запустить npm test перед коммитом» — тяжёлая проверка, не подходящая для хука
- Скорректируйте settings.json, удалите или измените хуки на основе анализа, задокументируйте решение в комментарии к коммиту
Сложность: advanced
Кейсы: Название: Защита production-базы данных от случайного удаления
Сценарий: Команда из пяти разработчиков использует Qwen Code для работы с микросервисной архитектурой на Node.js. Проект содержит Docker-контейнеры с production-подобными данными для локального тестирования. Разработчик случайно попросил агента выполнить docker volume prune во время отладки, что привело бы к удалённым томам с тестовыми данными, восстановление которых занимало 2-3 часа.
Задача: Правила в QWEN.md не предотвращали опасные команды в моменте: разработчик в состоянии потока мог не заметить предупреждение. Ручная проверка каждой команды Bash агентом была ненадёжной. Необходимо было автоматическое, но объяснимое препятствие на пути разрушительных операций без замедления обычной работы.
Решение: Команда внедрила защитный хук pre_tool_guard.py, расширив его шаблоны: добавили docker volume prune, docker system prune -a, rm в директориях с .env файлами, любые команды с DROP DATABASE. Хук настроен только на PreToolUse + Bash. При блокировке хук возвращает JSON с объяснением: «Команда docker volume prune удалит все неиспользуемые Docker-тома, включая тома с тестовыми данными проекта X. Для безопасной очистки используйте docker volume rm с конкретным именем тома или подтвердите через validation.md шаг 'Ручная очистка Docker-ресурсов'.» Разработчик видит причину и может выбрать безопасный путь.
Результат: За три месяца хук заблокировал 12 потенциально разрушительных команд. В 10 случаях разработчики выбрали безопасную альтернативу. В 2 случаях осознанно прошли через validation.md. Время восстановления тестовых данных сократилось с 2-3 часов до нуля. Хук стал частью onboarding-чеклиста новых разработчиков.
Извлечённые уроки: Блокировка без объяснения провоцирует попытки обхода; конкретная причина направляет к безопасному решению
Хук должен быть узкоспециализированным: защита Docker-команд не мешает обычной работе с git и файлами
Интеграция хука с validation.md создаёт связь между автоматической и ручной проверкой, не ломая процесс
Связанные концепции: Защитный хук (PreToolUse guard)
Код завершения хука
Выходной JSON хука с объяснением причины
Связь хуков с validation.md
Название: Переизбыток хуков и возврат к простоте
Сценарий: Команда из трёх человек энтузиастично внедрила хуки во все доступные события: SessionStart, UserPromptSubmit, PreToolUse, PostToolUse, PostToolUseFailure, Stop, PreCompact. Каждый хук выполнял 3-4 задачи: журналирование, проверку, добавление контекста, форматирование. Сессии Qwen Code стали занимать в 2.5 раза больше времени, агент начал игнорировать часть контекста из-за перегрузки, разработчики перестали понимать, откуда берётся та или иная реакция системы.
Задача: Классическая ловушка автоматизации: хуки перестали быть прозрачными инструментами и превратились в скрытую логику. Команда не могла объяснить поведение сессии одной фразой. Отладка требовала трассировки 7 хуков, многие из которых конфликтовали: один добавлял контекст, другой его модифицировал, третий записывал в журнал уже изменённую версию.
Решение: Команда провела аудит по принципу «одна фраза — один хук». Для каждого хука задала вопрос: «Что он делает одной фразой?» Хуки, не прошедшие проверку, были разделены или удалены. Итоговая конфигурация: SessionStart + inject_sdd_context (напомнить о проекте после /clear), PreToolUse + pre_tool_guard только для Bash (остановить опасное), PostToolUseFailure + log_tool_result async (сохранить ошибку для ретроспективы). Всё остальное перенесли в QWEN.md или validation.md.
Результат: Время сессии вернулось к исходному. Прозрачность восстановлена: любой разработчик мог объяснить поведение за 30 секунд. Журнал ошибок стал чистым и полезным для еженедельной ретроспективы. Правило «не больше трёх хуков на проект» вошло в командные гайдлайны.
Извлечённые уроки: Хук должен решать одну задачу и объясняться одной фразой; иначе он становится техническим долгом
Начинать с одного-двух хуков, а не подключать всё сразу — иначе процесс непрозрачен
Журналирование, проверка, форматирование и безопасность не должны смешиваться в одном скрипте
Связанные концепции: Правило «одна фраза — один хук»
Асинхронный режим
Что не стоит автоматизировать
Связь хуков с QWEN.md и validation.md
Советы по изучению: Начинайте практику строго с одного хука — лучше PreToolUse guard, так как его польза наглядна и риски понятны. Добавляйте остальные только после осмысленного анализа первого.
Ведите «дневник хуков» во время практики: фиксируйте каждое срабатывание, время реакции, была ли польза или шум. Это облегчит финальное упражнение по рефакторингу.
Используйте jq или python -m json.tool для чтения журнала tool-events.jsonl — формат JSONL специально выбран для построчной обработки, не пытайтесь читать его как обычный JSON-массив.
Создайте тестовую «песочницу» для проверки защитного хука: отдельный git-репозиторий, Docker-тома с ненужными данными, временные файлы. Никогда не проверяйте блокировку rm -rf / на реальной системе.
Сравнивайте поведение хука в синхронном и асинхронном режиме: запустите log_tool_result.py сначала без async, замерьте задержку между инструментами, затем включите async и сравните. Это визуализирует критическую разницу.
Для визуального типа обучения нарисуйте на бумаге схему из курса (событие → matcher → хук → решение → продолжение/остановка/контекст) и отметьте, какие пути проходят ваши настроенные хуки.
Для аудиального типа: проговаривайте вслух назначение каждого хука одной фразой перед его добавлением в settings.json. Если фраза получается длинной или с союзами «и», разделите хук.
Регулярно перечитывайте раздел «Что не стоит автоматизировать» — это чек-лист самопроверки перед каждым новым хуком.
Практикуйте ручное объединение settings.json: это навык, который пригодится при обновлениях курса и при работе с чужими репозиториями, где хуки могут быть скрытой угрозой.
Обсудите с коллегами или в учебной группе: какие команды в вашем стеке считаются «опасными»? Список отличается для Python (pip install неизвестного пакета), Node.js (npm audit fix --force), Go (go get с подменой модуля), DevOps (kubectl delete, terraform destroy).
Дополнительные ресурсы: Репозиторий примеров курса (sdd-qwen-code-ru/examples/hooks/): Исходные файлы pre_tool_guard.py, log_tool_result.py, inject_sdd_context.py, settings-workflow.example.json и README.md — основа всех практических упражнений
Официальная документация qwen code по хукам: Расширенное описание событий, типов исполнителей, форматов JSON (проверять актуальность версии)
Jq — командный процессор json: https://jqlang.github.io/jq/ — инструмент для анализа JSONL-журналов в терминале
Python json.tool: Встроенный модуль для валидации и форматирования JSON: python -m json.tool файл.json
Статья «the twelve-factor app» (раздел config): Принципы хранения конфигурации и секретов, применимые к настройке HTTP-хуков и переменных окружения
Owasp cheat sheet: injection prevention: Рекомендации по предотвращению инъекций, релевантные для обработки входных данных хуков и безопасного построения команд
Предыдущие части курса (qwen.md, specs/, validation.md): Контекст SDD, необходимый для правильного разграничения хуков и спецификаций
Резюме: Хуки Qwen Code — мощный, но требующий дисциплины инструмент автоматизации SDD-процесса. Их цель — снизить зависимость от человеческой памяти, а не заменить спецификации. Ключевые принципы: начинать с 1-2 хуков, каждый хук решает одну задачу и объясняется одной фразой, защитные хуки объясняют причину блокировки, журналирование работает асинхронно, проверки разделяются по весу (лёгкие — автоматически, тяжёлые — через validation.md). Безопасность хуков критична: они выполняются с правами пользователя, требуют ревью, таймаутов, изоляции секретов и осторожности при работе с чужими репозиториями. После освоения хуков студент готов к изучению безопасности хуков и SQLite-памяти в следующих частях курса.