Claude Code hooks — 세션·도구 이벤트에 자동 동작 붙이기
settings.json hooks로 세션 시작·도구 호출 전후·종료에 셸 명령을 끼우는 패턴. 보안 차단·자동 포맷·로깅·외부 알림 5종 예시.
Claude Code의 hooks는 settings.json의 hooks 키에 정의해 두면 세션 시작·도구 호출 전후·세션 종료 등 이벤트에서 셸 명령을 자동 실행한다. AI가 무엇을 하기 직전에 가로채고, 직후에 보정하고, 끝날 때 정리할 수 있는 강력한 확장점이다.
이 가이드는 Claude Code 1.x / 공식 hooks 스펙 기준. Claude Code 셋업 이후 자동화·보안을 한 단계 더 굳히는 단계다.
TL;DR
| Hook 이벤트 | 발동 시점 | 대표 활용 |
|---|---|---|
SessionStart | 세션 시작 직후 | 메모리 동기화 메시지, env 검증 |
UserPromptSubmit | 사용자가 프롬프트 제출 직후 | 슬래시 커맨드 인식, 로깅, 후처리 트리거 |
PreToolUse | 도구 호출 직전 | 위험 명령 차단, 시크릿 파일 보호 |
PostToolUse | 도구 호출 직후 | 자동 포맷(prettier), 린트, 사이드이펙트 기록 |
Stop | 세션 종료 직전 | 변경 요약, 로그 백업, 알림 |
핵심 규칙:
- exit code 2로 종료하면 도구 호출이 차단된다 (PreToolUse 시).
- hook stdin으로 JSON이 들어옴 —
jq로 파싱. - hook은 셸 명령이므로 OS 차이(macOS/Linux/Windows WSL) 주의.
사전 조건
- Claude Code 1.x 설치 — Claude Code 셋업
jq설치 (brew install jq/apt install jq/winget install jqlang.jq)settings.json편집 가능 (보통~/.claude/settings.json)
권장 베이스라인 다운로드
devAlice 권장 hooks 5종 + 권한 deny/allow 리스트 — 그대로 받아서 본인 환경에 맞춰 수정하면 된다.
settings.json# 1. 다운로드
curl -fsSL https://devalice.jaceclub.com/assets/ai-agents/claude-code-hooks/settings.example.json -o settings.json
# 2. SHA-256 검증
shasum -a 256 settings.json
# 기대값: 30c1d4117a935cac03b601c71125c11b71733c8c59517ab129fd8913cfb8a69e
# 3. 코드 검사 (특히 PreToolUse hook들)
less settings.json
# 4. 적용 위치로 복사 (macOS/Linux)
mkdir -p ~/.claude
cp settings.json ~/.claude/settings.json⚠️ 주의: hooks는 임의 셸 명령을 실행한다. 다른 사람의 hooks를 그대로 적용하기 전 반드시 코드 검사. 본 예시는 안전한 5종 기본 셋이지만 본인 환경에 맞춰 검토 후 사용.
1. hooks 구조 — 5분
~/.claude/settings.json의 hooks 키:
{
"hooks": {
"EventName": [
{
"matcher": "정규식 또는 도구 이름", // 선택
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc '실제 셸 명령'"
}
]
}
]
}
}매칭 규칙:
matcher미지정 → 모든 발동에 hook 실행matcher가 도구 이름 (Bash,Write,Edit,Read등) → 해당 도구만matcher가 정규식 (^/(?:ej|euijinpro)\\b) →UserPromptSubmit에서 프롬프트 텍스트 매칭
stdin으로 들어오는 JSON:
{
"session_id": "...",
"transcript_path": "/path/to/transcript.jsonl",
"cwd": "/Users/...",
"tool_name": "Bash",
"tool_input": { "command": "..." },
"tool_response": { /* PostToolUse 전용 */ }
}jq -r .tool_input.command로 추출.
2. SessionStart — 세션 컨텍스트 적재
가장 단순한 hook. 세션 진입 시 한 줄 출력:
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'printf \"[세션 시작] %s\\n메모리 동기화: 최신 (skip)\\n\" \"$(date \"+%Y-%m-%d %H:%M:%S\")\"'"
}
]
}
]stdout이 시스템 메시지로 노출된다. 이를 활용:
- 메모리 파일 자동 로드 트리거
- 프로젝트별 컨텍스트 출력
- 시작 시 git 상태 요약
# 더 풍부한 예시
command='/bin/bash -lc "echo [세션 시작]; git -C \"$PWD\" status -s; git -C \"$PWD\" log --oneline -3"'3. PreToolUse — 위험 명령 차단 (가장 가치 높은 hook)
exit 2로 차단. AI가 위험한 셸 명령을 시도해도 막을 수 있다.
3.1 위험 패턴 차단
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'cmd=$(jq -r .tool_input.command); case \"$cmd\" in *\"rm -rf /\"*|*\"sudo rm\"*|*\":(){\"*) echo \"위험 명령어 차단: $cmd\" >&2; exit 2;; esac'"
}
]
}
]차단 패턴:
rm -rf /— 시스템 파괴sudo rm— 광범위 삭제 (필요하면 화이트리스트로 풀어주기):(){— fork bomb (:(){ :|: & };:)
3.2 시크릿 파일 수정 차단
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'path=$(jq -r .tool_input.file_path); case \"$path\" in */.env|*/credentials.json|*/.aws/credentials) echo \"시크릿 파일 수정 차단: $path\" >&2; exit 2;; esac'"
}
]
}.env, credentials.json, ~/.aws/credentials 등을 AI가 실수로 변경하지 못하게.
3.3 특정 디렉토리 보호
command='/bin/bash -lc "path=\$(jq -r .tool_input.file_path); case \"\$path\" in /etc/*|/System/*) echo \"시스템 경로 차단: \$path\" >&2; exit 2;; esac"'4. PostToolUse — 자동 포맷 / 린트 / 로깅
도구 호출 이후 보정 작업.
4.1 prettier 자동 포맷
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'path=$(jq -r .tool_input.file_path); case \"$path\" in *.ts|*.tsx|*.js|*.jsx) prettier --write \"$path\" 2>/dev/null || true ;; esac'"
}
]
}
]AI가 Write/Edit한 직후 prettier가 자동 정리. 매 편집마다 0.5초 정도 추가.
4.2 변경 파일 로그
command='/bin/bash -lc "path=\$(jq -r .tool_input.file_path); echo \"[changed] \$(date +%T) \$path\" >> ~/.claude/change.log"'세션 어떤 파일이 어떤 순서로 변경됐는지 시간순 기록.
4.3 type-check / lint (느린 작업은 별도 hook 권장)
매 편집마다 tsc --noEmit은 비용이 크다. Stop hook으로 옮기는 게 낫다 (§6).
5. UserPromptSubmit — 슬래시 커맨드 감지 / 후처리 트리거
"UserPromptSubmit": [
{
"matcher": "^/(?:ej|euijinpro)\\b",
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'echo \"[ej skill] 프롬프트 euijin.pro 기록 대상\" >&2'"
}
]
}
]- 슬래시 커맨드 감지 → 외부 시스템에 트리거 (예: Slack 알림, 별도 로깅)
- 특정 키워드 (
urgent,bug)에 자동 라벨링 - 토큰 한도 임계치 검사
6. Stop — 세션 종료 시 cleanup
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'printf \"\\n[세션 종료] %s\\n\" \"$(date \"+%Y-%m-%d %H:%M:%S\")\"'"
}
]
}
]활용 예:
- 변경 파일 git status 요약
- 백업 (
rsync또는 git stash) - 외부 시스템에 종료 알림
- type-check / build 1회
command='/bin/bash -lc "if git diff --quiet; then echo \"[clean]\"; else echo \"[changes]\"; git diff --stat; fi"'7. permissions — 권한 deny / allow
hooks와 별개지만 settings.json에 함께 들어가는 가장 중요한 보안 키.
"permissions": {
"deny": [
"Bash(rm -rf /:*)",
"Bash(sudo rm:*)",
"Read(.env)",
"Read(.env.local)",
"Read(.aws/credentials)",
"Read(*/credentials.json)"
],
"allow": [
"Bash(git status:*)",
"Bash(git log:*)",
"Bash(git diff:*)",
"Bash(pnpm:*)",
"Bash(npm:*)",
"Bash(node:*)"
]
}deny는 무조건 우선 — hooks의 차단 로직과 보완 관계allow는 사용자 확인 없이 자동 승인 (자주 쓰는 안전한 명령)- 그 외는 사용자 매번 확인
본 가이드의 hooks는 deny와 중복 가드 — defense in depth.
8. settings.json 위치와 우선순위
| 위치 | 적용 범위 | 비고 |
|---|---|---|
~/.claude/settings.json | 사용자 전역 | 모든 프로젝트 |
<project>/.claude/settings.json | 프로젝트 | 프로젝트 진입 시 user 설정에 머지 |
<project>/.claude/settings.local.json | 프로젝트 + 사용자 로컬 | gitignored 권장 |
머지 순서: user → project → project.local. 뒤가 앞을 덮어쓴다.
hooks는 머지가 아닌 배열 누적 — user에 hook 5개 + project에 hook 3개 = 총 8개 모두 실행.
9. 디버깅 — hook이 안 도는 것 같을 때
9.1 stdin payload 보기
임시 hook으로 무엇이 들어오는지 확인:
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "/bin/bash -lc 'cat > /tmp/claude-hook-debug.json'"
}
]
}→ cat /tmp/claude-hook-debug.json | jq .
9.2 exit code 확인
command='/bin/bash -lc "echo dbg >&2; exit 2"'→ 차단되는지 (PreToolUse) 확인.
9.3 hook 자체가 호출됐는지
command='/bin/bash -lc "echo \"[hook fired $$ $(date +%T)]\" >> ~/.claude/hook-trace.log"'세션 후 로그 파일 확인.
9.4 JSON 문법 오류
settings.json은 매우 까다롭다 — trailing comma, escape 누락이 흔한 함정. jq . ~/.claude/settings.json으로 한 번 검증.
10. 트러블슈팅
"command not found: jq"
brew install jq (macOS) / sudo apt install jq (Linux) / winget install jqlang.jq (Windows).
hook이 발동했지만 효과 없음
command가 단일 라인이어야 함. 여러 라인은\\n또는 별도 스크립트 파일.- 쉘 escape 주의 — JSON 안에서
\"두 번 escape.
PreToolUse exit 2가 무시됨
- 실제로
exit 2가 셸 명령 마지막 줄에 도달했는지 확인. set -e환경에서 case 매칭 후;;로 정상 종료되어 0이 되는 함정.case안에서 직접exit 2.
prettier가 동작하지 않음
- 프로젝트 root에
prettier설치 여부 확인 (pnpm prettier --version). - hook의 PATH에
node_modules/.bin포함되지 않을 수 있음 →npx prettier또는 절대 경로.
settings.json 수정해도 반영 안 됨
- 세션 재시작 필요. 또는
/config reload(지원 시). - 잘못된 JSON 문법으로 무시되고 있을 수 있음.
jq .검증.
다음 단계
- Claude Code 셋업 — 본 가이드 전제
- Agent runner — 자율 실행 + hooks 조합
- MCP servers — hooks와 MCP의 역할 차이
- Multi-agent 워크플로 — 서브에이전트 통합
참고 링크
변경 이력
- 2026-05-12 — 초안 (devAlice M2 시드 확장)