빠른 설정
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/format.sh"
}
]
}
]
}
}이벤트 흐름
hook은 프롬프트 지시보다 결정적인 자동화다
Claude Code hook은 특정 lifecycle 이벤트에서 shell command, HTTP endpoint, prompt, agent 등을 자동 실행하는 장치입니다. "수정 후 포맷해 줘"라고 매번 요청하는 대신 PostToolUse에 formatter를 붙이면, 파일 편집 뒤 정해진 명령이 반복 실행됩니다.
UserPromptSubmit
-> prompt 검사 또는 맥락 주입
PreToolUse
-> 실행 전 차단 또는 수정
PostToolUse
-> 실행 후 포맷, 로그, 검사
Stop
-> 응답 종료 전 최종 확인hook은 모델이 기억해서 수행하는 규칙이 아니라 설정에 묶인 자동 실행입니다. 반드시 일어나야 하는 검사는 hook으로, 판단이 필요한 검토는 프롬프트나 리뷰 절차로 나누는 편이 좋습니다.
matcher는 자동화 범위를 좁히는 안전장치다
모든 tool call에 hook을 붙이면 느리고 시끄러워집니다. PreToolUse와 PostToolUse에는 matcher를 써서 대상 tool을 좁히는 것이 기본입니다.
Write
Edit
Edit|Write
BashMarkdown 표 안에서는 pipe가 열 구분자로 해석되므로 <code>Edit|Write</code>처럼 안전하게 적어야 합니다. 실제 settings JSON에서는 "Edit|Write"처럼 씁니다.
exit code는 차단 여부를 결정한다
command hook에서 exit code 0은 성공입니다. 정책 위반처럼 실제로 막아야 하는 상황은 exit code 2로 표현합니다. 특히 PreToolUse에서 2를 반환하면 해당 tool call을 막을 수 있습니다. 일반적인 exit code 1은 대부분의 hook 이벤트에서 비차단 오류로 취급될 수 있으므로, 차단 정책에는 맞지 않습니다.
#!/bin/bash
if echo "$1" | grep -q "rm -rf"; then
echo "Blocked destructive command" >&2
exit 2
fi
exit 0어디에 붙일까
| 목적 | 적합한 이벤트 |
|---|---|
| 프롬프트 금지어 검사 | UserPromptSubmit |
| 위험한 shell 명령 차단 | PreToolUse |
| 수정 후 formatter 실행 | PostToolUse |
| 세션 시작 시 이슈 맥락 주입 | SessionStart |
| 응답 종료 전 완료 조건 확인 | Stop |
| permission 요청 알림 | Notification |
주의할 점
hook은 강력하지만, 잘못 설정하면 Claude Code 세션 전체가 느려지거나 반복 차단될 수 있습니다. 먼저 좁은 matcher와 짧은 command hook으로 시작하고, 팀 공통 정책은 .claude/settings.json, 개인 실험은 .claude/settings.local.json에 나눠 두는 편이 안전합니다.
PostToolUse는 이미 실행된 뒤에 동작하므로 보안 차단에는 늦습니다. 위험한 명령이나 파일 접근을 막아야 한다면 실행 전에 판단할 수 있는 PreToolUse나 permission 관련 이벤트를 우선 검토해야 합니다.
참고 링크
2 sources