# 훅 (Hooks)

> Claude가 도구를 사용하거나 세션 마일스톤에 도달할 때 셸 커맨드, HTTP 요청, 프롬프트를 자동으로 실행합니다.

훅은 Claude Code의 도구 라이프사이클에 자동화를 연결합니다. Claude가 파일을 읽거나, bash 커맨드를 실행하거나, 응답을 완료할 때 설정된 훅이 자동으로 실행됩니다. 코드 스타일 강제, 테스트 실행, 도구 사용 로깅, Claude가 할 수 있는 작업 제어에 훅을 사용하세요.

## 훅 작동 방식

훅은 특정 **이벤트**에 바인딩된 커맨드(셸 스크립트, HTTP 엔드포인트, LLM 프롬프트)입니다. 이벤트가 발생하면 Claude Code가 매칭된 모든 훅을 실행하고 종료 코드와 출력을 사용해 다음 동작을 결정합니다.

각 훅의 입력은 무슨 일이 일어났는지 설명하는 JSON 객체입니다.

**종료 코드 의미:**
| 종료 코드 | 의미 |
|----------|------|
| `0` | 성공. stdout이 Claude에게 표시될 수 있음(이벤트별 다름) |
| `2` | 차단 또는 주입. stderr를 Claude에게 표시하고(`PreToolUse`) 도구 호출 방지 |
| 기타 | stderr를 사용자에게만 표시; 실행 계속 |

## 훅 이벤트

| 이벤트 | 설명 |
|--------|------|
| **PreToolUse** | 모든 도구 호출 직전에 발생. 도구 입력 검사, 승인/차단, 입력 수정 가능. 종료코드 `2` → 도구 호출 차단 |
| **PostToolUse** | 모든 성공적인 도구 호출 후 발생. 도구 출력 관찰 또는 Claude가 처리할 컨텍스트 주입 가능 |
| **PostToolUseFailure** | 도구 호출이 오류로 종료될 때 발생 |
| **Stop** | Claude가 응답을 종료하기 직전에 발생. 종료코드 `2` → stderr를 Claude에게 표시하고 대화 계속 |
| **SubagentStop** | 서브에이전트가 결론 내리기 직전에 발생 (`Stop`과 동일하지만 서브에이전트용) |
| **SubagentStart** | 새 서브에이전트가 시작될 때 발생 |
| **SessionStart** | 세션 시작, 재개, `/clear`, `/compact` 후에 발생 |
| **UserPromptSubmit** | 사용자가 프롬프트를 제출할 때 발생. 종료코드 `2` → 프롬프트 차단 |
| **PreCompact** | 컨텍스트 컴팩션 시작 직전에 발생. 종료코드 `2` → 컴팩션 차단 |
| **PostCompact** | 컴팩션 완료 후 발생 |
| **Setup** | 저장소 초기화(`init`) 및 주기적 유지보수(`maintenance`) 시 발생 |
| **PermissionRequest** | 권한 다이얼로그가 표시될 때 발생. 프로그래밍 방식으로 승인/거부 가능 |
| **PermissionDenied** | 도구 호출이 거부된 후 발생 |
| **Notification** | 권한 프롬프트, 유휴 프롬프트, 인증 성공 등의 알림 시 발생 |
| **CwdChanged** | 작업 디렉토리 변경 후 발생 |
| **FileChanged** | 감시 중인 파일이 변경될 때 발생 |
| **SessionEnd** | 세션이 종료될 때 발생 |
| **ConfigChange** | 세션 중 설정 파일이 변경될 때 발생 |

## 훅 설정

세션 내에서 `/hooks`를 실행해 훅 설정 메뉴를 열 수 있습니다. 훅은 설정 파일의 `hooks` 필드에 저장됩니다:

```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write $CLAUDE_FILE_PATH"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo 'Session complete' >> ~/.claude-log.txt"
          }
        ]
      }
    ]
  }
}
```

