Claude Code에서 “파일을 수정한 뒤 반드시 포매터를 실행해”라고 프롬프트로 지시하면 어떤 결과가 나올까요? 처음에는 지시를 잘 따르지만, 세션이 길어지거나 작업이 복잡해지면 이를 지키지 않을 때가 있습니다. “rm -rf는 절대 쓰지 마”라고 지시해도 리팩토링 도중에 빌드 디렉터리를 정리하며 이를 실행하는 상황도 발생하죠. 또 새로운 세션에서 이전 세션과 동일한 작업을 진행하려면 같은 지시를 처음부터 반복해야 하는 번거로움도 있습니다.
이는 LLM의 동작 방식 때문인데요. 세션이 길어지면 초기 지시가 컨텍스트에서 밀려나 LLM이 이를 참고하지 못할 수 있습니다. 아울러 LLM은 지시를 반드시 따르도록 설계되지는 않았고요. 가장 적절한 응답을 확률적으로 생성하도록 만들어졌죠. 또 세션이 바뀌면 이전 세션의 지시가 사라져 매번 동일한 지시를 다시 전달해야 하고요. 이렇듯 프롬프트만으로는 LLM이 모든 상황에서 지시를 일관되게 따르도록 보장하기 어렵습니다.
그러나 Hooks를 사용하면 이 문제를 해결할 수 있죠. Hooks는 Claude Code에서 파일 수정, 명령 실행 등 특정 이벤트가 발생할 때 설정 파일에 정의한 동작을 자동으로 실행하는 기능인데요. Claude의 확률적 판단이 아닌, 코드로 정의한 결정론적 규칙에 따라 동작합니다. 이에 세션이 길어지거나 전환돼도, 작업이 복잡해져도, 프롬프트 지시 없이 원하는 동작을 매번 일관되게 실행하도록 돕죠.
이 글에서는 Hooks의 개념과 구조, 유형, 실전 패턴과 사용법을 살펴보겠습니다.
Hooks 개요
Hooks의 기본 개념과 주요 특징을 먼저 살펴보고, 이어서 Hook을 구성하는 세 가지 요소(이벤트, 매처, 핸들러)와 네 가지 유형을 알아보겠습니다.

