[Claude Code Plugin 만들기 #3] 훅으로 자동화 — 규칙은 한 번 정하면 자동으로
· 약 9분
이 글은 Claude Code Plugin 만들기 시리즈의 세 번째 편입니다. Hooks의 구조, 이벤트 종류, exit code의 정확한 의미, 그리고 실전 디버깅 사례를 다룹니다.
TL;DR
- Hooks는
hooks.json에 정의하는 자동 실행 규칙 - 14가지 이벤트 중
PreToolUse,PostToolUse,SessionStart가 핵심 - exit 0 = 성공, exit 2 = 의도적 차단, 그 외 = 에러
exit 1은 "차단"이 아니라 "에러" — 이 차이를 모르면 버그를 만든다- hook 타입:
command(셸 명령),prompt(LLM 평가),agent(다중 턴 검증) 3가지
Hook이 뭔가요?
코드를 저장할 때마다 이런 말을 해야 한다고 생각해봅시다.
"들여쓰기가 이상한데 정리해줘. 그리고 이 파일은 .env니까 절대 수정하지 마."
매번 이런 말을 하는 건 비효율적입니다. Hooks를 쓰면 이 모든 일을 자동으로 처리합니다. 규칙을 한 번만 정하면, 앞으로는 조건이 맞을 때마다 자동으로 실행됩니다.
이벤트 전체 목록
Hook이 반응할 수 있는 이벤트는 총 14가지입니다. 공식 문서 기준으로 정리합니다.
| 이벤트 | 발생 시점 | 차단 가능 |
|---|---|---|
SessionStart | 세션 시작/재개 시 | X |
UserPromptSubmit | 사용자가 프롬프트 제출 시 | O |
PreToolUse | 도구 실행 직전 | O |
PermissionRequest | 권한 대화상자 표시 시 | O |
PostToolUse | 도구 실행 성공 직후 | X |
PostToolUseFailure | 도구 실행 실패 직후 | X |
Notification | 알림 발생 시 | X |
SubagentStart | 서브에이전트 생성 시 | X |
SubagentStop | 서브에이전트 종료 시 | O |
Stop | Claude 응답 완료 시 | O |
TeammateIdle | 팀 멤버 대기 상태 시 | O |
TaskCompleted | 작업 완료 표시 시 | O |
PreCompact | 컨텍스트 압축 직전 | X |
SessionEnd | 세션 종료 시 | X |
실무에서 가장 많이 쓰는 건 PreToolUse, PostToolUse, SessionStart 세 가지입니다.
hooks.json 구조
hooks.json은 3단계 중첩으로 구성됩니다.
이벤트 → matcher 그룹 → hook 핸들러
hooks/hooks.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo 'Bash 실행 전 검사'",
"timeout": 10
}
]
}
]
}
}
matcher: 언제 실행할지 필터링
matcher는 정규표현식입니다. 이벤트별로 필터링 대상이 다릅니다.
| 이벤트 | matcher 대상 | 예시 |
|---|---|---|
PreToolUse, PostToolUse | 도구 이름 | Bash, Edit|Write, mcp__.* |
SessionStart | 시작 방식 | startup, resume, clear |
SessionEnd | 종료 사유 | clear, logout |
SubagentStart | 에이전트 타입 | Explore, Plan |
Stop, UserPromptSubmit | 지원 안 함 | 항상 실행 |
"*", "", 또는 matcher 자체를 생략하면 모든 경우에 실행됩니다.
Hook 핸들러 필드
| 필드 | 필수 | 설명 |
|---|---|---|
type | O | "command", "prompt", "agent" |
command | type=command 시 | 실행할 셸 명령어 |
prompt | type=prompt/agent 시 | LLM에 보낼 프롬프트 |
timeout | X | 제한 시간 (초). command 기본값: 600초 |
statusMessage | X | 실행 중 표시할 스피너 메시지 |
async | X | true면 백그라운드 실행 (command만 지원) |
once | X | true면 세션당 1회만 실행 (skills 전용) |