각 이벤트는 **매처 객체** 배열에 매핑됩니다:
- `matcher` (선택사항) — 이벤트의 매칭 가능한 필드와 매칭되는 문자열 패턴
- `hooks` — 매처가 일치할 때 실행할 훅 커맨드 배열

빈 또는 없는 `matcher`는 해당 이벤트의 모든 입력과 일치합니다.

## 훅 커맨드 타입

**셸 커맨드 (`type: "command"`):**
```json
{
  "type": "command",
  "command": "npm test",
  "timeout": 60,
  "shell": "bash",
  "async": false
}
```

필드:
- `command` — 실행할 셸 커맨드 (필수)
- `timeout` — 타임아웃(초)
- `shell` — `"bash"` (기본) 또는 `"powershell"`
- `async` — 백그라운드에서 실행 (출력 무시)
- `once` — 한 번 실행 후 자동으로 훅 제거
- `if` — 조건부로 훅 건너뛰기 위한 권한 규칙 구문
- `statusMessage` — 훅 실행 중 스피너에 표시되는 커스텀 메시지

**HTTP 요청 (`type: "http"`):**
```json
{
  "type": "http",
  "url": "https://hooks.example.com/claude-event",
  "headers": {
    "Authorization": "Bearer $MY_TOKEN"
  },
  "allowedEnvVars": ["MY_TOKEN"],
  "timeout": 10
}
```

Claude Code가 훅 입력 JSON을 URL에 POST합니다.

**LLM 프롬프트 (`type: "prompt"`):**
```json
{
  "type": "prompt",
  "prompt": "이 bash 커맨드에 보안 문제가 있는지 확인하세요: $ARGUMENTS. 문제가 있으면 설명하고 코드 2로 종료하세요.",
  "model": "claude-haiku-4-5",
  "timeout": 30
}
```

**에이전트 훅 (`type: "agent"`):**
```json
{
  "type": "agent",
  "prompt": "단위 테스트가 실행되고 통과했는지 확인하세요.",
  "timeout": 60
}
```

도구 접근 권한이 있는 짧은 에이전틱 루프로 실행됩니다. 파일을 읽거나 커맨드를 실행해야 하는 검증 작업에 유용합니다.

## 훅 예시

**파일 편집 후 자동 포맷:**
```json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write",
        "hooks": [
          {
            "type": "command",
            "command": "prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
          }
        ]
      }
    ]
  }
}
```

**위험한 커맨드 차단:**
```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "if echo \"$CLAUDE_TOOL_INPUT\" | grep -q 'rm -rf'; then echo '차단: rm -rf는 허용되지 않습니다' >&2; exit 2; fi"
          }
        ]
      }
    ]
  }
}
```

**모든 도구 사용 로깅:**
```json
{
  "hooks": {
    "PostToolUse": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$(date -u +%Y-%m-%dT%H:%M:%SZ) $CLAUDE_TOOL_NAME\" >> ~/.claude-tool-log.txt",
            "async": true
          }
        ]
      }
    ]
  }
}
```

**디렉토리 변경 시 환경 변수 주입:**
```json
{
  "hooks": {
    "CwdChanged": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "if [ -f .envrc ]; then grep '^export ' .envrc >> \"$CLAUDE_ENV_FILE\"; fi"
          }
        ]
      }
    ]
  }
}
```

## 훅 vs 스킬

| 기능 | 훅 | 스킬 |
|------|-----|------|
| 실행 시점 | 도구 이벤트에 자동 | Claude나 사용자가 `/skill-name`으로 명시적 호출 |
| 목적 | 부작용, 게이팅, 관찰 | 온디맨드 워크플로우와 기능 |
| 설정 | 설정 JSON | `.claude/skills/`의 마크다운 파일 |

자동으로 발생해야 하는 것(포맷팅, 로깅, 강제)에는 훅을 사용하고, 의도적으로 트리거하려는 반복 가능한 워크플로우에는 스킬을 사용하세요.
