오늘도 공부
Claude Code — Hooks를 활용한 턴 종료 시점 품질 검증 본문
CodeDeck - 개발자를 위한 코드 학습 카드 뉴스
프로그래밍 언어와 프레임워크를 카드 뉴스 형태로 쉽게 배우는 개발자 학습 플랫폼
www.codedeck.kr
Claude Code의 잘 알려지지 않은 hooks 기능을 활용하여 각 턴이 끝날 때마다 자동으로 품질 검사를 실행하고 귀중한 시간을 절약하는 방법을 알아봅니다.
핵심 요약
- Stop hook을 사용하여 각 턴 종료 시점에 결정론적이고 자동화된 품질 검사를 실행합니다
- 가벼운 PostToolUse hook과 after-write.sh를 조합하여 편집 후 즉각적인 포맷팅이나 빠른 검증을 수행합니다
- .claude/settings.json에서 after-write.sh를 PostToolUse에, 강력한 end-of-turn-check.sh를 Stop에 연결하여 설치, 코드 품질 검사(Biome), 조건부 E2E 테스트(Playwright)를 실행합니다
- matcher를 사용하여 hook을 안전하고 빠르게, 범위를 제한적으로 유지하며, 중요한 실패 시 exit code 2를 사용하여 계속 진행을 차단합니다
왜 중요한가?
매번 AI 어시스턴트가 코드를 편집한 후 수동으로 검사를 실행하는 것은 느리고 오류가 발생하기 쉽습니다. Claude Code hooks를 사용하면 모델이 체크리스트를 기억하도록 의존하지 않고도 "항상 실행" 품질 게이트를 강제할 수 있습니다.
Stop 이벤트는 턴 종료 시점의 검증에 이상적입니다:
- 린팅
- 타입 체크
- 테스트
- 리포지토리별 가드레일
이를 통해 턴 사이에 작업 트리가 더 안전하게 유지되고 피드백이 즉각적으로 이루어집니다.
사전 준비사항
이 튜토리얼에서는 이미 hooks가 활성화된 리포지토리를 가정합니다:
.claude/settings.json # 이벤트를 스크립트에 연결
.claude/hooks/after-write.sh # write/edit 도구 호출 직후 실행
.claude/hooks/end-of-turn-check.sh # 턴 종료 시(Stop) 실행
핵심 개념 및 아키텍처
Hook 이벤트 종류
- PreToolUse: 도구 실행 전 게이트
- PostToolUse: 도구 실행 후
- Stop: 턴 종료 시점
- SessionStart/End: 세션 시작/종료
- UserPromptSubmit: 사용자 프롬프트 제출 시
- SubagentStop: 서브에이전트 중지 시
- PreCompact: 컴팩트 전
Matchers
특정 도구나 이벤트에만 hook을 적용하도록 범위를 지정합니다.
예: "Write|Edit" - 파일 쓰기/편집 시에만 실행
Hook 스크립트
환경 변수와 함께 실행되는 간단한 셸 명령입니다. 가능한 한 멱등성을 유지하고 빠르게 유지하세요.
실행 결과
- 일반 종료 코드 사용
- exit code 2: 차단 오류로 처리됨
- stderr 내용은 Claude에게 전달되어 자동 후속 조치가 가능합니다
단계별 가이드
1. .claude/settings.json에서 hooks 연결
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/after-write.sh"
}
]
}
],
"Stop": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/end-of-turn-check.sh"
}
]
}
]
}
}
2. after-write hook을 빠르게 유지
#!/usr/bin/env bash
set -euo pipefail
# 필요시 언어별 빠른 포맷터 추가
echo "After-write: file changes applied." >&2
# 예: Prettier 실행 (선택사항)
# prettier -w "**/*.{ts,tsx,js,jsx,json,md}" || true
용도:
- 포맷팅
- import 정렬
- 빠른 린팅
주의사항:
- 무거운 I/O 작업 피하기
- 더 깊은 검사는 Stop hook으로 연기
3. 강력한 Stop hook 구현
실용적인 Stop 스크립트는 리포지토리별 검사를 안정적으로 실행하고 문제 발생 시 명확하게 실패합니다.
#!/bin/bash
set -e
kill_port() {
local p=$1
local pid=$(lsof -ti:$p 2>/dev/null || true)
[ -n "$pid" ] && kill -9 "$pid" || true
}
# TSX 파일이 변경되었으면 Playwright E2E 실행
if git diff --name-only HEAD 2>/dev/null | grep -q '\\.tsx$' || \
git ls-files --others --exclude-standard | grep -q '\\.tsx$'; then
kill_port 3000
kill_port 1080
kill_port 1025
pnpm test:e2e
kill_port 3000
kill_port 1080
kill_port 1025
fi
# 항상 의존성 및 타입 체크 실행
pnpm install
pnpm check
이 예제의 핵심:
- maildev(가짜 메일박스 서비스)가 사용하는 포트를 정리
- .tsx 파일 변경 시에만 E2E 테스트 실행 (조건부)
- 항상 의존성 설치 및 코드 품질 검사 실행
4. 스크립트를 실행 가능하게 만들기
chmod +x .claude/hooks/after-write.sh .claude/hooks/end-of-turn-check.sh
5. 동작 확인
- 파일 편집 트리거: after-write 메시지 확인
- 턴 종료: 설치/검사가 실행되는지 확인
- 의도적 실패: 즉시 표면화되는지 확인
6. 중요한 실패 시 차단 (선택사항)
if ! pnpm check; then
echo "타입 체크 실패. 다음 단계 전에 수정 중..." >&2
exit 2
fi
exit code 2를 반환하면:
- 계속 진행 차단
- 에러를 Claude에게 피드백
- Claude가 자동으로 복구 시도
실제 예제
기본 예제
# .claude/hooks/after-write.sh
prettier -w "**/*.{ts,tsx,js,jsx,json,md}" || true
# .claude/hooks/end-of-turn-check.sh
set -e
pnpm install
pnpm check || { echo "check failed" >&2; exit 2; }
Next.js 프로젝트 예제
.tsx 파일 변경 시에만 Playwright를 조건부로 실행하고 충돌하는 포트를 먼저 정리합니다:
kill_port 3000; kill_port 1080; kill_port 1025
pnpm test:e2e || { echo "e2e failed" >&2; exit 2; }
kill_port 3000; kill_port 1080; kill_port 1025
팁: UI E2E는 Stop으로 연기하고 PostToolUse는 즉각적으로 유지하세요. 피드백 속도와 커버리지 간의 균형을 맞춥니다.
pnpm check의 역할
이 리포지토리에서 pnpm check가 하는 일:
// package.json (scripts)
{
"check": "biome check --write .",
"check:ci": "biome ci app components config emails lib scripts styles tests .github package.json biome.json tsconfig.json"
}
기능:
- Biome의 포맷터, 린터, import 정렬을 지원되는 파일 전체에 실행
- --write 옵션으로 안전한 문제를 디스크에서 자동 수정
- 간격 및 따옴표 수정, import 정렬, 사용하지 않는 변수 및 일반적인 정확성/스타일 문제 플래그
- 차단 실패 시 0이 아닌 종료 코드 반환
참고:
- biome ci는 읽기 전용이며 파이프라인에 적합
- 로컬에서는 check로 자동 수정 사용
- CI에서는 check:ci를 엄격하게 유지하여 회귀 방지
Biome 설정 (biome.json)
기본 설정으로도 합리적인 결과가 나옵니다. 포맷팅, 린트 규칙, 무시할 경로를 조정하려면 추가하세요:
{
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2,
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"correctness": {
"noUnusedVariables": "error"
},
"style": {
"useConst": "warn",
"noVar": "error"
}
}
},
"files": {
"ignore": ["node_modules", ".next", "coverage", "dist", "build"]
}
}
주요 사항:
- Formatter: 줄 너비 및 들여쓰기 설정; Biome은 TS/JS/JSON/MD 등에 일관된 포맷팅 적용
- Linter: 핵심 규칙 활성화; 기준에 따라 심각도 조정
- Files: 일반적인 빌드 아티팩트 무시; Biome은 기본적으로 node_modules 무시
- Import 정렬: biome check는 import 정렬도 수행
성능, 확장성 및 보안
성능
- PostToolUse는 빠르게 유지
- 더 무거운 검사는 Stop으로 예약
- matcher로 범위 지정하여 불필요한 실행 방지
- 안전한 경우 캐싱 사용
보안
- Hook은 사용자 자격 증명으로 실행 — CI 스크립트처럼 취급
- 검토, 버전 관리, 부작용 제한
- 중요한 문제에는 명시적 실패 선호: Stop이 exit 2를 반환하여 어시스턴트가 자동 복구
일반적인 함정 및 디버깅 팁
- 실행 불가능: 항상 chmod +x 수행
- 잘못된 경로: 명령은 워크스페이스 기준으로 실행 — 리포지토리 상대 경로 사용
- 과도한 검사: 파일 타입 휴리스틱(예: .tsx만) 사용하여 Stop 빠르게 유지
- 포트 충돌: E2E 실행 전후로 서버를 사전에 종료
대안 및 트레이드오프
Hook 타입 용도 장점
| PreToolUse | 도구 실행 전 엄격한 게이팅 | 권한 부여나 비용이 많이 드는 작업 방지에 최적 |
| PostToolUse | 도구 호출 후 즉각적인 피드백 | 포맷터 및 빠른 검증에 적합 |
| Stop | 턴 종료 시점 품질 게이트 | 설치, 코드 품질 검사, 테스트, 상태 요약에 최적 |
| Git hooks/CI | Claude hooks 보완 | 비대화형 안전을 위해 CI에서 중요한 검사 복제 유지 |
결론 및 다음 단계
턴 종료 시점 hook은 "X를 실행하는 것을 기억하세요"를 자동화된 반복 가능한 정책으로 전환합니다.
시작하기
- 가벼운 after-write hook으로 시작
- Stop 스크립트를 확장하여 설치, 검사, 타겟 E2E 커버
- 빠르고, 범위가 지정되고, 안전하게 유지
- 실패가 중요한 경우 exit 2 사용하여 Claude가 즉시 문제 수정
핵심 포인트
- 자동화: 수동 검사 불필요
- 일관성: 항상 같은 품질 기준 적용
- 피드백 루프: 즉각적인 오류 감지 및 수정
- 생산성: AI와 협업 시 안심하고 작업
참고 자료
작성 일자: 2025년 11월 3일
원문: Claude Code — Use Hooks to Enforce End-of-Turn Quality Gates
'AI > Claude code' 카테고리의 다른 글
| 컨텍스트 윈도우가 뭐지? (0) | 2025.11.04 |
|---|---|
| Claude Code의 모든 기능을 효과적으로 활용하는 방법 (0) | 2025.11.03 |
| Flow: AI와 함께하는 체계적인 개발 프레임워크 (0) | 2025.11.02 |
| CC Sessions로 AI 코딩의 혼돈을 종식시키는 법 (0) | 2025.10.31 |
| Claude Agent Skills Deep dive (0) | 2025.10.31 |
