동작하는 코드
프로젝트의 .claude/settings.json에 Hook을 추가해봅시다. main 브랜치에서 파일 수정을 차단하는 Hook입니다:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "[ \"$(git branch --show-current)\" != \"main\" ] || { echo '{\"block\":true,\"message\":\"main 브랜치에서는 직접 수정할 수 없습니다. feature 브랜치를 만드세요.\"}' >&2; exit 2; }",
"timeout": 5
}
]
}
]
}
}
이제 main 브랜치에서 Claude에게 파일 수정을 요청해보세요:
> README.md에 한 줄 추가해줘
Hook이 작동하여 수정이 차단됩니다. 다른 브랜치로 전환하면 정상적으로 수정됩니다:
> git checkout -b feature/test로 브랜치를 만들고, README.md를 수정해줘
직접 수정하기
이번에는 PostToolUse Hook으로 파일 저장 후 자동 린트를 실행해봅시다:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx eslint --fix $CLAUDE_FILE_PATHS 2>/dev/null || true",
"timeout": 10
}
]
}
]
}
}
Claude가 파일을 수정할 때마다 ESLint가 자동으로 실행되어 스타일을 교정합니다.
"왜?" — 반복되는 규칙을 코드로 강제하기
CLAUDE.md에 "main 브랜치에서 작업하지 마세요"라고 적어도 Claude가 무시할 수 있습니다. Hook은 이런 규칙을 코드로 강제합니다. 요청이 아니라 차단입니다.
주요 Hook 이벤트
| 이벤트 | 시점 | 용도 |
| ------------------ | -------------------- | -------------------------------- |
| PreToolUse | 도구 실행 전 | 위험 작업 차단, 조건부 승인 |
| PostToolUse | 도구 실행 후 | 자동 포매팅, 린트, 로깅 |
| Notification | 알림 발생 시 | 커스텀 알림 (Slack, 데스크톱 등) |
| Stop | 응답 완료 시 | 결과 검증, 정리 작업 |
| UserPromptSubmit | 사용자 입력 시 | 입력 전처리 |
| SubagentStop | 서브에이전트 완료 시 | 서브에이전트 결과 후처리 |
| PreCompact | 컨텍스트 압축 전 | 압축 전 데이터 보존 |
| SessionStart | 세션 시작 시 | 환경 검증, 의존성 체크 |
| SessionEnd | 세션 종료 시 | 정리, 로깅 |
이 중 가장 자주 쓰이는 건 PreToolUse, PostToolUse, Notification입니다.
Hook 설정 구조
{
"hooks": {
"이벤트이름": [
{
"matcher": "도구이름 패턴 (정규식)",
"hooks": [
{
"type": "command",
"command": "실행할 셸 명령어",
"timeout": 5
}
]
}
]
}
}
matcher 패턴
matcher는 어떤 도구에 Hook을 적용할지 필터링합니다:
| 패턴 | 매칭 대상 |
| ------------- | ------------------------- |
| Edit\|Write | 파일 수정/생성 도구 |
| Bash | 셸 명령어 실행 |
| Read | 파일 읽기 |
| .* | 모든 도구 (주의해서 사용) |
종료 코드로 동작 결정
Hook의 종료 코드가 동작을 결정합니다:
| 종료 코드 | 동작 |
| --------- | --------------------------- |
| 0 | 성공 — 작업 계속 진행 |
| 2 | 차단 — 도구 실행을 막음 |
| 그 외 | 오류로 처리 |
PreToolUse에서 exit 2를 반환하면 작업이 차단됩니다:
exit 2
stderr로 메시지를 전달하면 Claude에게 차단 이유를 알려줄 수 있습니다:
echo "main 브랜치에서는 수정할 수 없습니다." >&2
exit 2
심화 학습
Hook에서 사용할 수 있는 환경 변수는?
Hook 명령어 안에서 다음 환경 변수를 사용할 수 있습니다:
$CLAUDE_FILE_PATHS— 현재 도구 호출에 관련된 파일 경로들 (공백 구분)$CLAUDE_PROJECT_DIR— 프로젝트 루트 디렉토리의 절대 경로
더 상세한 정보가 필요하면 stdin으로 전달되는 JSON을 jq로 파싱할 수 있습니다:
jq -r '.tool_input.command' >> ~/.claude/bash-log.txt
.claude/settings.json에 main 브랜치 보호 Hook을 추가하고 테스트해보세요.- PostToolUse Hook으로 파일 수정 후 자동으로
prettier --write를 실행하는 Hook을 만들어보세요. - SessionStart Hook으로 세션 시작 시 "현재 브랜치: {브랜치명}" 메시지를 출력하는 Hook을 만들어보세요.
Q1. Claude Code가 파일을 수정하기 전에 실행되는 Hook 이벤트는?
- A) PostToolUse
- B) SessionStart
- C) PreToolUse
- D) Stop