개념
Hooks는 Claude Code의 라이프사이클에서 특정 이벤트가 발생할 때, 설정 파일에 정의한 동작을 실행하는 기능입니다. 예를 들어, “Claude가 파일을 수정하면 포매터를 실행한다”, “Claude가 셸 명령을 실행하려 하면 위험 여부를 먼저 검사한다”와 같은 규칙을 정의할 수 있죠.
Hooks의 핵심은 ‘조건이 충족되면 예외 없이 항상 실행된다’는 점인데요. 앞서 언급했듯 프롬프트 지시는 세션이 길어지면 컨텍스트에서 밀려나거나, LLM의 확률적 생성 특성 때문에 지켜지지 않을 수 있습니다. 그러나 Hooks는 프롬프트가 아닌 설정 파일(.claude/settings.json)에 JSON 형태로 규칙을 정의하는데요. 이로써 세션 길이나 작업 복잡도와 관계 없이 이벤트가 발생하면 항상 동일하게 작동하죠.
Hooks의 주요 특징은 다음과 같습니다.
-
Claude의 작업 흐름과 별도 동작: Hooks는 Claude가 코드를 분석하고 작성하는 과정(에이전틱 루프)과 독립적으로 실행됩니다. 예를 들어,
PostToolUseHook으로 포매터를 실행하면, 이는 Claude의 사고 과정에 포함되지 않고 외부에서 별도로 처리됩니다. 따라서 Hook이 별도의 출력을 반환하지 않는 한 컨텍스트 윈도우를 소비하지 않습니다. -
프로젝트 수준과 개인 수준 구분 설정 가능: 설정 파일의 위치에 따라 Hook의 적용 범위는 달라집니다.
설정 파일 위치 적용 범위 팀 공유 .claude/settings.json(프로젝트)해당 프로젝트에서만 적용 리포지터리에 커밋하면 팀 전체가 동일한 Hook을 사용 ~/.claude/settings.json(사용자)본인의 모든 프로젝트에 적용 본인에게만 적용, 팀과 공유되지 않음 팀 전체가 따라야 하는 규칙(위험 명령 차단, 자동 포매팅 등)은 프로젝트 설정에, 개인 취향에 해당하는 설정(데스크톱 알림 등)은 사용자 설정에 저장합니다.
CLAUDE.md와 비교하면 Hooks의 특징을 더 명확히 파악할 수 있는데요.
| 구분 | CLAUDE.md | Hooks |
|---|---|---|
| 성격 | Claude에게 전달하는 참고 지침 | 이벤트 발생 시 실행되는 결정론적 규칙 |
| 실행 보장 여부 | Claude가 참고하지만 반드시 따르지는 않음 | 이벤트가 발생하면 항상 실행됨 |
| 적합한 용도 | 코딩 컨벤션, 아키텍처 방향, 프로젝트 맥락 공유 | 포매팅 자동 실행, 위험 명령 차단, 감사 로그 기록 |
CLAUDE.md와 Hooks는 상호 보완적인 관계입니다. CLAUDE.md에는 Claude가 맥락을 이해하는 데 필요한 정보를 담고, Hooks에는 매번 반드시 실행돼야 하는 동작을 정의하죠. Anthropic은 ‘Claude가 이미 올바르게 수행하는 것은 CLAUDE.md에서 삭제하거나 Hook으로 전환하라’고 권장합니다.
구조
Hook은 세 가지 요소로 구성됩니다. 이벤트(언제 실행하는가?), 매처(어떤 도구에 실행하는가?), 핸들러(무엇 을 실행하는가?)가 그 내용입니다.
이벤트: 언제 실행하는가?
이벤트는 Claude Code의 작업 흐름에서 Hook이 실행되는 시점을 지정합니다. 주요 이벤트는 다음과 같습니다.
| 이벤트 | 실행 시점 | 활용 사례 |
|---|---|---|
PreToolUse | Claude가 도구를 실행하기 전 | 위험한 명령 차단, 파일 수정 사전 검증 |
PostToolUse | Claude가 도구를 실행한 후 | 자동 포매팅, 린팅, 테스트 실행 |
UserPromptSubmit | 사용자가 프롬프트를 제출할 때 | 민감 정보 포함 여부 검사, 컨텍스트 자동 주입 |
Notification | Claude가 사용자 입력이나 권한 승인을 기다릴 때 | 데스크톱 알림, Slack 알림 전송 |
Stop | Claude가 응답을 완료했을 때 | 최종 결과 검증, 완료 알림 |
SessionStart/SessionEnd | 세션 시작/종료 시 | 환경 설정, 정리 작업 |
이 중 가장 자주 사용하는 이벤트는 PreToolUse와 PostToolUse인데요. PreToolUse는 도구 실행 전에 작동해 위험한 작업을 차단하는 데 도움이 됩니다. PostToolUse는 도구 실행 후에 작동해 포매팅이나 린팅 같은 후처리에 적합하죠.
하나의 요청이 처리되는 과정에서 이벤트의 실행 순서를 흐름으로 나타내면 다음과 같습니다.

