Claude Code - Hooks
TMT클로드 코드의 동작을 사용자 정의 셸 명령어로 확장 및 맞춤화하기
소개
클로드 코드 훅은 클로드 코드의 라이프사이클에서 다양한 시점에 실행되는 사용자 정의 셸 명령어입니다. 훅을 사용하면 LLM이 임의로 실행 여부를 결정하는 대신, 항상 특정 동작이 실행되도록 결정론적으로 제어할 수 있습니다.
예시 사용 사례는 다음과 같습니다:
- 알림: 클로드 코드가 입력을 기다리거나 무언가를 실행하기 전에 알림을 받는 방식을 맞춤화합니다.
- 자동 포매팅: 파일이 수정될 때마다 .ts 파일에는 prettier, .go 파일에는 gofmt 등을 실행합니다.
- 로깅: 규정 준수 또는 디버깅을 위해 실행된 모든 명령어를 추적 및 집계합니다.
- 피드백: 클로드 코드가 코드베이스 규칙을 따르지 않는 코드를 생성했을 때 자동 피드백을 제공합니다.
- 맞춤 권한: 프로덕션 파일이나 민감한 디렉터리에 대한 수정 작업을 차단합니다.
이러한 규칙을 프롬프트 지침이 아닌 훅으로 작성하면, 제안이 아닌 앱 수준의 코드로 변환되어 항상 기대한 대로 실행됩니다.
[!Warning] 훅은 확인 없이 전체 사용자 권한으로 셸 명령어를 실행합니다. 훅의 안전성과 보안은 사용자에게 전적으로 책임이 있습니다. 훅 사용으로 인한 데이터 손실이나 시스템 손상에 대해 Anthropic은 책임지지 않습니다. 보안 고려사항을 반드시 검토하세요.
빠른 시작
이 빠른 시작에서는 클로드 코드가 실행하는 셸 명령어를 기록하는 훅을 추가합니다.
빠른 시작 전제조건: 커맨드라인에서 JSON 처리를 위해 jq
를 설치하세요.
1단계: 훅 구성 열기
/hooks
슬래시 명령어를 실행하고 PreToolUse
훅 이벤트를 선택하세요.
PreToolUse
훅은 도구 호출 전에 실행되며, 차단하면서 클로드에게 어떻게 다르게 해야 하는지 피드백을 제공할 수 있습니다.
2단계: 매처 추가
+ Add new matcher…
를 선택하여 Bash 도구 호출에만 훅이 실행되도록 합니다.
매처에 Bash
를 입력하세요.
3단계: 훅 추가
+ Add new hook…
를 선택하고 다음 명령어를 입력하세요:
jq -r '"\(.tool_input.command) - \(.tool_input.description // "No description")"' >> ~/.claude/bash-command-log.txt
4단계: 구성 저장
저장 위치로 User settings
를 선택하세요. 홈 디렉터리에 기록하므로 이 훅은 현재 프로젝트뿐만 아니라 모든 프로젝트에 적용됩니다.
Esc를 눌러 REPL로 돌아가면 훅이 등록된 것입니다!
5단계: 훅 확인
다시 /hooks
를 실행하거나 ~/.claude/settings.json
에서 구성을 확인하세요:
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '\"\\(.tool_input.command) - \\(.tool_input.description // \"No description\")\"' >> ~/.claude/bash-command-log.txt"
}
]
}
]
}
구성
클로드 코드 훅은 다음 설정 파일에 구성됩니다:
~/.claude/settings.json
- 사용자 설정.claude/settings.json
- 프로젝트 설정.claude/settings.local.json
- 로컬 프로젝트 설정(커밋되지 않음)- 엔터프라이즈 관리 정책 설정
구조
훅은 매처별로 구성되며, 각 매처에는 여러 훅이 포함될 수 있습니다:
{
"hooks": {
"EventName": [
{
"matcher": "ToolPattern",
"hooks": [
{
"type": "command",
"command": "your-command-here"
}
]
}
]
}
}
- matcher: 도구 이름에 매칭되는 패턴(
PreToolUse
,PostToolUse
에서만 적용)- 단순 문자열:
Write
는 Write 도구에만 매칭 - 정규식 지원:
Edit|Write
또는Notebook.*
- 생략하거나 빈 문자열이면 해당 이벤트에 대해 모두 실행
- 단순 문자열:
- hooks: 패턴이 매칭될 때 실행할 명령어 배열
type
: 현재는"command"
만 지원command
: 실행할 bash 명령어
훅 이벤트
PreToolUse
클로드가 도구 파라미터를 생성한 후, 도구 호출을 처리하기 전에 실행됩니다.
주요 매처 예시:
Task
- 에이전트 작업Bash
- 셸 명령어Glob
- 파일 패턴 매칭Grep
- 내용 검색Read
- 파일 읽기Edit
,MultiEdit
- 파일 편집Write
- 파일 쓰기WebFetch
,WebSearch
- 웹 작업
PostToolUse
도구가 성공적으로 완료된 직후 실행됩니다.
PreToolUse와 동일한 매처 값을 인식합니다.
Notification
클로드 코드가 알림을 보낼 때 실행됩니다.
Stop
클로드 코드가 응답을 마쳤을 때 실행됩니다.
훅 입력
훅은 세션 정보와 이벤트별 데이터를 포함한 JSON을 stdin으로 전달받습니다:
{
// 공통 필드
session_id: string
transcript_path: string // 대화 JSON 경로
// 이벤트별 필드
...
}
PreToolUse 입력
tool_input
의 정확한 스키마는 도구에 따라 다릅니다.
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
}
}
PostToolUse 입력
tool_input
및 tool_response
의 정확한 스키마는 도구에 따라 다릅니다.
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"tool_name": "Write",
"tool_input": {
"file_path": "/path/to/file.txt",
"content": "file content"
},
"tool_response": {
"filePath": "/path/to/file.txt",
"success": true
}
}
Notification 입력
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"message": "Task completed successfully",
"title": "Claude Code"
}
Stop 입력
stop_hook_active
가 true이면 클로드 코드가 이미 stop 훅의 결과로 계속 실행 중임을 의미합니다. 이 값을 확인하거나 트랜스크립트를 처리하여 클로드 코드가 무한 실행되는 것을 방지하세요.
{
"session_id": "abc123",
"transcript_path": "~/.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"stop_hook_active": true
}
훅 출력
훅은 클로드 코드에 결과를 반환하는 두 가지 방법이 있습니다. 출력은 차단 여부 및 클로드와 사용자에게 보여줄 피드백을 전달합니다.
간단: 종료 코드
훅은 종료 코드, stdout, stderr로 상태를 전달합니다:
- 종료 코드 0: 성공.
stdout
은 transcript 모드(CTRL-R)에서 사용자에게 표시됨 - 종료 코드 2: 차단 에러.
stderr
는 클로드에게 자동으로 피드백됨. 훅 이벤트별 동작은 아래 참조 - 기타 종료 코드: 비차단 에러.
stderr
는 사용자에게 표시되고 실행 계속
종료 코드 2 동작
훅 이벤트 | 동작 |
---|---|
PreToolUse | 도구 호출 차단, 에러를 클로드에게 표시 |
PostToolUse | 에러를 클로드에게 표시(도구는 이미 실행됨) |
Notification | 해당 없음, stderr는 사용자에게만 표시 |
Stop | 중단 차단, 에러를 클로드에게 표시 |
고급: JSON 출력
더 정교한 제어를 위해 훅은 stdout
에 구조화된 JSON을 반환할 수 있습니다:
공통 JSON 필드
모든 훅 유형에서 다음 선택적 필드를 포함할 수 있습니다:
{
"continue": true, // 훅 실행 후 클로드가 계속 진행할지 여부(기본값: true)
"stopReason": "string" // continue가 false일 때 사용자에게 보여줄 메시지(클로드에게는 표시되지 않음)
"suppressOutput": true, // stdout을 transcript 모드에서 숨김(기본값: false)
}
continue
가 false이면 훅 실행 후 클로드가 더 이상 처리하지 않습니다.
PreToolUse
에서는"decision": "block"
과 다릅니다. 이는 특정 도구 호출만 차단하고 클로드에게 자동 피드백을 제공합니다.PostToolUse
에서는"decision": "block"
과 다릅니다. 이는 클로드에게 자동 피드백만 제공합니다.Stop
에서는"decision": "block"
출력보다 우선합니다.- 모든 경우에
"continue" = false
가"decision": "block"
출력보다 우선 적용됩니다.
stopReason
은 continue
와 함께 사용되며, 사용자에게만 표시되는 이유 메시지입니다.
PreToolUse 결정 제어
PreToolUse
훅은 도구 호출의 진행 여부를 제어할 수 있습니다.
- “approve”는 권한 시스템을 우회합니다.
reason
은 사용자에게만 표시되고 클로드에게는 표시되지 않습니다. - “block”은 도구 호출을 차단합니다.
reason
은 클로드에게 표시됩니다. undefined
는 기존 권한 플로우를 따릅니다.reason
은 무시됩니다.
{
"decision": "approve" | "block" | undefined,
"reason": "결정에 대한 설명"
}
PostToolUse 결정 제어
PostToolUse
훅은 도구 호출의 진행 여부를 제어할 수 있습니다.
- “block”은 자동으로 클로드에게
reason
을 전달합니다. undefined
는 아무 동작도 하지 않습니다.reason
은 무시됩니다.
{
"decision": "block" | undefined,
"reason": "결정에 대한 설명"
}
Stop 결정 제어
Stop
훅은 클로드의 중단 여부를 제어할 수 있습니다.
- “block”은 클로드의 중단을 막습니다. 반드시
reason
을 입력해야 하며, 클로드가 어떻게 진행해야 할지 알 수 있도록 합니다. undefined
는 클로드의 중단을 허용합니다.reason
은 무시됩니다.
{
"decision": "block" | undefined,
"reason": "클로드가 중단을 막을 때 제공해야 하는 설명"
}
JSON 출력 예시: Bash 명령어 검증
#!/usr/bin/env python3
import json
import re
import sys
# 정규식 패턴과 메시지의 리스트로 검증 규칙 정의
VALIDATION_RULES = [
(
r"\bgrep\b(?!.*\|)",
"더 나은 성능과 기능을 위해 'grep' 대신 'rg'(ripgrep)를 사용하세요.",
),
(
r"\bfind\s+\S+\s+-name\b",
"'find -name' 대신 'rg --files | rg pattern' 또는 'rg --files -g pattern'을 사용하세요.",
),
]
def validate_command(command: str) -> list[str]:
issues = []
for pattern, message in VALIDATION_RULES:
if re.search(pattern, command):
issues.append(message)
return issues
try:
input_data = json.load(sys.stdin)
except json.JSONDecodeError as e:
print(f"Error: Invalid JSON input: {e}", file=sys.stderr)
sys.exit(1)
tool_name = input_data.get("tool_name", "")
tool_input = input_data.get("tool_input", {})
command = tool_input.get("command", "")
if tool_name != "Bash" or not command:
sys.exit(1)
# 명령어 검증
issues = validate_command(command)
if issues:
for message in issues:
print(f"• {message}", file=sys.stderr)
# 종료 코드 2는 도구 호출을 차단하고 stderr를 클로드에게 표시
sys.exit(2)
Stop 결정 제어
Stop
훅은 도구 실행을 제어할 수 있습니다:
{
"decision": "approve" | "block",
"reason": "사람이 읽을 수 있는 설명"
}
MCP 도구와 함께 사용하기
클로드 코드 훅은 Model Context Protocol(MCP) 도구와도 원활하게 작동합니다. MCP 서버가 도구를 제공하면, 훅에서 매칭할 수 있는 특별한 네이밍 패턴으로 나타납니다.
MCP 도구 네이밍
MCP 도구는 mcp__<server>__<tool>
패턴을 따릅니다. 예시:
mcp__memory__create_entities
- 메모리 서버의 엔터티 생성 도구mcp__filesystem__read_file
- 파일시스템 서버의 파일 읽기 도구mcp__github__search_repositories
- GitHub 서버의 검색 도구
MCP 도구에 대한 훅 구성
특정 MCP 도구 또는 전체 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"
}
]
}
]
}
}
예시
코드 포매팅
파일이 수정된 후 자동으로 코드를 포맷합니다:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "/home/user/scripts/format-code.sh"
}
]
}
]
}
}
알림
클로드 코드가 권한을 요청하거나 프롬프트 입력이 유휴 상태가 되었을 때 전송되는 알림을 맞춤화합니다.
{
"hooks": {
"Notification": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "python3 ~/my_custom_notifier.py"
}
]
}
]
}
}
보안 고려사항
면책 조항
자신의 책임 하에 사용하세요: 클로드 코드 훅은 시스템에서 임의의 셸 명령어를 자동으로 실행합니다. 훅을 사용함으로써 다음 사항에 동의합니다:
- 구성한 명령어에 대한 전적인 책임이 사용자에게 있음
- 훅은 사용자 계정이 접근 가능한 모든 파일을 수정, 삭제 또는 접근할 수 있음
- 악의적이거나 잘못 작성된 훅은 데이터 손실 또는 시스템 손상을 초래할 수 있음
- Anthropic은 훅 사용으로 인한 어떠한 손해에 대해서도 보증하지 않으며 책임지지 않음
- 프로덕션 환경에서 사용하기 전에 반드시 안전한 환경에서 훅을 충분히 테스트해야 함
훅 명령어를 추가하기 전에 항상 내용을 검토하고 이해하세요.
보안 모범 사례
더 안전한 훅을 작성하기 위한 주요 실천 사항은 다음과 같습니다:
- 입력값 검증 및 정제 - 입력 데이터를 무조건 신뢰하지 마세요
- 항상 셸 변수에 따옴표 사용 -
$VAR
대신"$VAR"
사용 - 경로 이동 차단 - 파일 경로에
..
이 포함되어 있는지 확인 - 절대 경로 사용 - 스크립트에 전체 경로 지정
- 민감한 파일 건너뛰기 -
.env
,.git/
, 키 등은 피하세요
구성 안전성
설정 파일에서 훅을 직접 수정해도 즉시 반영되지 않습니다. 클로드 코드는:
- 시작 시 훅의 스냅샷을 캡처
- 세션 내내 이 스냅샷을 사용
- 외부에서 훅이 수정되면 경고 표시
- 변경 사항을 적용하려면
/hooks
메뉴에서 검토 필요
이로써 악의적인 훅 수정이 현재 세션에 영향을 주지 않도록 방지합니다.
훅 실행 세부사항
- 타임아웃: 60초 실행 제한
- 병렬 실행: 매칭되는 모든 훅이 병렬로 실행됨
- 환경: 현재 디렉터리 및 클로드 코드의 환경에서 실행
- 입력: stdin을 통한 JSON
- 출력:
- PreToolUse/PostToolUse/Stop: 진행 상황이 transcript(CTRL-R)에 표시
- Notification: 디버그(
--debug
)에만 기록
디버깅
훅을 문제 해결하려면:
/hooks
메뉴에서 구성이 표시되는지 확인- 설정 파일이 유효한 JSON인지 확인
- 명령어를 수동으로 테스트
- 종료 코드 확인
- stdout 및 stderr 포맷 기대치 확인
- 올바른 따옴표 이스케이프 사용 확인
진행 메시지는 transcript 모드(CTRL-R)에 표시되며 다음을 보여줍니다:
- 어떤 훅이 실행 중인지
- 실행되는 명령어
- 성공/실패 상태
- 출력 또는 에러 메시지