3-1. Hooks 레퍼런스
hook 이벤트·설정 스키마·matcher·핸들러 유형 등 hooks 시스템 레퍼런스
Hooks 레퍼런스
Claude Code hook 이벤트, 설정 스키마, JSON 입출력 형식, 종료 코드, 비동기 hooks, HTTP hooks, prompt hooks, MCP tool hooks에 대한 레퍼런스입니다.
팁: 빠른 시작 가이드와 예제는 hooks로 워크플로 자동화하기를 참고하세요.
Hooks는 Claude Code의 생명주기 중 특정 시점에 자동으로 실행되는 사용자 정의 셸 명령, HTTP 엔드포인트 또는 LLM 프롬프트입니다. 이 레퍼런스를 사용하여 이벤트 스키마, 설정 옵션, JSON 입출력 형식, 비동기 hooks, HTTP hooks, MCP tool hooks 같은 고급 기능을 확인하세요. hooks를 처음 설정하는 경우 가이드부터 시작하는 것을 권장합니다.
Hook 생명주기
Hooks는 Claude Code 세션 중 특정 시점에 실행됩니다. 이벤트가 발생하고 matcher가 일치하면, Claude Code는 이벤트에 대한 JSON 컨텍스트를 hook 핸들러에 전달합니다. command hooks의 경우 입력은 stdin으로 전달됩니다. HTTP hooks의 경우 POST 요청 본문으로 전달됩니다. 핸들러는 입력을 검사하고, 작업을 수행한 뒤, 선택적으로 결정을 반환할 수 있습니다. 일부 이벤트는 세션당 한 번 실행되고, 다른 이벤트는 에이전트 루프 내에서 반복적으로 실행됩니다:
아래 표는 각 이벤트가 언제 실행되는지 요약합니다. Hook 이벤트 섹션에서 각 이벤트의 전체 입력 스키마와 결정 제어 옵션을 확인할 수 있습니다.
| 이벤트 | 실행 시점 |
|---|---|
SessionStart | 세션이 시작되거나 재개될 때 |
UserPromptSubmit | 프롬프트를 제출했을 때, Claude가 처리하기 전 |
PreToolUse | 도구 호출이 실행되기 전. 차단 가능 |
PermissionRequest | 권한 대화상자가 나타날 때 |
PostToolUse | 도구 호출이 성공한 후 |
PostToolUseFailure | 도구 호출이 실패한 후 |
Notification | Claude Code가 알림을 보낼 때 |
SubagentStart | 서브에이전트가 생성될 때 |
SubagentStop | 서브에이전트가 완료될 때 |
Stop | Claude가 응답을 마칠 때 |
TeammateIdle | 에이전트 팀 팀원이 유휴 상태로 전환되려 할 때 |
TaskCompleted | 작업이 완료로 표시될 때 |
InstructionsLoaded | CLAUDE.md 또는 .claude/rules/*.md 파일이 컨텍스트에 로드될 때. 세션 시작 시와 세션 중 파일이 지연 로드될 때 실행됨 |
ConfigChange | 세션 중 설정 파일이 변경될 때 |
WorktreeCreate | --worktree 또는 isolation: "worktree"를 통해 worktree가 생성될 때. 기본 git 동작을 대체함 |
WorktreeRemove | 세션 종료 시 또는 서브에이전트가 완료될 때 worktree가 제거될 때 |
PreCompact | 컨텍스트 압축 전 |
SessionEnd | 세션이 종료될 때 |
Hook 해석 과정
이러한 구성 요소들이 어떻게 맞물리는지 보기 위해, 파괴적인 셸 명령을 차단하는 PreToolUse hook을 살펴보겠습니다. 이 hook은 모든 Bash 도구 호출 전에 block-rm.sh를 실행합니다:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/block-rm.sh"
}
]
}
]
}
}
이 스크립트는 stdin에서 JSON 입력을 읽고, 명령을 추출한 후, rm -rf가 포함되어 있으면 permissionDecision을 "deny"로 반환합니다:
#!/bin/bash
# .claude/hooks/block-rm.sh
COMMAND=$(jq -r '.tool_input.command')
if echo "$COMMAND" | grep -q 'rm -rf'; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Destructive command blocked by hook"
}
}'
else
exit 0 # allow the command
fi
이제 Claude Code가 Bash "rm -rf /tmp/build"를 실행하려 한다고 가정해봅시다. 다음과 같은 과정이 진행됩니다:
Step 1: 이벤트 발생
PreToolUse 이벤트가 발생합니다. Claude Code는 도구 입력을 JSON으로 stdin을 통해 hook에 전달합니다:
{ "tool_name": "Bash", "tool_input": { "command": "rm -rf /tmp/build" }, ... }
Step 2: Matcher 확인
matcher "Bash"가 도구 이름과 일치하므로 block-rm.sh가 실행됩니다. matcher를 생략하거나 "*"를 사용하면 이벤트의 모든 발생에 대해 hook이 실행됩니다. hook이 건너뛰어지는 경우는 matcher가 정의되어 있고 일치하지 않을 때뿐입니다.
Step 3: Hook 핸들러 실행
스크립트가 입력에서 "rm -rf /tmp/build"를 추출하고 rm -rf를 발견하여 결정을 stdout으로 출력합니다:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Destructive command blocked by hook"
}
}
만약 명령이 안전한 것이었다면 (예: npm test), 스크립트는 대신 exit 0을 실행하며, 이는 Claude Code에 추가 작업 없이 도구 호출을 허용하라고 알려줍니다.
Step 4: Claude Code가 결과에 따라 동작
Claude Code가 JSON 결정을 읽고 도구 호출을 차단한 뒤 Claude에게 이유를 보여줍니다.
아래 설정 섹션에서 전체 스키마를, 각 hook 이벤트 섹션에서 명령이 받는 입력과 반환할 수 있는 출력을 확인할 수 있습니다.
설정
Hooks는 JSON 설정 파일에 정의됩니다. 설정은 세 단계의 중첩 구조를 가집니다:
PreToolUse나Stop같은 응답할 hook 이벤트를 선택합니다- "Bash 도구에 대해서만"과 같이 실행 시점을 필터링하는 matcher 그룹을 추가합니다
- 일치했을 때 실행할 하나 이상의 hook 핸들러를 정의합니다
주석이 달린 완전한 예제 워크스루는 위의 Hook 해석 과정을 참고하세요.
참고: 이 페이지는 각 단계에 대해 특정 용어를 사용합니다: 생명주기 시점은 hook 이벤트, 필터는 matcher 그룹, 실행되는 셸 명령, HTTP 엔드포인트, 프롬프트 또는 에이전트는 hook 핸들러입니다. "Hook" 단독으로는 전체 기능을 지칭합니다.
Hook 위치
hook을 정의하는 위치에 따라 적용 범위가 결정됩니다:
| 위치 | 적용 범위 | 공유 가능 여부 |
|---|---|---|
~/.claude/settings.json | 모든 프로젝트 | 아니오, 로컬 머신에서만 유효 |
.claude/settings.json | 단일 프로젝트 | 예, 저장소에 커밋 가능 |
.claude/settings.local.json | 단일 프로젝트 | 아니오, gitignore 대상 |
| 관리형 정책 설정 | 조직 전체 | 예, 관리자 제어 |
플러그인 hooks/hooks.json | 플러그인 활성화 시 | 예, 플러그인에 번들 |
| 스킬 또는 에이전트 frontmatter | 컴포넌트 활성화 중 | 예, 컴포넌트 파일에 정의 |
설정 파일 해석에 대한 자세한 내용은 settings를 참고하세요. 엔터프라이즈 관리자는 allowManagedHooksOnly를 사용하여 사용자, 프로젝트, 플러그인 hooks를 차단할 수 있습니다. Hook 설정을 참고하세요.
Matcher 패턴
matcher 필드는 hooks가 실행되는 시점을 필터링하는 정규식 문자열입니다. 모든 발생에 대해 일치시키려면 "*", "" 또는 matcher를 완전히 생략하세요. 각 이벤트 유형은 서로 다른 필드를 기준으로 매칭합니다:
| 이벤트 | matcher 필터 대상 | matcher 예시 값 |
|---|---|---|
PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest | 도구 이름 | Bash, Edit|Write, mcp__.* |
SessionStart | 세션 시작 방식 | startup, resume, clear, compact |
SessionEnd | 세션 종료 이유 | clear, logout, prompt_input_exit, bypass_permissions_disabled, other |
Notification | 알림 유형 | permission_prompt, idle_prompt, auth_success, elicitation_dialog |
SubagentStart | 에이전트 유형 | Bash, Explore, Plan, 또는 커스텀 에이전트 이름 |
PreCompact | 압축 트리거 | manual, auto |
SubagentStop | 에이전트 유형 | SubagentStart와 동일한 값 |
ConfigChange | 설정 소스 | user_settings, project_settings, local_settings, policy_settings, skills |
UserPromptSubmit, Stop, TeammateIdle, TaskCompleted, WorktreeCreate, WorktreeRemove, InstructionsLoaded | matcher 미지원 | 모든 발생 시 항상 실행 |
matcher는 정규식이므로, Edit|Write는 두 도구 중 하나와 일치하고 Notebook.*는 Notebook으로 시작하는 모든 도구와 일치합니다. matcher는 Claude Code가 stdin을 통해 hook에 보내는 JSON 입력의 필드를 기준으로 실행됩니다. 도구 이벤트의 경우 해당 필드는 tool_name입니다. 각 hook 이벤트 섹션에서 해당 이벤트의 전체 matcher 값 목록과 입력 스키마를 확인할 수 있습니다.
이 예제는 Claude가 파일을 작성하거나 편집할 때만 린팅 스크립트를 실행합니다:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "/path/to/lint-check.sh"
}
]
}
]
}
}
UserPromptSubmit, Stop, TeammateIdle, TaskCompleted, WorktreeCreate, WorktreeRemove, InstructionsLoaded는 matcher를 지원하지 않으며 모든 발생 시 항상 실행됩니다. 이러한 이벤트에 matcher 필드를 추가하면 조용히 무시됩니다.
MCP 도구 매칭
MCP 서버 도구는 도구 이벤트(PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest)에서 일반 도구로 나타나므로, 다른 도구 이름과 동일한 방식으로 매칭할 수 있습니다.
MCP 도구는 mcp__<server>__<tool> 명명 패턴을 따릅니다. 예를 들어:
mcp__memory__create_entities: Memory 서버의 엔티티 생성 도구mcp__filesystem__read_file: Filesystem 서버의 파일 읽기 도구mcp__github__search_repositories: GitHub 서버의 검색 도구
정규식 패턴을 사용하여 특정 MCP 도구 또는 도구 그룹을 대상으로 지정할 수 있습니다:
mcp__memory__.*는memory서버의 모든 도구와 일치합니다mcp__.*__write.*는 모든 서버에서 "write"를 포함하는 도구와 일치합니다
이 예제는 모든 memory 서버 작업을 로깅하고 모든 MCP 서버의 쓰기 작업을 검증합니다:
{
"hooks": {
"PreToolUse": [
{
"matcher": "mcp__memory__.*",
"hooks": [
{
"type": "command",
"command": "echo 'Memory operation initiated' >> ~/mcp-operations.log"
}
]
},
{
"matcher": "mcp__.*__write.*",
"hooks": [
{
"type": "command",
"command": "/home/user/scripts/validate-mcp-write.py"
}
]
}
]
}
}
Hook 핸들러 필드
내부 hooks 배열의 각 객체는 hook 핸들러입니다: matcher가 일치했을 때 실행되는 셸 명령, HTTP 엔드포인트, LLM 프롬프트 또는 에이전트입니다. 네 가지 유형이 있습니다:
- Command hooks (
type: "command"): 셸 명령을 실행합니다. 스크립트는 이벤트의 JSON 입력을 stdin으로 받고 종료 코드와 stdout을 통해 결과를 전달합니다. - HTTP hooks (
type: "http"): 이벤트의 JSON 입력을 HTTP POST 요청으로 URL에 전송합니다. 엔드포인트는 command hooks와 동일한 JSON 출력 형식으로 응답 본문을 통해 결과를 전달합니다. - Prompt hooks (
type: "prompt"): 단일 턴 평가를 위해 Claude 모델에 프롬프트를 전송합니다. 모델은 yes/no 결정을 JSON으로 반환합니다. 프롬프트 기반 hooks를 참고하세요. - Agent hooks (
type: "agent"): Read, Grep, Glob 같은 도구를 사용하여 조건을 검증한 후 결정을 반환하는 서브에이전트를 생성합니다. 에이전트 기반 hooks를 참고하세요.
공통 필드
이 필드들은 모든 hook 유형에 적용됩니다:
| 필드 | 필수 여부 | 설명 |
|---|---|---|
type | 예 | "command", "http", "prompt", 또는 "agent" |
timeout | 아니오 | 취소까지의 시간(초). 기본값: command 600, prompt 30, agent 60 |
statusMessage | 아니오 | hook 실행 중 표시되는 커스텀 스피너 메시지 |
once | 아니오 | true이면 세션당 한 번만 실행된 후 제거됨. 스킬 전용, 에이전트 제외. 스킬 및 에이전트의 hooks 참고 |
Command hook 필드
공통 필드 외에 command hooks는 다음 필드를 추가로 지원합니다:
| 필드 | 필수 여부 | 설명 |
|---|---|---|
command | 예 | 실행할 셸 명령 |
async | 아니오 | true이면 블로킹 없이 백그라운드에서 실행됨. 백그라운드에서 hooks 실행 참고 |
HTTP hook 필드
공통 필드 외에 HTTP hooks는 다음 필드를 추가로 지원합니다:
| 필드 | 필수 여부 | 설명 |
|---|---|---|
url | 예 | POST 요청을 보낼 URL |
headers | 아니오 | 키-값 쌍으로 된 추가 HTTP 헤더. 값은 $VAR_NAME 또는 ${VAR_NAME} 구문을 사용한 환경 변수 보간을 지원합니다. allowedEnvVars에 나열된 변수만 해석됩니다 |
allowedEnvVars | 아니오 | 헤더 값에 보간할 수 있는 환경 변수 이름 목록. 나열되지 않은 변수에 대한 참조는 빈 문자열로 대체됩니다. 환경 변수 보간이 작동하려면 필수입니다 |
Claude Code는 hook의 JSON 입력을 Content-Type: application/json과 함께 POST 요청 본문으로 전송합니다. 응답 본문은 command hooks와 동일한 JSON 출력 형식을 사용합니다.
에러 처리는 command hooks와 다릅니다: 2xx가 아닌 응답, 연결 실패, 타임아웃은 모두 실행을 계속 허용하는 비차단 에러를 발생시킵니다. 도구 호출을 차단하거나 권한을 거부하려면, decision: "block" 또는 permissionDecision: "deny"가 포함된 hookSpecificOutput을 가진 JSON 본문과 함께 2xx 응답을 반환하세요.
이 예제는 PreToolUse 이벤트를 로컬 검증 서비스에 전송하며, MY_TOKEN 환경 변수의 토큰으로 인증합니다:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "http",
"url": "http://localhost:8080/hooks/pre-tool-use",
"timeout": 30,
"headers": {
"Authorization": "Bearer $MY_TOKEN"
},
"allowedEnvVars": ["MY_TOKEN"]
}
]
}
]
}
}
참고: HTTP hooks는 설정 JSON을 직접 편집하여 구성해야 합니다.
/hooks인터랙티브 메뉴는 command hooks 추가만 지원합니다.
Prompt 및 agent hook 필드
공통 필드 외에 prompt 및 agent hooks는 다음 필드를 추가로 지원합니다:
| 필드 | 필수 여부 | 설명 |
|---|---|---|
prompt | 예 | 모델에 보낼 프롬프트 텍스트. hook 입력 JSON의 플레이스홀더로 $ARGUMENTS를 사용합니다 |
model | 아니오 | 평가에 사용할 모델. 기본값은 빠른 모델 |
일치하는 모든 hooks는 병렬로 실행되며, 동일한 핸들러는 자동으로 중복 제거됩니다. Command hooks는 명령 문자열로, HTTP hooks는 URL로 중복 제거됩니다. 핸들러는 현재 디렉토리에서 Claude Code의 환경으로 실행됩니다. $CLAUDE_CODE_REMOTE 환경 변수는 원격 웹 환경에서 "true"로 설정되며, 로컬 CLI에서는 설정되지 않습니다.
경로로 스크립트 참조
작업 디렉토리에 관계없이 프로젝트 또는 플러그인 루트를 기준으로 hook 스크립트를 참조하려면 환경 변수를 사용하세요:
$CLAUDE_PROJECT_DIR: 프로젝트 루트. 공백이 포함된 경로를 처리하려면 따옴표로 감싸세요.${CLAUDE_PLUGIN_ROOT}: 플러그인의 루트 디렉토리, 플러그인에 번들된 스크립트용.
프로젝트 스크립트
이 예제는 $CLAUDE_PROJECT_DIR을 사용하여 Write 또는 Edit 도구 호출 후 프로젝트의 .claude/hooks/ 디렉토리에서 스타일 검사기를 실행합니다:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-style.sh"
}
]
}
]
}
}
플러그인 스크립트
플러그인 hooks는 hooks/hooks.json에 선택적 최상위 description 필드와 함께 정의합니다. 플러그인이 활성화되면, 해당 hooks가 사용자 및 프로젝트 hooks와 병합됩니다.
이 예제는 플러그인에 번들된 포매팅 스크립트를 실행합니다:
{
"description": "Automatic code formatting",
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "${CLAUDE_PLUGIN_ROOT}/scripts/format.sh",
"timeout": 30
}
]
}
]
}
}
플러그인 hooks 생성에 대한 자세한 내용은 플러그인 컴포넌트 레퍼런스를 참고하세요.
스킬 및 에이전트의 Hooks
설정 파일과 플러그인 외에도, hooks는 frontmatter를 사용하여 스킬과 서브에이전트에 직접 정의할 수 있습니다. 이러한 hooks는 컴포넌트의 생명주기에 한정되며, 해당 컴포넌트가 활성화된 경우에만 실행됩니다.
모든 hook 이벤트가 지원됩니다. 서브에이전트의 경우, Stop hooks는 서브에이전트가 완료될 때 발생하는 이벤트인 SubagentStop으로 자동 변환됩니다.
Hooks는 설정 기반 hooks와 동일한 구성 형식을 사용하지만, 컴포넌트의 수명에 한정되며 완료 시 정리됩니다.
이 스킬은 각 Bash 명령 전에 보안 검증 스크립트를 실행하는 PreToolUse hook을 정의합니다:
---
name: secure-operations
description: Perform operations with security checks
hooks:
PreToolUse:
- matcher: "Bash"
hooks:
- type: command
command: "./scripts/security-check.sh"
---
에이전트도 YAML frontmatter에서 동일한 형식을 사용합니다.
/hooks 메뉴
Claude Code에서 /hooks를 입력하면 인터랙티브 hooks 관리자가 열리며, 설정 파일을 직접 편집하지 않고도 hooks를 조회, 추가, 삭제할 수 있습니다. 단계별 안내는 가이드의 첫 번째 hook 설정하기를 참고하세요.
메뉴의 각 hook에는 출처를 나타내는 대괄호 접두사가 표시됩니다:
[User]:~/.claude/settings.json에서 정의[Project]:.claude/settings.json에서 정의[Local]:.claude/settings.local.json에서 정의[Plugin]: 플러그인의hooks/hooks.json에서 정의, 읽기 전용
Hooks 비활성화 또는 제거
hook을 제거하려면 설정 JSON 파일에서 해당 항목을 삭제하거나, /hooks 메뉴에서 hook을 선택하여 삭제하세요.
제거하지 않고 모든 hooks를 일시적으로 비활성화하려면, 설정 파일에서 "disableAllHooks": true를 설정하거나 /hooks 메뉴의 토글을 사용하세요. 구성에 유지하면서 개별 hook만 비활성화하는 방법은 없습니다.
disableAllHooks 설정은 관리형 설정 계층 구조를 따릅니다. 관리자가 관리형 정책 설정을 통해 hooks를 구성한 경우, 사용자, 프로젝트 또는 로컬 설정에서 설정한 disableAllHooks로는 해당 관리형 hooks를 비활성화할 수 없습니다. 관리형 설정 수준에서 설정한 disableAllHooks만이 관리형 hooks를 비활성화할 수 있습니다.
설정 파일에서 hooks를 직접 편집해도 즉시 적용되지 않습니다. Claude Code는 시작 시 hooks의 스냅샷을 캡처하고 세션 전체에서 이를 사용합니다. 이는 악의적이거나 실수로 인한 hook 수정이 검토 없이 세션 중간에 적용되는 것을 방지합니다. hooks가 외부에서 수정되면, Claude Code가 경고를 표시하며 변경 사항이 적용되기 전에 /hooks 메뉴에서 검토를 요구합니다.