Claude는 하나의 요청을 처리하면서 도구를 여러 번 호출할 수 있습니다. 예를 들어, “이 파일을 수정하고 테스트를 실행해”라고 요청하면 Claude는 파일 읽기, 파일 편집, 테스트 실행 등 여러 도구를 순서대로 호출하는데요. 이때 도구 호출마다 PreToolUse → 도구 실행 → PostToolUse 사이클이 반복되죠. Stop은 Claude가 응답을 완료할 때 실행되고요.
SessionStart와 SessionEnd는 세션 시작·종료 시 각각 한 번씩 실행되며, Notification은 Claude가 사용자 입력이나 권한 승인을 기다릴 때 발생합니다.
매처: 어떤 도구에 실행하는가?
매처는 Hook이 반응할 도구를 지정하는 필터입니다. 정규식 형태로 작성하며, 주요 예시는 다음과 같습니다.
| 매처 | 의미 |
|---|---|
Bash | Bash 도구를 사용할 때만 실행 |
| `Write | Edit` |
* 또는 빈 문자열 | 모두 도구에 실행 |
매처는 대소문자를 구분합니다. 예를 들어, bash로 설정하면 Bash 도구와 매칭되지 않아 주의해야 합니다.
매처는 PreToolUse, PostToolUse 등 도구 관련 이벤트에 적용됩니다. UserPromptSubmit이나 Stop 등 일부 이벤트는 매처를 지원하지 않고, 해당 이벤트가 발생하면 실행됩니다.
핸들러: 무엇을 실행하는가?
핸들러는 이벤트가 발생하고 매처 조건이 충족됐을 때 실제로 실행되는 동작입니다. 핸들러에는 네 가지 유형이 있으며, 각 유형은 다음 섹션에서 자세히 다루겠습니다.
이벤트, 매처, 핸들러를 조합한 settings.json 설정의 기본 구조는 다음과 같습니다.
{
"hooks": {
"이벤트 이름": [
{
"matcher": "매처 패턴",
"hooks": [
{
"type": "핸들러 유형",
"command": "실행할 명령"
}
]
}
]
}
}
앞서 살펴본 이벤트(PreToolUse, PostToolUse 등), 매처(Bash, Write|Edit 등), 핸들러 유형(command, http, prompt, agent)이 각 자리에 들어갑니다. 위 예시는 command 유형 기준이며, 유형에 따라 실행 내용을 지정하는 필드가 달라집니다. 예를 들어, http 유형은 url 필드를, prompt와 agent 유형은 prompt 필드를 사용합니다.
유형
핸들러에는 command, http, prompt, agent 네 가지 유형이 있습니다. 각 유형이 무엇이고, 어떤 상황에서 사용하기에 적합한지 살펴보겠습니다.

