Claude Code Hooks 완전 가이드: PreToolUse, PostToolUse 자동화
Claude Code Hooks는 Claude가 도구(Write, Edit, Bash 등)를 호출할 때 자동으로 실행되는 쉘 명령어다. 파일 저장 직후 타입체크를 돌리거나, git push 전에 테스트를 강제하거나, 위험한 명령어를 사전 차단하는 등 개발 워크플로를 Claude의 손이 닿는 모든 지점에서 자동화할 수 있다. Hooks를 활용하면 Claude가 혼자 작업하는 동안에도 코드 품질과 보안 규칙이 항상 유지된다. 이 가이드는 Hooks의 작동 원리부터 settings.json 설정, 12개 실전 예제까지 모두 다룬다.
Claude Code Hooks란?
Claude Code는 코드를 읽고(Read), 수정하고(Edit), 저장하고(Write), 터미널 명령을 실행한다(Bash). 이 모든 행동은 내부적으로 "도구 호출(tool call)"이다. Hooks는 이 도구 호출의 직전(PreToolUse)과 직후(PostToolUse)에 끼어들어 원하는 쉘 명령을 실행하는 메커니즘이다.
예를 들어:
Edit직후에tsc --noEmit을 실행해 타입 오류를 즉시 피드백Bash실행 전에 위험 패턴(rm -rf,DROP TABLE)을 검사해 차단- 모든 도구 호출 로그를 파일에 기록해 나중에 감사(audit) 가능하게 유지
Hooks는 Claude가 기억하지 않아도 자동으로 실행되기 때문에, 프롬프트에 "타입체크 해줘"라고 매번 쓸 필요가 없다. 한 번 설정하면 모든 세션, 모든 프로젝트에서 항상 동작한다.
더 넓은 Claude Code 활용법은 Claude Code 한국어 완벽 가이드를 참고하라.
Hooks 이벤트 종류
| 이벤트 | 발화 시점 | 도구 호출 차단 가능? | 주요 용도 |
|---|---|---|---|
PreToolUse |
도구 실행 직전 | 가능 (exit 1 시 차단) | 안전 검사, 위험 명령 차단, 사전 로깅 |
PostToolUse |
도구 실행 직후 | 불가 | 포매터 실행, 타입체크, 테스트 트리거, 결과 로깅 |
PreCompact |
컨텍스트 압축 직전 | 불가 | 압축 전 상태 스냅샷 저장, 중간 커밋 자동화 |
UserPromptSubmit |
사용자 메시지 전송 시 | 가능 | 세션 시작 로깅, 환경 검사 |
핵심 규칙:
PreToolUseHook이 **0이 아닌 종료 코드(exit non-zero)**를 반환하면 Claude는 해당 도구 호출을 취소한다.- stderr로 출력한 메시지는 Claude에게 피드백으로 전달되어, Claude가 다음 행동을 결정하는 데 활용된다.
PostToolUse는 도구 실행 결과를 바꿀 수 없고, 사이드 이펙트(포맷, 테스트 등)를 추가하는 용도다.
settings.json 기본 설정법
Hooks는 두 곳 중 하나에 설정한다:
- 프로젝트 레벨:
.claude/settings.json(해당 프로젝트에서만 동작) - 글로벌 레벨:
~/.claude/settings.json(모든 Claude Code 세션에서 동작)
두 파일이 모두 존재하면 프로젝트 레벨이 우선되지 않고, 두 설정이 **합산(append)**된다. 즉 글로벌 Hooks와 프로젝트 Hooks가 둘 다 실행된다.
기본 구조:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{"type": "command", "command": "bun run typecheck 2>&1 | head -20"}]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{"type": "command", "command": "echo \"[HOOK] 실행: $TOOL_NAME\""}]
}
]
}
}
설정 필드 설명:
| 필드 | 설명 |
|---|---|
matcher |
어떤 도구에 적용할지. 파이프(|)로 여러 도구 지정. "*"는 전체. |
type |
현재는 "command"만 지원 |
command |
실행할 쉘 명령어. 환경 변수로 컨텍스트 접근 가능 |
Hooks에서 사용 가능한 환경 변수:
| 변수 | 내용 | 사용 가능 위치 |
|---|---|---|
TOOL_NAME |
호출된 도구 이름 | Pre / Post |
TOOL_INPUT |
도구 입력값 (JSON) | Pre |
CLAUDE_FILE_PATH |
파일 경로 (파일 관련 도구) | Pre / Post |
CLAUDE_SESSION_ID |
현재 세션 ID | Pre / Post |
CLAUDE_WORKING_DIR |
현재 작업 디렉토리 | Pre / Post |
실전 예제 12개
타입체크 & 빌드
1. TypeScript 파일 저장 후 즉시 타입체크
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '\\.tsx?$'; then cd \"$CLAUDE_WORKING_DIR\" && bun run typecheck 2>&1 | head -20; fi"
}]
}
]
}
}
.ts / .tsx 파일이 저장될 때마다 타입체크를 실행하고 결과 상위 20줄을 Claude에 피드백한다. Claude가 스스로 타입 오류를 수정하는 루프가 자동으로 만들어진다.
2. Next.js 빌드 가능 여부 사전 확인
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '\\.(tsx?|js)$'; then cd \"$CLAUDE_WORKING_DIR\" && bun run build 2>&1 | tail -10; fi"
}]
}
]
}
}
파일 저장마다 빌드를 돌리는 것은 느리지만, CI 없는 솔로 프로젝트에서 빌드 브레이킹 커밋을 방지하는 가장 간단한 방법이다.
린트 & 포맷
3. Prettier 자동 포맷 (저장 시)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '\\.(ts|tsx|js|jsx|json|css)$'; then npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null; fi"
}]
}
]
}
}
Claude가 파일을 저장할 때마다 Prettier가 자동으로 적용된다. Claude의 코드 스타일이 항상 프로젝트 포맷 규칙을 따르게 된다.
4. ESLint 오류 즉시 피드백
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '\\.(tsx?|jsx?)$'; then npx eslint \"$CLAUDE_FILE_PATH\" --max-warnings=0 2>&1 | head -15; fi"
}]
}
]
}
}
ESLint 경고가 0개를 초과하면 stdout으로 오류를 출력해 Claude에게 전달한다. Claude는 이를 읽고 바로 수정한다.
5. Python 파일 black 포맷
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '\\.py$'; then black \"$CLAUDE_FILE_PATH\" 2>/dev/null; fi"
}]
}
]
}
}
테스트
6. 관련 테스트 파일 자동 실행
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "TEST_FILE=$(echo \"$CLAUDE_FILE_PATH\" | sed 's/\\.ts$/.test.ts/'); if [ -f \"$TEST_FILE\" ]; then cd \"$CLAUDE_WORKING_DIR\" && bun test \"$TEST_FILE\" 2>&1 | tail -15; fi"
}]
}
]
}
}
편집한 파일에 대응하는 .test.ts 파일이 존재하면 자동으로 테스트를 실행한다.
7. git push 전 전체 테스트 강제
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "if echo \"$TOOL_INPUT\" | grep -q 'git push'; then cd \"$CLAUDE_WORKING_DIR\" && bun test 2>&1; if [ $? -ne 0 ]; then echo 'BLOCKED: 테스트 통과 후 push 가능합니다' >&2; exit 1; fi; fi"
}]
}
]
}
}
git push를 시도할 때 테스트가 실패하면 Claude가 push를 못 하도록 차단한다.
Git & 보안
8. 위험 명령어 사전 차단
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "BLOCKED='rm -rf /|DROP TABLE|DELETE FROM.*WHERE 1=1|kill -9 -1'; if echo \"$TOOL_INPUT\" | grep -qiE \"$BLOCKED\"; then echo 'BLOCKED: 위험 명령어 감지 — 사람의 확인이 필요합니다' >&2; exit 1; fi"
}]
}
]
}
}
파괴적인 패턴이 포함된 Bash 명령을 모두 차단한다. BLOCKED 패턴을 프로젝트에 맞게 확장하면 된다.
9. .env 파일 편집 차단
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "if echo \"$CLAUDE_FILE_PATH\" | grep -qE '(\\.env|secrets|credentials|private_key)'; then echo 'BLOCKED: 시크릿 파일 편집은 사람이 직접 해야 합니다' >&2; exit 1; fi"
}]
}
]
}
}
.env, secrets, credentials 경로의 파일은 Claude가 수정할 수 없도록 완전히 잠근다.
로깅
10. 전체 도구 호출 감사 로그
{
"hooks": {
"PreToolUse": [
{
"matcher": "*",
"hooks": [{
"type": "command",
"command": "echo \"$(date -u +%Y-%m-%dT%H:%M:%SZ) $TOOL_NAME $CLAUDE_FILE_PATH\" >> ~/claude-audit.log"
}]
}
]
}
}
모든 도구 호출을 타임스탬프와 함께 ~/claude-audit.log에 기록한다. 세션 후 Claude가 무엇을 했는지 전체 이력을 확인할 수 있다.
11. Bash 명령 전용 실행 로그
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "echo \"[$(date +%H:%M:%S)] CMD: $(echo $TOOL_INPUT | python3 -c 'import sys,json; d=json.load(sys.stdin); print(d.get(\"command\",\"\"))' 2>/dev/null)\" >> ~/claude-bash.log"
}]
}
]
}
}
Claude가 실행하는 모든 Bash 명령을 시간과 함께 기록한다. 긴 자동화 세션에서 무슨 명령이 실행됐는지 추적할 때 유용하다.
12. macOS 데스크탑 알림 (파일 저장 시)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write",
"hooks": [{
"type": "command",
"command": "osascript -e 'display notification \"'\"$CLAUDE_FILE_PATH\"'\" with title \"Claude 파일 저장\"' 2>/dev/null || true"
}]
}
]
}
}
Claude가 파일을 저장할 때마다 macOS 알림이 표시된다. 백그라운드에서 긴 작업이 실행될 때 진행 상황을 체크할 수 있다.
Hooks 주의사항
1. 실행 시간 제한
Hooks는 기본 60초 타임아웃이 있다. 전체 테스트 스위트를 Edit 마다 실행하면 세션이 매우 느려진다. 빠른 명령(타입체크, 린터)은 PostToolUse에, 느린 명령(전체 테스트, 빌드)은 특정 이벤트(git push)에만 거는 것이 좋다.
2. 무한 루프 방지
Hook이 Claude Code 자체를 다시 호출하면(claude -p "...") Hook → Claude → Tool → Hook 루프가 발생할 수 있다. 이 패턴은 의도적으로만 사용하고, 항상 종료 조건을 명확히 하라.
3. 종료 코드 의미
- exit 0: 성공, 도구 호출 허용
- exit 1 (또는 non-zero): PreToolUse에서는 도구 호출 차단, PostToolUse에서는 오류 메시지로 처리
4. stderr vs stdout
PreToolUse에서 차단할 때는 반드시 >&2로 stderr에 메시지를 쓰라. Claude는 stderr를 읽어 왜 차단됐는지 이해하고 다음 행동을 결정한다.
5. 팀 공유 vs 개인 설정
.claude/settings.json(프로젝트 레벨)은 git에 커밋해 팀과 공유할 수 있다. ~/.claude/settings.json(글로벌)은 개인 설정이라 공유되지 않는다. 보안 차단 규칙은 프로젝트에, 개인 선호(알림, 로깅)는 글로벌에 두는 것이 일반적이다.
Hooks와 함께 Claude Code 영문 Hooks 가이드도 참고하면 더 많은 패턴을 확인할 수 있다. 전반적인 Claude Code 아키텍처는 Claude Code 완전 가이드를 보라.
Frequently Asked Questions
Claude Code Hooks는 어떤 버전부터 사용 가능한가?
Hooks는 Claude Code 1.x 이상에서 지원된다. claude --version으로 버전을 확인하고, 구버전이라면 npm install -g @anthropic-ai/claude-code@latest로 업데이트하라.
PreToolUse Hook이 exit 1을 반환하면 Claude는 어떻게 반응하나?
Claude는 해당 도구 호출이 차단됐음을 인식하고, Hook의 stderr 메시지를 읽는다. 그 후 메시지의 지시에 따라 다른 방식으로 접근하거나, 사용자에게 확인을 요청하거나, 작업을 포기한다. 명확한 이유를 stderr에 출력할수록 Claude의 대응이 정확해진다.
프로젝트 레벨 Hooks와 글로벌 Hooks가 충돌하면 어떻게 되나?
충돌이 아니라 합산(append)된다. 글로벌 ~/.claude/settings.json의 Hooks가 먼저 실행되고, 그 다음 프로젝트 .claude/settings.json의 Hooks가 실행된다. 같은 이벤트·같은 matcher에 두 개가 있으면 둘 다 실행되는 것이다. 이를 고려해 글로벌에는 범용 규칙을, 프로젝트에는 특수 규칙을 배치하라.
Hooks 디버깅은 어떻게 하나?
- Hook 명령을 터미널에서 직접 실행해 환경 변수 없이도 작동하는지 확인한다.
- 명령어 끝에
2>> /tmp/hook-debug.log를 추가해 오류를 파일로 캡처한다. claude --debug모드로 실행하면 Hook 실행 과정이 디버그 출력에 표시된다.- Hook 명령에
set -x를 추가하면 쉘 실행 흐름 전체를 볼 수 있다.
TOOL_INPUT 환경 변수로 Bash 명령 전체를 읽을 수 있나?
TOOL_INPUT은 도구 입력 전체가 JSON으로 인코딩된 값이다. Bash 도구의 경우 {"command": "ls -la"} 형태다. python3 -c 'import sys,json; print(json.load(sys.stdin)["command"])'처럼 파싱하거나, grep으로 패턴만 추출해 차단 여부를 판단할 수 있다.
Hooks가 실행되지 않는다면?
가장 흔한 원인 3가지: (1) settings.json JSON 문법 오류 — cat .claude/settings.json | python3 -m json.tool로 검증하라. (2) matcher 오타 — 도구 이름은 대소문자 구분이 있다(Write, Edit, Bash). (3) 파일 위치 오류 — 프로젝트 레벨은 반드시 프로젝트 루트의 .claude/settings.json이어야 한다.
Claude Code Power Prompts 300으로 Hooks 활용 극대화
Hooks 설정을 마쳤다면 이제 Claude에게 무엇을 시킬지가 중요하다. Claude Code Power Prompts 300은 Hooks와 함께 사용하도록 설계된 300개의 실전 프롬프트 컬렉션이다. 타입체크 자동화, 코드 리뷰, 배포 파이프라인 등 Claude Code의 자율 실행 능력을 최대한 끌어낼 수 있다.
→ Claude Code Power Prompts 300 구매하기 ($29)
30일 환불 보장. 구매 즉시 다운로드.