모듈 5: Hooks - 자동화 트리거
학습 목표
- Hook의 개념과 동작 시점을 이해한다
- 프로젝트에 정의된 Hook들의 역할을 설명할 수 있다
- 간단한 Hook을 직접 작성할 수 있다
- Hook의 보안 고려사항을 이해한다
Hook이란?
Claude Code 생명주기의 특정 시점에 자동으로 실행되는 쉘 스크립트입니다.
AI가 “선택적으로” 실행하는 것이 아니라, 설정된 조건에서 반드시 실행됩니다.
AI의 선택 = 불확실
Hook = 확실한 실행 보장
Hook 이벤트 목록
| 이벤트 | 트리거 시점 | 주요 용도 |
|---|---|---|
PreToolUse | 도구 실행 직전 | 위험한 명령 차단 |
PostToolUse | 도구 실행 성공 후 | 자동 포맷, 로그 |
UserPromptSubmit | 사용자 프롬프트 전송 시 | 알림, 사전 처리 |
SubagentStop | 서브에이전트 완료 시 | 결과 통합 |
Stop | 메인 에이전트 응답 완료 | 최종 정리 |
SessionStart | 세션 시작 | 환경 초기화 |
PreCompact | 컨텍스트 압축 전 | 중요 정보 보존 |
프로젝트 Hook 설정 파일
// .claude/hooks/example-hook-config.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/log-tool-usage.sh",
"description": "파일 편집 시 자동 로그"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "...(위험 명령 차단 스크립트)...",
"description": "위험한 bash 명령 차단"
}
]
}
]
}
}Hook 1: 파일 편집 후 로그 (PostToolUse)
설정
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [{
"type": "command",
"command": ".claude/hooks/log-tool-usage.sh"
}]
}
]동작
AI가 파일 편집 (Edit 도구)
|
v (자동 실행)
log-tool-usage.sh
- 편집된 파일명 기록
- 타임스탬프 기록
- tool_use.log에 저장
활용 사례
- 어떤 파일을 AI가 수정했는지 추적
- 코드 리뷰 전 AI 수정 이력 확인
- 팀 작업 이력 관리
Hook 2: 위험 명령 차단 (PreToolUse)
설정
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "bash -c 'input=$(cat); cmd=$(echo \"$input\" | jq -r \".tool_input.command\"); if [[ \"$cmd\" =~ (rm|delete).*(\\*|\\.env|credentials|secret) ]]; then echo \"{\\\"action\\\": \\\"block\\\", \\\"message\\\": \\\"위험한 명령 차단\\\"\"}; else echo \"{}\"; fi'"
}]
}
]동작
AI가 bash 명령 실행 시도
|
v (PreToolUse 실행)
명령어 검사:
"rm -rf *" -> BLOCK (위험)
"rm .env" -> BLOCK (환경 파일)
"dotnet build" -> 허용
"dotnet test" -> 허용
|
v (차단 시)
{"action": "block", "message": "위험한 명령 차단: rm -rf *"}
|
v (허용 시)
{} (빈 객체 = 허용)
차단 조건
현재 설정에서 차단하는 패턴:
rm *또는delete *- 와일드카드 삭제rm .env- 환경 설정 파일 삭제rm credentials- 인증 정보 파일 삭제rm secret- 비밀 키 파일 삭제
Hook 3: 검증 알림 (UserPromptSubmit)
설정
"UserPromptSubmit": [
{
"hooks": [{
"type": "command",
"command": "bash -c '...test/validate 키워드 감지 시 validation-gates 알림...'"
}]
}
]동작
사용자: "이 코드 테스트해줘"
|
v (UserPromptSubmit 실행)
프롬프트에 "test" 키워드 감지
|
v (stderr로 알림)
"Reminder: validation-gates subagent 사용을 권장합니다."
|
v
Claude에게 프롬프트 전달 (차단 아님, 알림만)
Hook 4: 서브에이전트 완료 알림 (SubagentStop)
동작
validation-gates 에이전트 작업 완료
|
v (SubagentStop 실행)
"Validation gates completed. Running final checks..."
(stderr에 출력 - 개발자에게 알림)
Hook 입출력 형식
입력 (stdin JSON)
// PostToolUse - Edit 도구 실행 후
{
"tool_name": "Edit",
"tool_input": {
"file_path": "src/ui/ViewModels/MyViewModel.cs",
"old_string": "old code",
"new_string": "new code"
},
"tool_result": { "success": true }
}// PreToolUse - Bash 도구 실행 전
{
"tool_name": "Bash",
"tool_input": {
"command": "rm -rf *"
}
}출력 (stdout JSON)
// 허용 (진행)
{}
// 차단 (중단)
{
"action": "block",
"message": "이유 설명"
}Hook 설정 적용 방법
프로젝트 전용 설정
# .claude/settings.json에 추가
cp .claude/hooks/example-hook-config.json .claude/settings.json전체 사용자 설정 (모든 프로젝트에 적용)
# Windows: %APPDATA%\Claude\settings.json
# Mac/Linux: ~/.claude/settings.json실습: 커스텀 Hook 작성
목표: C# 파일 편집 후 자동으로 빌드 경고 확인
# .claude/hooks/check-build-warning.sh
#!/bin/bash
# stdin에서 JSON 읽기
INPUT=$(cat)
# 편집된 파일명 추출
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# .cs 파일만 처리
if [[ "$FILE" == *.cs ]]; then
echo "C# 파일 편집 감지: $FILE" >&2
# 빌드 실행하여 경고 확인
BUILD_OUTPUT=$(dotnet build 2>&1)
WARNING_COUNT=$(echo "$BUILD_OUTPUT" | grep -c "warning")
if [ "$WARNING_COUNT" -gt 0 ]; then
echo "주의: 빌드 경고 ${WARNING_COUNT}개 발생" >&2
fi
fi
# Hook 성공 (Claude 계속 진행)
echo "{}"// settings.json에 등록
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": ".claude/hooks/check-build-warning.sh"
}]
}
]
}
}Hook 디버깅
# Claude Code 디버그 모드 실행
claude --debug
# 출력에서 Hook 관련 로그 확인
# [HOOK] PostToolUse triggered for Edit
# [HOOK] Command: .claude/hooks/log-tool-usage.sh
# [HOOK] Exit code: 0
# [HOOK] Output: {}보안 고려사항
Hook은 쉘 명령을 실행하므로 주의가 필요합니다:
# 위험: stdin 데이터를 직접 eval
eval "$(echo "$INPUT" | jq -r '.command')" # 절대 금지
# 안전: jq로 특정 필드만 추출 후 검증
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
if [[ "$FILE" =~ ^[a-zA-Z0-9/_.-]+$ ]]; then # 경로 형식 검증
# 처리
fi주의사항:
- 입력 데이터 항상 검증
- 절대 경로 사용 권장 (PATH 조작 방지)
- 민감한 정보 (API Key 등) Hook 스크립트에 하드코딩 금지
핵심 정리
- Hook = Claude 생명주기 이벤트에 반드시 실행되는 쉘 스크립트
- AI의 선택이 아닌 결정론적 자동화
- 주요 용도: 위험 명령 차단, 자동 포맷, 작업 로그, 알림
- 입력: stdin JSON / 출력:
{}(허용) 또는{"action":"block"}(차단) .claude/settings.json에 등록하여 활성화- 보안: 입력 데이터 항상 검증, eval 금지