Зачем это нужно
В предыдущем модуле мы построили orchestration для multi-agent workflow:
Planner
-> Task DAG
-> Agents
-> Integration
-> Reviewer
-> CI
-> Human approval
Эта схема работает лучше, чем "пусть агенты сами разберутся", но в ней остается важный вопрос:
Какие проверки мы оставляем на память агента,
а какие выносим в автоматическое выполнение?
Плохой вариант:
Пожалуйста, не забудь после каждого изменения запускать formatter.
Пожалуйста, не забудь перед commit запускать tests.
Пожалуйста, не забудь перед deploy проверить secrets.
LLM может забыть. Может решить, что проверка "не нужна в этот раз". Может написать убедительный summary без фактического запуска команды. Может остановиться из-за context pressure. Может перепутать project commands.
Hook решает другую задачу:
Когда произошло событие X,
автоматически выполни действие Y
и останови workflow, если результат небезопасен.
Примеры:
AfterEdit
-> formatter
BeforeCommit
-> lint
-> typecheck
-> tests
BeforeDeploy
-> security check
-> migration check
-> human approval
Главная мысль урока:
То, что можно надежно проверить или выполнить программно,
не должно жить только как просьба в prompt.
Основная идея
Hook - это автоматическое действие, привязанное к событию workflow.
Формула:
Event
-> Hook command
-> Exit status / evidence
-> Continue, fix, stop or ask approval
Например:
Agent edited TypeScript file
-> run formatter on changed file
-> if formatting succeeds, continue
-> if formatting fails, stop and show error
Или:
Agent wants to commit
-> run scripts/verify
-> if green, commit allowed
-> if red, task returns to fix/verification
Hook важен не потому, что он "умнее" агента. Он важен потому, что он:
- deterministic;
- повторяемый;
- наблюдаемый;
- работает одинаково для человека и агента;
- возвращает exit code;
- может остановить workflow;
- не зависит от того, помнит ли LLM инструкцию.
Prompt остается полезным:
Перед commit запусти scripts/verify.
Но hook делает правило enforceable:
Commit не проходит, если scripts/verify failed.
Ключевые термины
| Термин | Значение |
|---|---|
| Hook | Автоматическое действие, которое запускается при определенном событии workflow. |
| Trigger | Событие, которое запускает hook: edit, commit, push, deploy, tool call, file change. |
| Action | Команда или script, который hook выполняет. |
| Exit code | Машинно-читаемый результат команды: 0 обычно success, non-zero failure. |
| Deterministic automation | Проверка или действие, которое выполняется программно и повторяемо. |
| AfterEdit | Hook после изменения файлов. Часто запускает formatter или lightweight checks. |
| BeforeCommit | Hook перед commit. Часто запускает lint, typecheck, tests, secret scan. |
| BeforeDeploy | Hook перед deploy. Часто запускает security checks, migration checks, smoke tests, approval. |
| Fail closed | При failure workflow останавливается. Безопасный default для critical checks. |
| Fail open | При failure workflow продолжает работу с warning. Использовать осторожно. |
| Idempotent | Повторный запуск hook не ломает состояние и не создает лишних изменений. |
scripts/verify |
Единая команда в репозитории, которая запускает стандартные проверки проекта. |
| Hook evidence | Короткое подтверждение: какая команда запущена, что passed/failed, что не запускалось. |
| Routing decision | Что делать после hook result: continue, fix, retry, block, ask approval. |
Hook В Agent Workflow
Без hooks agent workflow часто выглядит так:
С hooks:
Важное изменение:
Проверка больше не является частью хорошего поведения агента.
Проверка становится частью среды выполнения.
Это особенно важно в AI-assisted development, потому что агент может быстро писать код, но не всегда стабильно поддерживает operational discipline. Hooks добавляют внешнюю опору.
Hook Vs Prompt Instruction
Prompt instruction говорит агенту, что делать.
Hook делает действие частью workflow.
| Правило | Prompt instruction | Hook |
|---|---|---|
| Format after edit | "Не забудь запустить formatter." | Formatter запускается после изменения файла. |
| Test before commit | "Перед commit запусти tests." | Commit blocked, если tests failed. |
| Do not commit secrets | "Не добавляй secrets." | Secret scan blocks commit. |
| Validate docs links | "Проверь ссылки." | Link checker runs in verify. |
| No direct deploy | "Не deploy без approval." | Deploy command требует approval gate. |
Prompt instruction слабее, потому что:
- зависит от внимания модели;
- может конфликтовать с другими instructions;
- может быть пропущена при длинной задаче;
- может быть выполнена частично;
- может превратиться в unsupported claim.
Hook сильнее, потому что:
- запускается по событию;
- имеет machine-readable result;
- может остановить действие;
- дает одинаковый результат для агента, человека и CI;
- оставляет evidence.
Но hook не заменяет prompt полностью. Prompt объясняет intent и поведение:
If BeforeCommit fails, inspect the output, fix the root cause,
rerun the same command, and report failed/not-run checks explicitly.
Hook обеспечивает execution. Prompt объясняет, как агент должен реагировать.
Hook Vs Test Vs CI Vs Guardrail
Эти механизмы пересекаются, но не совпадают.
| Механизм | Что делает | Пример |
|---|---|---|
| Hook | Запускает действие при событии workflow. | BeforeCommit запускает scripts/verify. |
| Test | Проверяет поведение кода. | Unit test проверяет password reset token expiry. |
| CI | Запускает checks в центральной среде. | Pull request build, lint, tests. |
| Guardrail | Ограничивает действие или требует gate. | Нельзя push в main, нельзя deploy без approval. |
| Prompt rule | Инструктирует агента. | "Не меняй unrelated files." |
Hook может запускать tests. CI может запускать тот же scripts/verify. Guardrail может требовать, чтобы CI был green. Prompt может сказать агенту, как читать failures.
Практичная связка:
Prompt rule:
Before finishing, provide verification evidence.
Hook:
BeforeCommit runs scripts/verify.
CI:
Pull request runs scripts/verify in clean environment.
Guardrail:
Merge blocked unless CI is green.
В следующем уроке мы подробнее разберем guardrails. Сейчас важно увидеть роль hooks: они запускают automation в нужный момент.
Anatomy Of A Hook
У hook есть несколько обязательных частей.
Name:
BeforeCommit
Trigger:
user or agent attempts commit
Action:
./scripts/verify
Inputs:
current working tree, changed files, environment variables
Output:
command output, logs, summary
Decision:
exit 0 -> continue
exit non-zero -> stop and route to fix
Минимальный hook contract:
| Поле | Вопрос |
|---|---|
| Event | Когда hook запускается? |
| Scope | На какие файлы или действия он реагирует? |
| Command | Что именно выполняется? |
| Runtime | Где выполняется: local, CI, agent environment? |
| Timeout | Сколько времени допустимо? |
| Failure behavior | Что происходит при non-zero exit? |
| Evidence | Как результат попадает в handoff/report? |
| Owner | Кто чинит hook, если он сломан? |
Если hook не имеет clear failure behavior, он быстро превращается в шум.
AfterEdit Hooks
AfterEdit hook запускается после изменения файлов.
Типичные задачи:
- formatter;
- import organizer;
- generated index refresh;
- lightweight static check;
- markdown table formatting;
- docs TOC refresh;
- file-level lint;
- schema/codegen refresh для конкретного файла.
Пример:
Event:
Agent edited `*.ts` or `*.tsx`
Action:
Run formatter on changed files.
Failure:
Stop and show formatter output.
Do not continue to larger tests until formatting problem is resolved.
AfterEdit hook должен быть быстрым. Если он занимает минуты, агент будет получать slow feedback после каждого небольшого изменения и начнет обходить hook.
Хорошие AfterEdit checks:
| Hook | Почему подходит |
|---|---|
| Format changed file | Быстро, deterministic, idempotent. |
| Sort imports | Быстро, локально, уменьшает diff noise. |
| Markdown formatting | Быстро, предотвращает мелкие style issues. |
| Regenerate local schema types | Подходит, если четко привязано к измененному schema file. |
Плохие AfterEdit checks:
| Hook | Почему плохо |
|---|---|
| Full test suite after every edit | Слишком дорого, мешает iteration. |
| Production deploy after config edit | Рискованно, требует approval. |
| Automatic dependency upgrade | Меняет scope без решения человека. |
| Large semantic rewrite | Hook начинает делать implementation вместо проверки. |
Принцип:
AfterEdit should reduce mechanical friction,
not make product decisions.
BeforeCommit Hooks
BeforeCommit hook запускается перед созданием commit.
Его задача:
Не дать непроверенному diff попасть в историю.
Типичные checks:
- formatting check;
- lint;
- typecheck;
- unit tests;
- targeted integration tests;
- docs build;
- secret scan;
- generated files up to date;
- lockfile consistency;
- no conflict markers;
- no accidental debug statements;
- no large unrelated artifacts.
Пример policy:
BeforeCommit:
1. Run formatter check.
2. Run lint.
3. Run typecheck.
4. Run tests relevant to changed files.
5. Run secret scan.
6. Block commit if any required check fails.
BeforeCommit не обязан всегда запускать everything. В больших репозиториях это может быть слишком дорого. Но он должен запускать minimal reliable checks, которые защищают от очевидно плохого diff.
Практичная схема:
| Размер проекта | BeforeCommit |
|---|---|
| Маленький repo | Full scripts/verify. |
| Средний repo | Format/lint/typecheck + targeted tests. |
| Большой repo | Fast local checks + changed-file tests + CI for full suite. |
| Safety-critical area | Required targeted tests + security checks + approval. |
В AI Agent Development BeforeCommit особенно важен, потому что агент может сделать много маленьких изменений быстро. Hook заставляет каждое законченное изменение пройти одинаковый minimum bar.
BeforeDeploy Hooks
BeforeDeploy hook запускается перед release или deploy.
Это более строгий stage, чем BeforeCommit, потому что последствия выходят за пределы локального repo.
Типичные checks:
- full test suite;
- build;
- smoke tests;
- migration dry run;
- secret/config validation;
- dependency vulnerability scan;
- permissions check;
- environment check;
- rollback plan check;
- human approval.
Пример:
BeforeDeploy:
1. Ensure current commit passed CI.
2. Check migrations are backward-compatible or approved.
3. Run smoke tests against staging.
4. Verify secrets/config are present and not printed.
5. Require human approval for production deploy.
BeforeDeploy должен быть fail closed для risky operations.
If security check fails, do not deploy.
If migration check is inconclusive, ask human approval.
If staging smoke test fails, stop release.
Плохая практика:
Agent says: "Deploy should be fine because tests passed locally."
Локальные tests не являются deploy approval.
scripts/verify Как Единая Точка Проверки
В плане курса итоговым artifact модуля указан scripts/verify. Это важная идея.
Вместо того чтобы каждый agent вспоминал набор команд:
npm run lint
npm run typecheck
npm test
npm run build
репозиторий дает одну команду:
./scripts/verify
Она становится единым контрактом:
Если хочешь заявить, что change verified,
покажи результат scripts/verify или объясни, почему он не запускался.
scripts/verify может быть простым:
#!/usr/bin/env bash
set -euo pipefail
npm run lint
npm run typecheck
npm test
Или чуть более структурированным:
#!/usr/bin/env bash
set -euo pipefail
echo "[verify] format"
npm run format:check
echo "[verify] lint"
npm run lint
echo "[verify] typecheck"
npm run typecheck
echo "[verify] tests"
npm test
В больших проектах scripts/verify может принимать режим:
./scripts/verify --fast
./scripts/verify --changed
./scripts/verify --full
./scripts/verify --security
Но даже тогда нужен default:
./scripts/verify
Default должен быть понятен агенту и человеку.
Почему Единая Команда Важна Для Агентов
Агенту трудно надежно удерживать в context project-specific набор проверок, особенно если:
- repo polyglot;
- есть frontend и backend;
- tests лежат в нескольких директориях;
- commands отличаются для local и CI;
- часть проверок optional;
- есть generated files;
- есть линтеры, formatters, schema checks;
- команда менялась со временем.
scripts/verify снижает cognitive load:
Agent does not need to rediscover the verification protocol.
The repo exposes it as executable interface.
Это похоже на public API:
Input:
current repo state
Command:
./scripts/verify
Output:
pass/fail + logs
В идеале scripts/verify используется в трех местах:
Local developer
-> ./scripts/verify
Agent BeforeCommit hook
-> ./scripts/verify
CI
-> ./scripts/verify
Так local, agent и CI говорят на одном языке.
Hook Placement В Development Loop
Вспомним development loop:
Understand task
-> Plan
-> Write tests
-> Implement
-> Verify
-> Review
-> Commit
Hooks добавляются вокруг repeatable checkpoints:
Hook не должен заменять thinking stages:
- он не решает, что строить;
- он не выбирает architecture;
- он не проверяет все product assumptions;
- он не делает independent review;
- он не принимает risk decisions.
Hook усиливает mechanics:
- запускает повторяемые команды;
- ловит очевидные нарушения;
- создает early feedback;
- фиксирует evidence;
- переводит workflow в failed state, если нужно.
Hooks И Orchestration Gates
В уроке 11.4 мы говорили про gates:
Spec Gate
Plan Gate
Contract Gate
Verification Gate
Integration Gate
Review Gate
CI Gate
Human Approval Gate
Hook может реализовать часть gate.
| Gate | Что может сделать hook | Что не должен делать hook |
|---|---|---|
| Verification Gate | Запустить tests/lint/typecheck. | Решать, соответствует ли feature продуктовой цели. |
| Integration Gate | Запустить full verify после merge. | Молча менять contract. |
| Review Gate | Подготовить review packet. | Заменять independent reviewer. |
| CI Gate | Запустить checks в clean env. | Игнорировать failed checks. |
| Human Approval Gate | Остановить workflow и запросить approval. | Самостоятельно принимать risky decision. |
Важно:
Hook can enforce mechanics.
Human/reviewer still handles judgment.
Например, secret scan может заблокировать commit. Но решение "это false positive или реальный secret" может требовать человека.
Failure Behavior
Hook без понятного failure behavior раздражает. Hook с понятным failure behavior улучшает процесс.
Минимальная политика:
If hook fails:
1. Stop the current transition.
2. Preserve output.
3. Identify failing command.
4. Route to fix, retry, block or approval.
5. Do not claim success.
Таблица решений:
| Failure | Routing |
|---|---|
| Formatter changed files | Inspect diff, continue if only mechanical. |
| Formatter failed | Fix syntax/config issue, rerun. |
| Lint failed | Fix lint issue or justify suppression. |
| Typecheck failed | Fix implementation or contract mismatch. |
| Unit tests failed | Fix code or test, rerun same tests. |
| Secret scan failed | Stop, remove secret, rotate if leaked. |
| Security check inconclusive | Ask human/security approval. |
| Deploy smoke test failed | Stop deploy, investigate staging/prod mismatch. |
| Hook infrastructure broken | Mark blocked, do not pretend verification passed. |
Agent response to hook failure should not be:
The hook probably failed because of environment issues, continuing.
Better:
BeforeCommit failed on `npm run typecheck`.
I will inspect the TypeScript error, fix the root cause,
rerun `./scripts/verify`, and report whether it passes.
Fail Closed И Fail Open
Fail closed:
If check fails, stop workflow.
Fail open:
If check fails, continue with warning.
Для agent workflow default должен быть conservative.
| Check | Рекомендуемое поведение |
|---|---|
| Formatter | Обычно fail closed before commit, auto-fix after edit. |
| Lint | Fail closed before commit. |
| Typecheck | Fail closed before commit. |
| Unit tests | Fail closed before commit или before merge. |
| Secret scan | Fail closed. |
| Security check before deploy | Fail closed or human approval required. |
| Docs link checker | Может быть fail open locally, fail closed in CI для docs release. |
| Slow flaky integration test | Отдельная policy: quarantine, rerun, owner, not silent pass. |
Fail open опасен, если агент начинает использовать warning как permission.
Плохой pattern:
The check failed, but it is probably fine.
Хороший pattern:
The check failed.
This transition is blocked unless the project policy allows override.
Override requires human approval and documented reason.
Hook Design Principles
Хороший hook:
- deterministic;
- idempotent;
- fast enough for its stage;
- scoped;
- has clear exit codes;
- prints actionable output;
- avoids destructive side effects;
- works locally and in CI;
- has documented failure behavior;
- is easy to run manually;
- is versioned in the repo;
- does not depend on hidden local state;
- does not require broad permissions without reason.
Плохой hook:
- иногда pass, иногда fail без причины;
- делает large rewrite;
- скрывает output;
- требует секреты для обычной локальной проверки;
- долго работает на каждом edit;
- меняет unrelated files;
- автоматически deploy'ит;
- обновляет dependencies;
- чинит tests путем их ослабления;
- имеет неясный owner.
Короткая формула:
Hooks should make the safe path easy
and the unsafe path explicit.
Что Можно Автоматизировать Hook'ом
Хорошие candidates:
| Candidate | Почему подходит |
|---|---|
| Formatting | Deterministic, fast, low judgment. |
| Import sorting | Mechanical, idempotent. |
| Lint | Static, repeatable. |
| Typecheck | Deterministic для большинства проектов. |
| Unit tests | Проверяют behavior, хорошо подходят before commit/CI. |
| Secret scan | High value, deterministic enough. |
| Conflict marker check | Cheap and important. |
| Generated files check | Ловит забытый codegen. |
| Markdown lint | Полезно для docs/course repos. |
| Link check | Полезно перед docs release. |
| Dependency lockfile check | Ловит inconsistent installs. |
| Test coverage threshold | Подходит, если threshold осмысленный. |
С осторожностью:
| Candidate | Риск |
|---|---|
| Full e2e after every edit | Слишком медленно. |
| Vulnerability scan on every local commit | Может быть шумным и медленным. |
| Auto-fix lint with semantic changes | Может изменить behavior. |
| AI-generated review hook | Не deterministic, лучше как assistant, не gate. |
| Auto-migration | Риск data loss. |
| Auto-deploy | Риск production impact. |
Почти никогда не стоит:
- автоматически force push;
- автоматически удалять user data;
- автоматически менять billing/permissions;
- автоматически принимать security risk;
- автоматически изменять acceptance criteria;
- автоматически отключать tests.
Hooks Для Разных Типов Репозиториев
Node/TypeScript Web App
AfterEdit:
- format changed files;
- organize imports.
BeforeCommit:
- format check;
- lint;
- typecheck;
- unit tests;
- changed e2e tests if relevant;
- secret scan.
BeforeDeploy:
- build;
- full tests;
- migration check;
- staging smoke;
- approval.
Python Service
AfterEdit:
- formatter on changed `.py`;
- import sorting.
BeforeCommit:
- lint;
- typecheck if used;
- unit tests;
- contract tests;
- secret scan.
BeforeDeploy:
- full test suite;
- migration dry run;
- dependency audit;
- smoke tests.
Documentation / Course Repository
AfterEdit:
- markdown format;
- heading/style check if lightweight.
BeforeCommit:
- markdown lint;
- internal link check;
- code fence check;
- spell/terminology check if available.
BeforeRelease:
- docs build;
- link check;
- sample code verification.
AI Agent Workflow Repository
AfterEdit:
- format prompts/skills/docs;
- validate YAML/JSON config;
- regenerate prompt index.
BeforeCommit:
- prompt schema validation;
- skill metadata validation;
- eval smoke suite;
- scripts/verify;
- no secrets in examples.
BeforeDeploy:
- eval regression suite;
- tool permission diff review;
- approval for new external tools;
- rollout plan.
Hooks Для AI Agent Development
AI Agent Development имеет особые риски:
- prompt changes can silently change behavior;
- skill updates can alter agent procedures;
- tool permission changes can expand blast radius;
- evals may be skipped because they are slow;
- examples may include fake secrets;
- agent instructions can contradict project rules.
Hooks помогают сделать процесс стабильнее.
Примеры:
| Event | Hook | Purpose |
|---|---|---|
| Skill edited | Validate SKILL.md frontmatter and required sections. |
Не дать сломанному skill попасть в repo. |
| Prompt edited | Run prompt schema or snapshot tests. | Ловить broken placeholders and missing variables. |
| Tool config changed | Show permission diff. | Сделать blast radius visible. |
| Eval file changed | Run eval smoke suite. | Проверить, что evals still execute. |
| Agent policy changed | Run policy consistency check. | Найти contradictions between docs and prompts. |
| Before release | Run regression eval suite. | Поймать behavior drift. |
Пример hook policy для prompt/skill repo:
BeforeCommit:
- validate all YAML/JSON files;
- validate SKILL.md frontmatter;
- check prompts have required variables;
- run eval smoke suite;
- run markdown checks;
- scan examples for secrets.
Это не гарантирует, что агент стал лучше. Но это гарантирует, что obvious structural failures не попали в history.
Hook Evidence В Agent Report
Агент должен включать hook evidence в final report.
Плохой final report:
Сделал. Все проверил.
Хороший final report:
Changed:
- modules/module_12/lesson_12_01_hooks.md
Verification:
- `rg -n "UNFINISHED|DRAFT_MARKER|TEMP_MARKER"`: no matches
- code fence count: even
- `git diff --check`: passed
Not run:
- full course build, because repo has no build script.
Evidence не обязательно должна быть длинной. Она должна быть конкретной.
Для hooks это особенно важно:
Hook result should become part of the handoff.
Если hook failed и потом passed, report должен сказать:
BeforeCommit initially failed on markdown lint.
Fixed heading spacing.
Reran `./scripts/verify`: passed.
Так reviewer видит процесс, а не только итоговую уверенность.
Hooks И Skills
В модуле 6 мы обсуждали skills. Skill может сказать агенту:
When editing API endpoints, run the API verification script.
Это полезно, но это still prompt-level instruction.
Если проверка критична и повторяема, лучше вынести ее в hook или script:
skills/api-endpoint/SKILL.md
-> instructs agent when and why to run checks
scripts/verify-api-change.sh
-> executes deterministic checks
BeforeCommit hook
-> requires checks before commit
Связка:
| Layer | Role |
|---|---|
| Skill | Объясняет workflow и domain-specific judgment. |
| Script | Выполняет repeatable command. |
| Hook | Запускает script в нужный момент. |
| CI | Повторяет проверку в clean environment. |
| Guardrail | Блокирует merge/deploy без required pass. |
Не нужно помещать большие scripts прямо в SKILL.md. Skill должен ссылаться на script в repo и объяснять, когда его использовать.
Hooks И MCP/Tools
Hook не обязан быть только shell script. В agent ecosystem hook может запускать:
- local command;
- test runner;
- formatter;
- static analyzer;
- MCP tool;
- internal verification service;
- policy check;
- notification;
- approval request.
Но принцип тот же:
Trigger -> Action -> Result -> Decision
Если hook вызывает external tool, добавляются вопросы:
- какие permissions нужны;
- что делать при network failure;
- является ли результат deterministic;
- где хранится output;
- можно ли повторить проверку локально;
- как избежать утечки secrets;
- кто владеет integration.
Для 101 уровня default простой:
Prefer local scripts for project checks.
Use external tools when they add real verification value.
Например, secret scanning может быть local tool. Security posture dashboard может быть external. Но агенту все равно нужен понятный result: passed, failed, blocked, approval required.
Пример: Hooks Plan Для Demo Repo
Допустим, demo repo содержит:
web/
src/
tests/
docs/
scripts/
Технологии:
- TypeScript frontend;
- API routes;
- Markdown docs;
- test suite;
- deploy через CI.
Hooks Plan
AfterEdit:
- if changed files match `web/src/**/*.{ts,tsx}`:
run formatter on changed files;
- if changed files match `docs/**/*.md`:
run markdown format/check;
- if changed files match `*.json` or `*.yaml`:
run config validation.
BeforeCommit:
- run `./scripts/verify --changed`;
- run secret scan;
- block commit on failure.
BeforePush:
- run `./scripts/verify`;
- block push on failure.
BeforeDeploy:
- require green CI for commit;
- run staging smoke tests;
- check migration plan if migrations changed;
- require human approval for production.
scripts/verify Contract
Command:
./scripts/verify [--changed|--full|--security]
Default:
./scripts/verify runs the standard local verification suite.
Required output:
- each stage prints name;
- failures return non-zero;
- skipped checks print reason;
- no secrets printed.
Used by:
- human developer;
- agent BeforeCommit;
- CI workflow.
Agent Instruction Around Hooks
Before finalizing a coding task:
1. Run the relevant targeted checks.
2. Run `./scripts/verify` unless impractical.
3. If a hook/check fails, fix root cause and rerun.
4. If verification cannot be run, report it as not run with reason.
5. Do not describe a check as passed unless the command actually passed.
Notice: this instruction is still useful. But the real protection is that BeforeCommit/CI run the script regardless of the agent's memory.
Example Failure Flow
Scenario:
Agent edits password reset API.
BeforeCommit runs `./scripts/verify`.
Typecheck fails.
Good flow:
Bad flow:
The typecheck issue appears unrelated, so I will continue.
Maybe it is unrelated. But the right next action is not silent continuation. The agent should:
- identify if it is pre-existing;
- show evidence;
- ask whether to proceed if policy allows;
- document residual risk;
- avoid claiming the change is fully verified.
Hook Output Который Помогает Агенту
Hook output должен быть readable.
Плохо:
ERROR 1
Лучше:
[verify] typecheck
web/src/auth/reset.ts:42:13
Type 'string | null' is not assignable to type 'string'.
Next:
- fix null handling;
- rerun `./scripts/verify`.
Хороший output экономит tokens и время. Агенту не нужно угадывать, что сломалось.
Для больших logs полезно:
- печатать stage names;
- показывать failed command;
- сохранять full logs в файл;
- выводить last relevant lines;
- не печатать secrets;
- не смешивать несколько tools в нечитаемый поток.
Hooks И Cost Management
Автоматизация не бесплатна. Слишком много hooks замедляют работу.
Нужно разделять checks по цене:
| Уровень | Пример | Когда запускать |
|---|---|---|
| Very fast | format changed file, conflict marker check | AfterEdit. |
| Fast | lint changed files, config validation | AfterEdit или BeforeCommit. |
| Medium | typecheck, targeted unit tests | BeforeCommit. |
| Slow | full e2e, full build, security scan | BeforePush, CI, BeforeDeploy. |
| Expensive | full eval regression suite | Before release, scheduled, high-risk changes. |
Правило:
Run cheap checks early.
Run expensive checks at meaningful gates.
Если slow check запускается слишком часто, люди и агенты начнут искать обход. Лучше иметь tiered verification:
./scripts/verify --fast
./scripts/verify --changed
./scripts/verify --full
Но default policy должна быть ясной:
- что нужно перед commit;
- что нужно перед PR/merge;
- что нужно перед deploy;
- что делать, если check не запускался.
Hooks И Изменение Тестов
В AI-assisted development есть особый риск:
Agent changes tests to make hook green.
Hook сам по себе не понимает, были ли tests ослаблены. Поэтому нужны дополнительные правила:
- если agent меняет tests, он должен объяснить why;
- reviewer смотрит test diff особенно внимательно;
- acceptance criteria остаются source of truth;
- failing test нельзя удалять без reason;
- test weakening для green build требует review;
- для bug fix сначала нужен reproducing test, когда practical.
Можно добавить hook, который сигналит о test changes:
If files under `tests/` changed:
- require test change summary in final report;
- run relevant test suite;
- include before/after behavior if bug fix.
Но judgement остается за reviewer.
Hooks И Secrets
Secret scan - один из самых полезных hooks для agent workflow.
Почему:
- агент может вставить example token;
- user может случайно дать secret в prompt;
- docs/examples могут содержать fake-looking but real credentials;
- logs могут попасть в commit;
- config files легко перепутать.
Практичная policy:
BeforeCommit:
- scan changed files for secrets;
- block on high-confidence secret;
- require human decision for ambiguous finding.
BeforeDeploy:
- validate required secrets exist in environment;
- do not print secret values;
- fail if config references missing secret.
Важно различать:
Secret present in repo: block and remove.
Secret missing in deploy environment: block deploy and configure securely.
Hook не должен "исправлять" secret путем печати нового value или записи его в файл.
Hooks И Generated Files
Многие проекты имеют generated artifacts:
- API clients from OpenAPI;
- GraphQL types;
- protobuf classes;
- database migration snapshots;
- docs TOC;
- lockfiles;
- compiled assets.
Агент может изменить source file и забыть generated file.
Hook помогает:
If schema changed:
-> run codegen check
-> fail if generated files are outdated
Два подхода:
| Подход | Как работает |
|---|---|
| Auto-generate after edit | Hook обновляет generated files сразу. |
| Check before commit | Hook fails, если generated files outdated. |
Auto-generate подходит, если:
- generator deterministic;
- output small;
- command fast;
- generated files expected in repo.
Check-only подходит, если:
- generator slow;
- output large;
- developer should decide;
- generated files sometimes excluded.
Hooks И Документация
Для этого курса hooks полезны даже в Markdown-only репозитории.
Примеры:
AfterEdit:
- check code fences are balanced;
- format markdown tables;
- enforce heading style if needed.
BeforeCommit:
- run markdown lint;
- check internal links;
- check lesson files have required sections;
- scan for unfinished draft markers;
- check duplicate lesson titles.
Для курса можно сделать scripts/verify-docs:
#!/usr/bin/env bash
set -euo pipefail
echo "[docs] placeholders"
rg -n "UNFINISHED|DRAFT_MARKER|TEMP_MARKER" modules guide req && exit 1 || true
echo "[docs] markdown fences"
: "real implementation can count fences per file"
echo "[docs] required summaries"
rg -L "## Краткое резюме" modules/**/*.md
Это учебный пример, не готовый universal linter. Но идея правильная: повторяемые проверки курса лучше сделать script'ом.
Как Проектировать Hook
Шаблон:
Hook Name:
Purpose:
Trigger:
Scope:
Command:
Expected duration:
Runs locally:
yes/no
Runs in CI:
yes/no
Failure behavior:
Can auto-fix:
yes/no
Requires human approval:
yes/no
Evidence to report:
Owner:
Пример:
Hook Name:
BeforeCommitVerify
Purpose:
Prevent unverified code from being committed.
Trigger:
Before local commit or agent checkpoint.
Scope:
All changed files.
Command:
./scripts/verify --changed
Expected duration:
Under 2 minutes.
Runs locally:
yes
Runs in CI:
CI runs ./scripts/verify --full
Failure behavior:
Block commit. Agent fixes root cause or reports blocked.
Can auto-fix:
No.
Requires human approval:
Only for override.
Evidence to report:
Command, pass/fail, not-run reason, failing stage.
Owner:
Project maintainers.
Когда Hook Не Нужен
Не все нужно превращать в hook.
Hook не нужен, если:
- действие требует product judgement;
- проверка не deterministic;
- false positives слишком шумные;
- command слишком медленная для выбранного stage;
- output нельзя безопасно показать агенту;
- действие требует secrets без необходимости;
- check редко применяется и проще запускать вручную;
- hook будет менять scope задачи;
- нет owner, который будет поддерживать hook.
Примеры:
| Идея | Почему hook может быть плохим |
|---|---|
| "AI reviewer before every save" | Нестабильно, дорого, много noise. |
| "Auto-refactor after edit" | Может менять behavior и расширять diff. |
| "Auto-deploy after tests" | Deploy требует risk decision и approval. |
| "Auto-delete unused files" | Риск потери work-in-progress. |
| "Auto-upgrade dependencies weekly" | Требует review, changelog, compatibility checks. |
Хороший вопрос:
Can this action be safely repeated by a script
without understanding product intent?
Если нет, это не простой hook. Возможно, это review, approval, manual task или guardrail.
Типичные Ошибки
Ошибка 1. Hook Дублирует Prompt, Но Не Enforce'ит
Плохо:
BeforeCommit hook prints:
"Remember to run tests."
Это reminder, а не hook.
Лучше:
BeforeCommit hook runs tests and fails on non-zero exit.
Ошибка 2. Hook Слишком Медленный
Плохо:
AfterEdit runs full e2e suite.
Последствие:
- feedback слишком дорогой;
- agents and humans avoid the hook;
- iteration slows down;
- hook воспринимается как препятствие.
Лучше:
AfterEdit: format.
BeforeCommit: targeted tests.
CI/BeforeDeploy: full suite.
Ошибка 3. Hook Делает Semantic Changes
Плохо:
Hook rewrites API behavior to match tests.
Это implementation, не hook.
Лучше:
Hook reports mismatch and blocks transition.
Agent or human decides fix.
Ошибка 4. Hook Скрывает Failure
Плохо:
npm test || true
Такой hook создает ложную безопасность.
Лучше:
npm test
И если failure allowed, он должен быть explicit:
Known flaky test:
- name:
- owner:
- issue:
- expiration date:
- approval:
Ошибка 5. Hooks Отличаются Локально И В CI
Плохо:
Local hook runs lint.
CI runs different lint config and fails later.
Лучше:
Both local hook and CI call the same repo script.
Например:
./scripts/verify
Ошибка 6. Hook Требует Too Much Context
Если hook должен читать длинные docs, интерпретировать product requirements и выбирать architecture, это уже не hook.
Hook должен проверять narrow, executable condition.
Ошибка 7. No Owner
Hook может сломаться после upgrade toolchain.
Если никто не владеет hook:
- failure начинают игнорировать;
- команды устаревают;
- false positives копятся;
- agents получают contradictory instructions.
У каждого важного hook должен быть owner.
Практика
Спроектируйте hooks для demo repo или capstone feature.
Заполните шаблон:
Repository type:
Main languages/frameworks:
Critical workflows:
- edit:
- commit:
- push:
- deploy:
AfterEdit hooks:
1.
2.
3.
BeforeCommit hooks:
1.
2.
3.
BeforeDeploy hooks:
1.
2.
3.
scripts/verify:
- command:
- fast checks:
- full checks:
- security checks:
Failure behavior:
- formatter failure:
- lint failure:
- test failure:
- secret scan failure:
- deploy check failure:
Human approval points:
- dependency upgrade:
- migration:
- deploy:
- security override:
Evidence in agent report:
- command:
- result:
- not-run checks:
- known risks:
Минимальный хороший результат:
[ ] Есть AfterEdit hook для mechanical cleanup.
[ ] Есть BeforeCommit hook для локальной проверки.
[ ] Есть BeforeDeploy или release gate для risky action.
[ ] Есть `scripts/verify` как единый вход.
[ ] Failure behavior описан.
[ ] Агент знает, как report'ить hook evidence.
[ ] Slow checks не запускаются слишком рано.
[ ] High-risk failures не fail open без approval.
Мини-Задание: Перевести Prompt Rules В Hooks
Возьмите 5 prompt rules:
1. Always format code before final response.
2. Always run tests before commit.
3. Never commit secrets.
4. Validate prompt files after editing them.
5. Check docs links before release.
Переведите их:
| Prompt rule | Hook |
|---|---|
| Always format code before final response. | AfterEdit formatter или BeforeCommit format check. |
| Always run tests before commit. | BeforeCommit runs ./scripts/verify --changed. |
| Never commit secrets. | BeforeCommit secret scan blocks commit. |
| Validate prompt files after editing them. | AfterEdit/BeforeCommit prompt schema validation. |
| Check docs links before release. | BeforeRelease link checker. |
После этого спросите:
- что должно fail closed;
- что может быть warning;
- где нужен human approval;
- какой script будет единым entry point;
- какую evidence агент должен показать reviewer'у.
Краткое резюме
Hook - это deterministic automation вокруг agent workflow. Он запускается по событию, выполняет command, возвращает result и помогает решить, можно ли переходить к следующему stage.
Главный принцип:
Do not ask the model to remember what the system can enforce.
Hooks особенно полезны для:
- formatting;
- lint;
- typecheck;
- tests;
- secret scan;
- generated files;
- docs checks;
- prompt/skill validation;
- deploy readiness checks.
Но hooks не заменяют judgement. Они не должны принимать product decisions, менять scope, скрывать failures или deploy'ить без approval. Хороший hook делает workflow более предсказуемым: cheap checks run early, expensive checks run at gates, failed checks stop the transition, evidence попадает в handoff.
Для курса ключевой artifact:
./scripts/verify
Это executable contract между человеком, агентом и CI.
Вопросы для самопроверки
- Чем hook отличается от prompt instruction?
- Почему
scripts/verifyполезен именно для AI-assisted development? - Какие проверки подходят для AfterEdit, а какие лучше оставить для BeforeCommit или CI?
- Что должен сделать агент, если BeforeCommit hook failed?
- Почему hook не должен автоматически принимать security или deploy decisions?
Что дальше
В следующем уроке мы разберем guardrails: branch protection, tool permissions, CI gates, approval gates и другие hard constraints. Hooks запускают автоматизацию в нужный момент. Guardrails задают границы, через которые workflow не должен проходить без выполнения правил или явного human approval.