한 줄 요약: Claude Code 공식 문서 "Automate actions with hooks". 첫 훅(데스크톱 알림)을 만드는 3단계, 바로 붙여 쓸 설정 예 7가지(알림, 편집 후 포맷, 보호 파일 편집 차단, 컴팩션 뒤 컨텍스트 다시 넣기, 설정 변경 감사, 디렉터리·파일이 바뀔 때 환경 다시 읽기, 특정 권한 확인 자동 승인), 훅이 도는 방식(이벤트 목록, 여러 훅의 결과 합치기, stdin 입력·종료 코드·JSON 출력, matcher와 if 필드, 설정 위치), prompt·agent·HTTP 훅, 한계와 문제 해결을 다룬다.
원본 정보#
- 제목: Automate actions with hooks
- 발행: Anthropic, Claude Code 공식 문서 (원본 날짜 미상)
- URL: https://code.claude.com/docs/en/hooks-guide (새 창)
- 수집(fetch)일: 2026-10-18. 본문의 이벤트 목록, matcher 값, 설정 키, 기본 타임아웃, 버전 조건(v2.1.210, v2.1.234, v2.1.246, v2.1.248)은 이 날짜 기준이다.
- 범위: 원본은 스스로 "흔한 용도와 시작하는 법"을 다룬다고 밝히고, 전체 이벤트 스키마, JSON 입출력 형식, async 훅, MCP 도구 훅 같은 고급 기능은 Hooks reference로 넘긴다. 이 요약도 원본이 링크만 한 레퍼런스 내용(이벤트별 종료 코드 2 동작 전체 목록, decision control 요약표, 보안 고려 사항)은 담지 않는다. 그 레퍼런스는 2026-10-19에 Claude Code 훅 레퍼런스로 따로 수집했다.
핵심 주장#
- 훅은 결정론적 통제다. 훅은 사용자가 정의한 셸 명령으로, Claude Code가 생명주기의 정해진 지점에서 실행한다. 원본: "certain actions always happen rather than relying on the LLM to choose to run them." 규칙이 아니라 판단이 필요한 결정에는 Claude 모델이 조건을 평가하는 prompt 훅·agent 훅을 쓸 수 있다. → 훅
- 훅은 stdin·stdout·stderr·종료 코드로 말한다. 이벤트가 일어나면 Claude Code가 이벤트별 데이터를 JSON으로 stdin에 넘긴다. 종료 코드 0은 "종료 코드로는 이의 없음"이고(
PreToolUse에서는 승인이 아니라 일반 권한 흐름이 그대로 적용), 종료 코드 2는 동작을 막으며 stderr에 이유를 쓴다. 그 밖의 종료 코드는 대부분의 이벤트에서 막지 않는 오류(non-blocking error)로 처리되고 동작은 진행된다. 더 세밀하게 통제하려면 종료 코드 0으로 끝내고 stdout에 JSON 객체를 쓴다. 원본은 한 훅에서 두 방식 중 하나만 고르라고 한다. → Claude Code 훅 설정 레시피 - Claude의 컨텍스트에 무언가 넣는 길은 이벤트와 출력 형식에 따라 다르다. 종료 코드 0에서 Claude Code가 일반 텍스트로 다루는 stdout은
UserPromptSubmit,UserPromptExpansion,SessionStart,PostModelSwitch훅에서 Claude의 컨텍스트에 더해진다(원본이 이름으로 든 네 이벤트).UserPromptSubmit에서 텍스트를 넣으려면hookSpecificOutput.additionalContext를 쓰고, 이 필드를 JSON 최상위에 두면 Claude Code가 조용히 무시한다.additionalContext로 돌려준 텍스트는 system reminder로 주입돼 Claude가 일반 텍스트로 읽는다. 여러 훅이 같은 이벤트에 맞으면 모든 훅의additionalContext가 함께 전달된다. → 훅, 컨텍스트 비용 PreToolUse의 거부는 권한 모드를 가리지 않지만, 허용은 권한 규칙보다 느슨하게 만들지 못한다.PreToolUse훅은 어떤 권한 모드 검사보다 먼저,dontAsk를 포함한 모든 모드에서 실행되고,permissionDecision: "deny"를 돌려주면bypassPermissions나--dangerously-skip-permissions에서도 도구를 막는다. 반대로"allow"는 settings의 deny 규칙을 넘지 못하고 몇몇 확인 창을 없애지 못한다. 조건과 예외가 붙는다: 설치한 mod가tool.check를 다루면 managed settings에 있지 않은 훅이 막은 호출을 승인할 수 있고(plan 모드에서는 읽기 전용 호출만, 세부 기준은 권한 문서로 넘김. 위키는 권한 문서 기준으로 정리: 훅의 ‘원본끼리 달랐던 점’ 상자), matcher가Edit|Write면 Claude가 셸 명령으로 고친 파일은 보지 못하며,if필드 거르기는 최선 노력(best-effort)이라 확실한 허용·거부는 권한 시스템으로 하라고 원본이 말한다. → 권한 모드, Claude Code 관리자 권한 통제- 훅 실패는 자주 조용하다. 성공한 훅은 대화에 아무것도 보이지 않는다. JSON 앞에 셸 프로필의
echo가 끼거나 필드를 잘못된 층에 두면 JSON이 무시되고 오류도 보이지 않는다. 그래서/hooks메뉴,Ctrl+O트랜스크립트 보기,claude --debug·/debug디버그 로그로 확인한다. → Claude Code 훅 문제 해결
원본이 든 설정 예 (2026-10-18 기준)#
원본은 각 예에 바로 쓸 수 있는 설정 블록을 붙인다. 설정 원문은 Claude Code 훅 설정 레시피에 그대로 옮겼다.
| 목적 | 이벤트 | matcher | 원본이 넣은 위치 |
|---|---|---|---|
| Claude가 입력을 기다릴 때 데스크톱 알림 | Notification | "" | ~/. |
| 편집한 파일에 Prettier 실행 | PostToolUse | Edit|Write | 프로젝트 . |
.·package-lock.·. 편집 차단 | PreToolUse | Edit|Write | 프로젝트 . + . |
| 컴팩션 뒤 프로젝트 관례 다시 넣기 | SessionStart | compact | 프로젝트 . |
| 설정· | ConfigChange | "" | ~/. |
| 디렉터리가 바뀔 때 direnv 환경 다시 읽기 | SessionStart + CwdChanged (또는 FileChanged) | 없음 (FileChanged는 .) | ~/. |
plan 끝의 ExitPlanMode 확인 자동 승인 | PermissionRequest | ExitPlanMode | ~/. |
원본이 밝힌 세부 동작 (2026-10-18 기준)#
이벤트
원본 표의 이벤트는 다음과 같다: SessionStart, Setup, UserPromptSubmit, UserPromptExpansion, PreToolUse, PermissionRequest, PermissionDenied, PostToolUse, PostToolUseFailure, PostToolBatch, Notification, MessageDisplay, SubagentStart, SubagentStop, TaskCreated, TaskCompleted, Stop, StopFailure, TeammateIdle, InstructionsLoaded, ConfigChange, CwdChanged, DirectoryAdded, FileChanged, WorktreeCreate, WorktreeRemove, PreCompact, PostCompact, PreModelSwitch, PostModelSwitch, Elicitation, ElicitationResult, SessionEnd. 원본은 전체 목록을 Hooks reference로 넘긴다.
- 원본 이벤트 표가 "막을 수 있다"고 적은 것:
PreToolUse(도구 호출),UserPromptExpansion(명령 확장),PreModelSwitch(모델 전환). 표 밖 본문에서도ConfigChange는 종료 코드 2나{"decision": "block"}으로 변경을 막을 수 있고,PostToolUse·Stop은decision: "block"을 쓴다. 이벤트별 전체 목록은 레퍼런스에 있다. Stop은 Claude가 응답을 마칠 때마다 실행된다. 작업 완료 때만이 아니다. 사용자 중단에는 실행되지 않고, API 오류로 끝난 턴은StopFailure가 받는다.PermissionRequest는 Claude Code가 사용자에게 권한을 물으려 할 때, 또는 물을 수 없는 호출을 자동 거부하려 할 때 실행된다.-p비대화형 모드에서도dontAsk모드가 아니면 실행되고, 어떤 훅도 정하지 않고 달리 답할 것도 없는 호출은 거부된다.PostToolUse훅은 도구가 이미 실행됐으므로 동작을 되돌리지 못한다.
종류
command(셸 명령, 가장 흔함) 외에 네 가지가 있다: http(이벤트 데이터를 URL로 POST), mcp_tool(설정된 MCP 서버의 도구 호출), prompt(단일 턴 LLM 평가), agent(도구를 쓰는 다중 턴 검증). 원본은 agent 훅이 실험 기능이라 바뀔 수 있으니 운영 워크플로에는 command 훅을 권한다.
여러 훅이 맞을 때
- 같은 이벤트에 맞는 훅은 모두 병렬로 실행되고, 모두 끝난 뒤 결과를 합친다. 한 훅의
deny가 다른 훅의 실행을 멈추지 않으므로, 한 훅의deny로 다른 훅의 부작용을 막으려 하지 말라고 원본이 경고한다. PreToolUse권한 결정은 가장 제한적인 답이 이긴다:deny,defer,ask,allow순.- 여러
PreToolUse훅이updatedInput으로 도구 인자를 고쳐 쓰면 마지막에 끝난 것이 적용되고 순서는 비결정적이다. 한 도구의 입력을 둘 이상의 훅이 고치지 않게 하라고 한다.
종료 코드 2가 보여 주는 곳
이벤트마다 다르다. 어떤 이벤트는 stderr를 Claude에게 피드백으로 주고, 어떤 이벤트는 사용자에게 보여 주며, ConfigChange·Elicitation 같은 몇몇은 메시지를 보이지 않는다. SessionStart 등 막을 수 없는 이벤트에서는 종료 코드 2가 stderr를 사용자에게 보여 주고 실행은 계속된다. 전체 목록은 레퍼런스에 있다.
PreToolUse의 permissionDecision 값
"allow": 대화형 확인 창을 건너뛴다. 단 deny·ask 규칙(기업 managed deny 목록 포함)은 그대로 적용되고, 네트워크 경로 읽기,requiresUserInteraction표시 MCP 도구, 조직이ask로 정한 커넥터 도구(그 설정이 Claude Code에 닿는 세션에서)의 확인 창도 남는다. plan 모드에서 파일 편집을"allow"해도 훅이 없을 때와 같은 확인·차단·승인을 받는다."deny": 도구 호출을 취소하고permissionDecisionReason을 Claude에게 준다."ask": 평소처럼 사용자에게 확인 창을 띄운다."defer":-p비대화형 모드에서만. 도구 호출을 보존한 채 프로세스를 끝내 Agent SDK 래퍼가 입력을 모은 뒤 재개하게 한다.
다른 이벤트는 결정 형식이 다르다: PostToolUse·Stop은 최상위 decision: "block", PermissionRequest는 hookSpecificOutput.decision.behavior를 쓴다. PreModelSwitch는 같은 permissionDecision을 쓰되 "ask"는 대화형 /model에서만 확인을 받고 그 밖에서는 거부로 다룬다.
matcher와 if
- matcher가 없으면 그 이벤트가 일어날 때마다 실행된다. 이벤트마다 matcher가 거르는 필드가 다르다(도구 이벤트는 도구 이름,
SessionStart는 시작 방식,Notification은 알림 종류,ConfigChange는 설정 출처 등).UserPromptSubmit,PostToolBatch,Stop,TeammateIdle,TaskCreated,TaskCompleted,WorktreeCreate,WorktreeRemove,CwdChanged,MessageDisplay는 matcher를 지원하지 않아 매번 실행된다. - matcher는 대소문자를 구분한다.
"Edit|Write"와"Edit, Write"는 같다. MCP 도구 이름은mcp__<server>__<tool>형식이라mcp__github__.*같은 정규식으로 맞춘다. if필드는 권한 규칙 문법("Bash(git *)","Edit(*.ts)")으로 도구 이름과 인자를 함께 걸러, 맞을 때만 훅 프로세스를 띄운다. 도구 이벤트(PreToolUse,PostToolUse,PostToolUseFailure,PermissionRequest,PermissionDenied)에서만 동작하고 다른 이벤트에 붙이면 훅이 실행되지 않는다. Bash 명령을 어떤 명령으로 실행할지 판단할 수 없으면 패턴과 상관없이 훅을 실행한다. 원본은 이 거르기가 최선 노력이므로 확실한 허용·거부는 권한 시스템으로 하라고 한다.
설정 위치와 끄기
| 위치 | 범위 | 공유 |
|---|---|---|
~/. | 내 모든 프로젝트 | 아니오, 내 기기 |
. | 프로젝트 하나 | 예, 저장소에 커밋 가능 |
. | 프로젝트 하나 | 아니오, Claude Code가 설정을 저장할 때 gitignore |
| Managed policy settings | 조직 전체 | 예, 관리자 통제 |
플러그인 hooks/ | 플러그인이 켜져 있을 때 | 예, 플러그인에 묶임 |
| 스킬 frontmatter | 스킬을 부른 뒤 세션 끝까지 | 예, 스킬 파일 |
| 서브에이전트 frontmatter | 그 서브에이전트가 도는 동안 | 예, 서브에이전트 파일 |
"disableAllHooks": true로 훅을 끈다. 설정 우선순위를 적용한 뒤 남은 값을 읽으므로 프로젝트 설정이 사용자 설정을 덮을 수 있다. managed settings에 있는 훅은 managed settings에도disableAllHooks가 있지 않으면 계속 실행된다.- 조직이
allowManagedHooksOnly를 켜면/hooks메뉴에 "Only hooks from managed settings run here"가 보이고, user·project·local 설정 파일의 훅은 실행되지 않고 목록에도 없다. - Claude Code가 실행 중일 때 설정 파일을 직접 고치면 파일 감시기가 보통 자동으로 반영한다.
기본 타임아웃 (훅마다 timeout 필드, 초 단위로 바꿀 수 있음)
command·http·mcp_tool: 10분. 단UserPromptSubmit·PreModelSwitch·PostModelSwitch는 30초,MessageDisplay는 10초로 낮춘다.prompt: 30초.agent: 60초(도구 사용 최대 50턴).SessionEnd훅은 종류와 상관없이 1.5초 예산을 나눈다. 훅별timeout을 더 길게 두면 최대 60초까지 예산을 올린다.
버전 조건
Notification의quota_auto_resume_fired·quota_auto_resume_stale·quota_auto_resume_disabledmatcher: v2.1.234 이상.- 터미널 세션에서 샌드박스 명령의 네트워크 요청에 대한
permission_prompt: v2.1.246 이상. - 팀원의 터미널 설정 질문에 대한
agent_needs_input: v2.1.248 이상. - prompt 훅
PreToolUse의"ok": false: v2.1.210 전에는 거부 이유가 도구 오류로 Claude에게 돌아가고 턴이 계속됐다. 지금은 기본으로 턴이 끝나고 경고 줄로 보이며,continueOnBlock: true면 이유를 Claude에게 돌려주고 계속한다.