command 유형
command 유형은 지정한 셸 명령을 실행하는 가장 기본적인 형태입니다. Claude Code는 이벤트를 탐지하면 설정된 셸 명령을 실행하고, 셸 명령이 반환하는 결과 코드에 따라 작업을 계속 진행하거나 중단하죠.
결과 코드는 숫자 코드로 전달되는데요. 0을 반환하면 Claude Code가 ‘문제없음’으로 판단해 작업을 계속 진행하고, 2를 반환하면 ‘차단’으로 판단해 해당 작업을 중단합니다. Hook 스크립트에 차단 사유를 미리 포함해 두면 Claude Code가 이를 Claude에게 전달하고요. Claude는 사유를 확인한 뒤 대안을 제안합니다.
command 유형은 포매터 실행, 린터 실행, 위험한 명령 차단, 로그 기록처럼 규칙이 명확하고 셸 명령으로 표현할 수 있는 작업에 적합합니다.
http 유형
http 유형은 Hook 이벤트 정보를 외부 서버로 전송하는 유형입니다. 이벤트가 발생하면 지정한 URL로 이벤트 정보를 전송하고, 서버의 응답에 따라 작업을 계속할지 차단할지 결정하죠. 단, 서버 오류나 연결 실패 시에는 작업을 차단하지 않고 실행을 계속합니다.
command 유형은 각 사용자의 로컬 환경에서만 동작하지만, http 유형은 외부 서버와 통신할 수 있는데요. 이로써 팀 전체에 동일한 정책을 적용하는 중앙 정책 서버를 구축하거나, Hook 이벤트를 실시간으로 모니터링하는 대시보드를 연동하거나, Slack 같은 외부 서비스로 알림을 보내는 등 로컬 환경을 넘어서는 자동화가 필요할 때 유용합니다.
prompt 유형
prompt 유형은 Hook 이벤트의 판단을 AI 모델에 요청하는 유형입니다. 이벤트가 발생하면 Claude에 프롬프트를 보내고, 모델이 상황을 평가한 뒤 해당 작업의 ‘허용’ 또는 ‘차단’ 결정을 반환하죠.
command나 http 유형은 파일 이름, 명령어 패턴처럼 명확한 규칙을 코드로 작성해야 하는데요. 그러나 ‘이 변경이 보안에 영향을 미치는가?’, ‘이 코드가 인증 관련 코드를 수정하는가?’처럼 맥락에 따라 달라지는 판단은 코드로 작성하기 어렵죠. 이런 판단이 필요할 때 prompt 유형을 사용하면 좋습니다.
다만, prompt 유형은 단일 턴으로 작동해 전달받은 이벤트 정보만으로 판단하고요. 파일 내용을 직접 읽거나 관련 코드를 탐색하지는 않습니다.
agent 유형
agent 유형은 코드베이스를 직접 탐색해 해당 작업의 허용 또는 차단을 판단하는 유형입니다. Hook 이벤트가 발생하면 파일을 읽고(Read), 코드를 검색하고(Grep), 파일 목록을 조회하는(Glob) 도구를 사용하는 서브에이전트를 생성해 변경 사항의 영향 범위를 파악한 뒤 판단을 내리죠.
prompt 유형이 전달받은 정보만으로 즉시 판단하는 것과 달리 agent 유형은 관련 파일을 직접 찾아보고 판단하는데요. 예를 들어, 인증 모듈의 함수를 수정할 때 “이 함수를 호출하는 다른 파일이 있는가?”를 실제로 검색해 영향 범위를 확인할 수 있습니다.
단, 코드를 탐색하는 만큼 실행 시간은 길어집니다. 기본 타임아웃이 60초로, prompt 유형(30초)보다 두 배 더 길죠. 모든 파일 수정에 적용하면 작업 흐름이 느려지는데요. 변경 사항이 다른 파일에 미치는 영향을 확인해야 하거나, 아키텍처 규칙 준수 여부를 코드 수준에서 검증해야 하는 등 코드 탐색이 필요한 고위험 변경에 한정해 사용하는 걸 권장합니다.
실전 패턴과 사용법
지금까지 살펴본 핸들러 유형을 실제로 적용해 보겠습니다. 각 사용 패턴은 상황, 설정 방법, 동작 확인 순서로 구성했습니다.
1. 파일 편집 후 자동 포매팅 (PostToolUse + command)
상황
Claude가 코드를 작성하거나 수정한 뒤, 매번 포매터(Prettier, Black 등)를 수동으로 실행하는 대신 자동으로 실행되도록 설정할 수 있습니다.
설정 방법
이 예제는 프로젝트에 Prettier가 설치돼 있다고 가정합니다.
-
프로젝트의
.claude/settings.json파일을 열거나, 파일이 없으면 새로 생성합니다. -
다음 내용을 추가합니다.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$CLAUDE_TOOL_INPUT_FILE_PATH\""
}
]
}
]
}
}PostToolUse: Claude가 도구를 실행한 후에 Hook이 작동합니다.Write|Edit: 파일 쓰기 또는 편집 도구를 사용했을 때만 Hook이 실행됩니다.$CLAUDE_TOOL_INPUT_FILE_PATH: Claude가 수정한 파일의 경로가 자동으로 입력됩니다.
-
설정을 저장한 뒤 Claude Code를 실행합니다.
동작 확인
-
Claude에게 포매팅되지 않은 코드로 파일을 생성하도록 요청합니다.
Claude Code에서 포매팅되지 않은 코드로 파일 생성을 요청하는 화면
-
Claude가
Write도구로 파일을 생성하면,PostToolUseHook이 Prettier를 자동으로 실행합니다.Claude가
Write도구로 포매팅되지 않은 코드를 파일에 작성한 화면
-
파일 내용을 확인하면 포매팅이 적용된 결과를 볼 수 있습니다.

