# 훅 레퍼런스

> 모든 훅 이벤트, 입력 페이로드, 출력 스키마, 각 종료 코드가 Claude 동작에 미치는 영향에 대한 전체 레퍼런스.

훅은 Claude의 에이전틱 루프에서 정의된 지점에서 발생하는 셸 커맨드, HTTP 엔드포인트, LLM 프롬프트, 또는 인프로세스 콜백입니다.

## 설정

훅은 설정 파일의 최상위 `hooks` 키로 구성됩니다:

```json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "echo 'bash 커맨드 실행 예정' >&2"
          }
        ]
      }
    ]
  }
}
```

## 매처 설정

`matcher` 필드는 이벤트별로 다른 필드와 매칭됩니다:

| 이벤트 | 매칭되는 필드 |
|--------|-------------|
| `PreToolUse` / `PostToolUse` / `PostToolUseFailure` / `PermissionRequest` / `PermissionDenied` | `tool_name` |
| `Notification` | `notification_type` |
| `SessionStart` | `source` (`startup`, `resume`, `clear`, `compact`) |
| `Setup` | `trigger` (`init`, `maintenance`) |
| `SubagentStart` / `SubagentStop` | `agent_type` |
| `PreCompact` / `PostCompact` | `trigger` (`manual`, `auto`) |
| `ConfigChange` | `source` |
| `FileChanged` | 파일 이름 패턴 (예: `".envrc|.env"`) |

## 훅 타입

**셸 커맨드:**
```json
{
  "type": "command",
  "command": "jq '.tool_name' && my-validator",
  "timeout": 30,
  "shell": "bash",
  "async": false,
  "once": false,
  "if": "Bash(git *)",
  "statusMessage": "검증 중..."
}
```

필드:
- `command`: 실행할 셸 커맨드 (필수)
- `timeout`: 타임아웃(초), 기본 60초
- `shell`: `bash` (기본) 또는 `powershell`
- `async`: `true`면 백그라운드에서 비블로킹 실행
- `asyncRewake`: `true`면 백그라운드 실행, 종료코드 2로 종료 시 모델 깨움
- `once`: `true`면 한 번 실행 후 자동 제거
- `if`: 조건부로 훅 건너뛰기 위한 권한 규칙 구문
- `statusMessage`: 실행 중 스피너에 표시되는 커스텀 메시지

**LLM 평가:**
```json
{
  "type": "prompt",
  "prompt": "이 bash 커맨드가 안전한지 확인하세요: $ARGUMENTS",
  "model": "claude-haiku-4-5",
  "timeout": 30
}
```

**에이전틱 검증기:**
```json
{
  "type": "agent",
  "prompt": "단위 테스트가 실행되고 통과했는지 확인하세요.",
  "model": "claude-haiku-4-5",
  "timeout": 120
}
```

**HTTP 엔드포인트:**
```json
{
  "type": "http",
  "url": "https://my-server.example.com/hook",
  "headers": {
    "Authorization": "Bearer $MY_TOKEN"
  },
  "allowedEnvVars": ["MY_TOKEN"],
  "timeout": 10
}
```

## 기본 훅 입력

모든 훅이 stdin에서 받는 공통 필드:

| 필드 | 타입 | 설명 |
|------|------|------|
| `hook_event_name` | `string` | 발생한 이벤트 (예: `"PreToolUse"`) |
| `session_id` | `string` | 현재 세션 식별자 |
| `transcript_path` | `string` | 세션 JSONL 트랜스크립트 파일의 절대 경로 |
| `cwd` | `string` | 훅 발생 시점의 현재 작업 디렉토리 |
| `permission_mode` | `string` | 활성 권한 모드 |
| `agent_id` | `string` | 서브에이전트에서 발생 시 식별자 |

## 동기 훅 출력 (stdout의 JSON)

블로킹 훅의 경우 종료 전에 JSON을 stdout에 씁니다:

```json
{
  "continue": true,
  "suppressOutput": false,
  "decision": "approve",
  "reason": "커맨드가 안전합니다",
  "systemMessage": "훅이 이 작업을 승인했습니다.",
  "hookSpecificOutput": {
    "hookEventName": "PreToolUse",
    "permissionDecision": "allow"
  }
}
```

## 훅 이벤트 상세

