← All guides

Claude Code Hooks 완전 가이드: PreToolUse, PostToolUse 자동화

Claude Code Hooks로 파일 저장 시 자동 타입체크, 커밋 시 린트, 에러 감지까지 — 12개 실전 예제와 .claude/settings.json 설정법.

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)에 끼어들어 원하는 쉘 명령을 실행하는 메커니즘이다.

예를 들어:

Hooks는 Claude가 기억하지 않아도 자동으로 실행되기 때문에, 프롬프트에 "타입체크 해줘"라고 매번 쓸 필요가 없다. 한 번 설정하면 모든 세션, 모든 프로젝트에서 항상 동작한다.

더 넓은 Claude Code 활용법은 Claude Code 한국어 완벽 가이드를 참고하라.


Hooks 이벤트 종류

이벤트 발화 시점 도구 호출 차단 가능? 주요 용도
PreToolUse 도구 실행 직전 가능 (exit 1 시 차단) 안전 검사, 위험 명령 차단, 사전 로깅
PostToolUse 도구 실행 직후 불가 포매터 실행, 타입체크, 테스트 트리거, 결과 로깅
PreCompact 컨텍스트 압축 직전 불가 압축 전 상태 스냅샷 저장, 중간 커밋 자동화
UserPromptSubmit 사용자 메시지 전송 시 가능 세션 시작 로깅, 환경 검사

핵심 규칙:


settings.json 기본 설정법

Hooks는 두 곳 중 하나에 설정한다:

두 파일이 모두 존재하면 프로젝트 레벨이 우선되지 않고, 두 설정이 **합산(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. 종료 코드 의미

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 디버깅은 어떻게 하나?

  1. Hook 명령을 터미널에서 직접 실행해 환경 변수 없이도 작동하는지 확인한다.
  2. 명령어 끝에 2>> /tmp/hook-debug.log를 추가해 오류를 파일로 캡처한다.
  3. claude --debug 모드로 실행하면 Hook 실행 과정이 디버그 출력에 표시된다.
  4. 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일 환불 보장. 구매 즉시 다운로드.

AI Disclosure: Written with Claude Code.

도구와 자료