PostToolUseHook이 Prettier를 자동 실행해 포매팅이 적용된 파일 내용
2. 위험한 명령 사전 차단(PreToolUse + command)
상황
Claude가 리팩토링이나 정리 작업 중에 rm -rf와 같은 위험한 명령을 실행하지 못하도록 사전에 차단할 수 있습니다.
설정 방법
-
위험한 명령을 검사하는 스크립트 파일을 프로젝트에 생성합니다.
.claude/hooks/block-dangerous.sh경로에 다음 내용을 저장합니다.#!/bin/bash
# .claude/hooks/block-dangerous.sh
# Claude가 실행하려는 명령을 읽어옵니다
COMMAND=$(cat | jq -r '.tool_input.command')
# 위험한 패턴 목록
DANGEROUS_PATTERNS="rm -rf|git push --force|git push -f"
# 위험한 패턴이 포함되어 있으면 차단합니다
if echo "$COMMAND" | grep -qE "$DANGEROUS_PATTERNS"; then
echo "위험한 명령이 감지되어 차단했습니다: $COMMAND" >&2
exit 2 # exit 2 = 차단
fi
exit 0 # exit 0 = 통과 -
스크립트에 실행 권한을 부여합니다.
chmod +x .claude/hooks/block-dangerous.sh -
.claude/settings.json에 다음 Hook 설정을 추가합니다.{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": ".claude/hooks/block-dangerous.sh"
}
]
}
]
}
}PreToolUse: Claude가 도구를 실행하기 전에 Hook이 작동합니다.Bash: Bash 도구(셸 명령 실행)를 사용하려 할 때만 실행됩니다.- 스크립트가
exit 2를 반환하면 Claude는 해당 명령을 실행하지 않고, 차단 사유를 확인한 뒤 대안을 제안합니다.
동작 확인
-
Claude에게 빌드 디렉터리를 정리하도록 요청합니다.
Claude Code에서 build 디렉터리 삭제를 요청하는 화면
-
Claude가
rm -rf를 사용하려 하면 Hook 이 이를 차단합니다. Claude는 차단 사유를 확인한 뒤 더 안전한 명령을 제안합니다.
PreToolUseHook이rm -rf명령을 차단하고 Claude가 대안을 제안하는 화면
3. Hook 이벤트 실시간 모니터링 (PostToolUse + http)
상황
Claude Code가 작업 중에 어떤 도구를 어떤 입력으로 사용하는지를 실시간으로 확인하고 싶을 때 활용할 수 있습니다. command 유형으로 로그 파일에 기록하는 방법도 있지만, http 유형을 사용하면 브라우저에서 실시간으로 이벤트를 모니터링 할 수 있습니다.
이 패턴에서는 ‘HookLab’이라는 오픈 소스 도구를 사용합니다. HookLab은 Claude Code의 HTTP Hook 이벤트를 수신해 브라우저 대시보드에 실시간으로 표시하는 도구입니다.
설정 방법
-
Docker로 HookLab을 실행합니다.
export SECRET_KEY_BASE=$(openssl rand -base64 64)
docker run -d \
-p 4000:4000 \
-v hook_lab_data:/app/data \
-e SECRET_KEY_BASE \
-e DATABASE_PATH=/app/data/hook_lab.db \
-e PHX_HOST=localhost \
ghcr.io/felipeelias/hook-lab:latest -
브라우저에서 http://localhost:4000에 접속해 HookLab 대시보드가 정상적으로 열리는지 확인합니다.
-
.claude/settings.json에 다음 Hook 설정을 추가합니다.{
"hooks": {
"PostToolUse": [
{
"matcher": "*",
"hooks": [
{
"type": "http",
"url": "http://localhost:4000/api/hooks"
}
]
}
]
}
}http유형: 이벤트가 발생하면 지정한 URL로 이벤트 정보를 전송합니다.matcher: “*” 모든 도구 사용에 이벤트를 전송합니다.- HookLab은 전송받은 이벤트를 대시보드에 실시간으로 표시합니다.
-
설정을 저장한 뒤 Claude Code를 실행합니다.
동작 확인
-
Claude에게 작업을 요청합니다.
Claude Code에서 HTTP Hook 테스트를 위해 파일 생성을 요청하는 화면
-
Claude가 도구를 사용할 때마다 이벤트 유형, 도구 이름, 입력 내용, 타임스탬프 등이 HookLab 대시보드에 실시간으로 표시되는 걸 확인할 수 있습니다.
Claude가
Write도구로hello.js를 생성한 화면