### `PreToolUse`
도구가 실행되기 직전에 발생.

**입력 필드:** `tool_name`, `tool_input`, `tool_use_id`

**종료 코드:**
| 코드 | 효과 |
|------|------|
| `0` | stdout/stderr 표시 안 됨. 훅 출력 JSON 적용 |
| `2` | stderr를 Claude에게 표시; 도구 호출 **차단** |
| 기타 | stderr를 사용자에게만 표시; 도구 호출 계속 |

**`hookSpecificOutput` 필드:**
- `permissionDecision`: `'allow'` | `'deny'` | `'ask'` — 권한 결정 재정의
- `updatedInput`: 도구가 받을 교체 입력
- `additionalContext`: 이 턴의 Claude 컨텍스트에 주입될 텍스트

---

### `PostToolUse`
도구가 성공적으로 완료된 후 발생.

**입력 필드:** `tool_name`, `tool_input`, `tool_response`, `tool_use_id`

**종료 코드:**
| 코드 | 효과 |
|------|------|
| `0` | stdout이 트랜스크립트 모드에 표시 (Ctrl+O) |
| `2` | stderr를 즉시 Claude에게 시스템 메시지로 표시 |
| 기타 | stderr를 사용자에게만 표시 |

---

### `Stop`
Claude가 응답을 종료하기 직전에 발생.

**입력 필드:** `stop_hook_active`, `last_assistant_message`

**종료 코드:**
| 코드 | 효과 |
|------|------|
| `0` | stdout/stderr 표시 안 됨 |
| `2` | stderr를 시스템 메시지로 주입; Claude **대화 계속** |
| 기타 | stderr를 사용자에게만 표시; Claude 중지 |

> 💡 Stop 훅의 종료코드 2를 사용해 Claude 출력을 확인하고 조건이 충족되지 않으면 대화를 계속하게 합니다 — 예를 들어 테스트가 여전히 실패하는 경우.

---

### `SessionStart`
세션 시작 시 발생. 초기 컨텍스트 주입이나 환경 설정에 사용.

**입력 필드:** `source` (`'startup'` | `'resume'` | `'clear'` | `'compact'`), `model`

**`hookSpecificOutput` 필드:**
- `additionalContext`: 세션 시스템 프롬프트에 주입될 컨텍스트
- `initialUserMessage`: 세션의 첫 사용자 메시지로 자동 제출
- `watchPaths`: `FileChanged` 감시기에 등록할 절대 파일 경로

---

### `UserPromptSubmit`
사용자가 프롬프트를 제출할 때 발생.

**입력 필드:** `prompt`

**종료 코드:**
| 코드 | 효과 |
|------|------|
| `0` | stdout이 Claude에게 추가 컨텍스트로 표시 |
| `2` | 처리 **차단**; 원본 프롬프트 지워짐; stderr를 사용자에게 표시 |
| 기타 | stderr를 사용자에게만 표시 |

---

### `PermissionRequest`
권한 다이얼로그가 표시될 때 발생. UI 없이 프로그래밍 방식으로 승인/거부 가능.

**종료 코드:**
| 코드 | 효과 |
|------|------|
| `0` | `hookSpecificOutput.decision`이 설정된 경우 훅 결정 적용 |
| 기타 | stderr를 사용자에게 표시; 일반 다이얼로그로 폴백 |

---

### `CwdChanged`
작업 디렉토리 변경 후 발생.

**입력 필드:** `old_cwd`, `new_cwd`

`CLAUDE_ENV_FILE` 환경 변수가 설정됨 — 환경 변수를 `export KEY=value` 줄로 써서 이후 Bash 도구 호출에 적용합니다.

---

### `FileChanged`
감시 중인 파일이 수정, 추가, 제거될 때 발생.

**입력 필드:** `file_path`, `event` (`'change'` | `'add'` | `'unlink'`)

---

## 비동기 훅

백그라운드에서 실행되는 훅은 일반 동기 출력 대신 비동기 확인을 stdout에 출력합니다:

```json
{
  "async": true,
  "asyncTimeout": 30
}
```

> ⚠️ 비동기 훅은 도구 실행을 차단하거나 컨텍스트를 주입할 수 없습니다. 에이전틱 루프를 느리게 하면 안 되는 알림, 로깅, 메트릭 같은 부작용에 사용하세요.
