AI 에이전트 신뢰성을 보장하는 훅 8가지
CLAUDE.md 규칙은 80% 정도 지켜집니다. 훅은 100% 실행됩니다. 6개월간 테스트한 끝에 한 번도 제거하지 않은 8가지를 정리했습니다.
CLAUDE.md는 제안서에 가깝습니다. “커밋 전에 Prettier를 실행하세요”라고 써놓으면, 에이전트는 세 번 중 한 번쯤은 그냥 넘깁니다. 더 정밀하게 지시문을 다듬어도 문제가 해결되지 않습니다. 준수율 80%는 모델 품질의 문제가 아닙니다. 규칙을 컨텍스트 윈도우 안에 넣고 모델이 따르기를 기대하는 구조 자체의 한계입니다.
훅은 전혀 다른 평면에서 작동합니다. 모델의 판단과 무관하게, 특정 라이프사이클 시점에 자동으로 실행되는 스크립트입니다. PreToolUse는 에이전트가 파일을 수정하거나 명령어를 실행하기 직전에 발동합니다. PostToolUse는 실행 직후에 발동합니다. 모델이 실행 여부를 선택하지 않습니다. 그냥 실행됩니다.
실질적인 차이는 즉각적입니다. CLAUDE.md에 규칙 열 줄을 추가하는 것과 .claude/settings.json에 훅 하나를 추가하는 것은 전혀 다른 개입입니다. 종료 코드 2는 에이전트 동작을 완전히 차단합니다. 종료 코드 0은 통과시킵니다. 그 외의 종료 코드는 경고를 기록하되 차단하지 않습니다. 훅은 settings.json에 보관되므로, 한 번 커밋하면 팀 전체가 git을 통해 공유하게 됩니다.
실행 전에 세우는 4개의 방어선
훅을 6개월 넘게 운영해왔습니다. 다음 4개의 PreToolUse 훅은 어떤 프로젝트에서도 한 번도 제거되지 않았습니다.
위험한 명령어 차단은 정규식 매칭으로 rm -rf, git reset --hard, DROP TABLE 같은 파괴적 패턴을 포착하고, 종료 코드 2를 반환해 실행 전에 동작을 종료합니다. 에이전트가 건드려선 안 되는 디렉터리에 rm -rf를 시도하는 장면을 직접 목격했습니다. 이 훅이 없었다면 피해는 실제로 발생했을 것입니다.
민감한 파일 보호는 .env, package-lock.json, *.pem 등의 파일에 대한 수정 시도를 원천 차단합니다. 에이전트가 락 파일을 덮어쓰거나 자격 증명을 커밋에 유출할 기회 자체를 없애줍니다.
PR 전 테스트 통과 강제는 풀 리퀘스트 생성을 테스트 통과에 연동합니다. 매처를 mcp__github__create_pull_request로 설정하면, 테스트가 통과하기 전까지 에이전트는 PR을 열 수 없습니다. “다음에 테스트 고칠게요”라는 말이 사라집니다.
명령어 전체 로깅은 에이전트가 실행하는 모든 bash 명령어를 타임스탬프와 함께 .claude/command-log.txt에 기록합니다. 사흘 뒤 뭔가 이상해 보일 때, 무슨 일이 있었는지 정확히 추적할 수 있습니다.
실행 후에 작동하는 3개의 검사기
PostToolUse 훅은 에이전트가 파일을 수정한 직후에 실행됩니다. 세 개를 순서대로 연결해서 씁니다.
자동 포맷은 변경된 모든 파일에 Prettier를 실행합니다. 파이썬 프로젝트라면 Black으로, Go라면 gofmt로 교체하면 됩니다. 에이전트가 포맷을 기억했는지와 무관하게 포맷터가 실행됩니다.
자동 린트는 포맷 직후에 ESLint를 실행합니다. ESLint가 오류를 발견하면 에이전트는 같은 턴 안에 바로 확인하고 수정합니다. 사람의 코드 리뷰까지 린트 이슈가 올라오는 경우가 거의 사라집니다.
자동 테스트는 파일이 변경될 때마다 관련 테스트 스위트를 실행합니다. 테스트가 실패하면 에이전트는 수초 내에 인지하고 수정을 시도합니다. 출력을 tail -5로 요약만 남기도록 파이프해두면, 테스트 결과가 컨텍스트 윈도우를 넘치게 만드는 걸 방지할 수 있습니다.
순서가 중요합니다. Prettier 먼저, 그다음 ESLint, 그다음 테스트입니다. 사람이 코드를 볼 때쯤이면 포맷과 린트는 이미 통과한 상태입니다. 코드 리뷰에서 스타일 관련 코멘트가 사라집니다.
에이전트가 멈췄을 때 작업을 보존하는 방법
Stop 훅은 하나면 충분합니다. 자동 커밋은 에이전트가 응답을 마칠 때마다 git add -A && git commit을 실행합니다. 작업 단위마다 커밋이 생깁니다. 두 개의 작업이 하나의 커밋으로 뒤섞이는 일이 없어집니다.
git 워크트리와 함께 쓰면 피처 브랜치별로 커밋이 자동 생성됩니다. 에이전트가 충돌하거나 작업 도중 중단되더라도, 마지막 작업 단위를 잃지 않습니다.
기대만큼 깔끔하지 않았던 부분
훅 체이닝은 개념상 우아하지만, 실패한 체인을 디버깅하는 건 단일 스크립트보다 훨씬 복잡합니다. 자동 테스트 훅이 새 프로젝트에 테스트 러너가 설치되지 않은 채로 조용히 실패하기 시작했을 때, 에이전트가 계속 테스트 없는 코드를 만들어내는 이유를 추적하는 데 한 시간을 썼습니다. 테스트 스크립트 자체가 없었기 때문에 훅이 종료 코드 0을 반환했고, 셸은 “명령어를 찾을 수 없음”을 차단 조건으로 처리하지 않았습니다. 실행 전에 테스트 러너 존재 여부를 명시적으로 확인하는 로직을 추가해야 했습니다.
성능도 고려해야 할 제약입니다. 훅이 많으면 느려진다는 걱정이 일반적이지만, 그건 정확한 진단이 아닙니다. 핵심 질문은 개별 훅 하나가 200밀리초 이내에 끝나는지입니다. Prettier가 단일 파일에 실행되는 시간은 약 50ms입니다. ESLint 검사는 약 80ms입니다. 테스트는 변동이 있지만, 영향받은 파일로 범위를 좁히면 대부분 빠르게 유지됩니다. 훅 하나가 1초를 넘기기 시작하면, 에이전트의 피드백 루프가 느리게 느껴지기 시작합니다.
더 넓은 패턴과의 연결
OpenAI의 Harness Engineering 블로그는 에이전트가 엄격한 경계와 예측 가능한 구조 안에서 가장 잘 작동한다고 설명합니다. React의 설계 철학도 컴포넌트에 대해 같은 말을 합니다. 정의된 라이프사이클 단계와 상태를 가진 조합 가능한 단위라는 개념입니다.
Claude Code의 훅도 동일한 추상화를 따릅니다. 상태는 세션과 메모리에 해당합니다. 훅은 라이프사이클 경계에서 개입하는 함수입니다. PreToolUse가 경계를 설정하고, PostToolUse가 구조를 예측 가능하게 만들며, Stop이 결과를 보존합니다.
예전에 CLAUDE.md에 써뒀던 “Prettier 실행하세요” 한 줄은 이제 없습니다. 훅이 매번, 요청 없이 실행해줍니다.
뉴스레터 구독하기
최신 AI에 대한 인사이트를 받아보세요.