Claude Code 훅, 막을지 물을지 알릴지 정해서 거는 법
Claude Code 훅이 도는 때와 거는 곳, 막기·묻기·알리기를 가르는 기준을 실제로 걸어 둔 훅 여섯 개로 보여 드려요.
1단계부터 보기 · 모두 15단계숫자로 판단할 수 있는 위험은 명령 직전에 막고, 사람이 정할 일만 묻고, 나머지는 세션을 열거나 답을 마칠 때 알리기만 하게 나누면 작업을 세우지 않고 사고를 막아요.
준비물
- 도구Claude Code, 파이썬(훅 스크립트용). 셸 스크립트로 써도 돼요.
- 돈무료예요. 훅은 내 PC에서 도는 스크립트예요.
- 계정Claude Code를 쓰는 계정
- 걸리는 시간이 글의 예시 훅 하나를 걸고 시험하는 데 30분쯤 잡으세요.
- 난이도중급. JSON 설정 파일과 짧은 스크립트를 다뤄요.
차례
한 화면에 한 단계씩 넘기며 보세요.
- 1시작은 이랬어요
- 2알아 두기훅이 도는 때
- 3알아 두기어디에 거나
- 4알아 두기막을까, 물을까, 알리기만 할까
- 5훅 하나 거는 순서 1/7Claude Code에서
/hooks를 쳐서 지금 걸린 훅부터 봐요 - 6훅 하나 거는 순서 2/7도는 때를 골라요
- 7훅 하나 거는 순서 3/7결정을 골라요
- 8훅 하나 거는 순서 4/7스크립트를 써요
- 9훅 하나 거는 순서 5/7설정 파일에 등록해요
- 10훅 하나 거는 순서 6/7
timeout을 짧게 잡아요 - 11훅 하나 거는 순서 7/7직접 넣어 시험해요
- 12막혔던 곳승인 창 때문에 작업이 자꾸 멈췄어요
- 13막혔던 곳시간 제한이 끝나도 grep이 살아 있었어요
- 14막혔던 곳같은 폴더가 두 번 등록돼 상태 표시가 사라졌어요
- 15막혔던 곳예약해 둔 점검이 세션과 함께 사라져요
한 쪽에 모두 보기
이 사이트 운영자는 규칙 문서에 적어 둔 것을 AI가 놓치는 일을 여러 번 겪었어요. 2026년 9월 29일 메모리 정리 규칙을 정하면서 운영자는 이렇게 물었어요.
«메모리비울때 크롬은 끄지않도록해 다음부터는 근데 메모리비울깨마다 크롬을 끄지않는 규칙을 안볼거같은데 이거 어떻게 하면 좋아?»
그래서 규칙을 한 줄 더 적는 대신, Claude가 명령을 실행하기 직전에 스크립트가 끼어들게 했어요. Claude Code의 훅(hook)이에요. 지금 운영자 PC와 이 사이트 저장소에는 훅이 여섯 개 걸려 있어요. 이 글은 훅이 언제 돌고 어디에 거는지, 그리고 막을지·물을지·알리기만 할지를 어떻게 가르는지 그 여섯 개로 보여 드려요.
훅이 도는 때
훅은 Claude Code가 정해진 때마다 실행하는 명령이에요. 자주 쓰는 때만 추리면 이래요.
| 이벤트 | 언제 | 막을 수 있나 |
|---|---|---|
| SessionStart | 세션을 새로 열거나 다시 열 때 | 못 막아요. 대신 훅이 찍은 평문이 Claude가 읽는 맥락에 들어가요 |
| UserPromptSubmit | 사람이 보낸 말을 Claude가 처리하기 전 | 막을 수 있어요 |
| PreToolUse | 셸 명령·파일 쓰기 같은 도구를 실행하기 직전 | 막을 수 있어요 |
| PostToolUse | 도구가 성공한 뒤 | 이미 실행된 뒤예요 |
| Stop | Claude가 답을 마칠 때 | 막으면 Claude가 멈추지 않고 이어서 일해요 |
이 밖에도 대화를 압축하기 전후, 하위 에이전트가 시작하고 끝날 때 같은 때가 더 있어요. 전체 목록은 아래 «근거»의 공식 문서에 있어요.

운영자가 쓰는 때는 세 가지뿐이에요. 막는 일은 명령 직전(PreToolUse)에, 치우는 일은 답을 마칠 때(Stop)와 세션을 열 때(SessionStart)에 해요.
어디에 거나
훅은 설정 파일의 hooks 칸에 적어요. 어느 파일에 적느냐로 적용 범위가 달라져요.
| 파일 | 범위 | 다른 사람과 나누나 |
|---|---|---|
~/.claude/settings.json |
이 PC의 모든 프로젝트 | 아니요 |
프로젝트의 .claude/settings.json |
그 프로젝트 | 예. 저장소에 커밋해요 |
프로젝트의 .claude/settings.local.json |
그 프로젝트, 나만 | 아니요 |
운영자는 어느 프로젝트에서든 필요한 다섯 개를 사용자 설정(~/.claude/settings.json)에 걸었어요. 이 사이트에서만 쓰는 점검 알림 하나는 이 저장소의 .claude/settings.json에 걸고 커밋했어요. 그래서 이 저장소를 여는 세션이면 어느 것이든 같은 알림을 받아요.
막을까, 물을까, 알리기만 할까
훅을 만들기 전에 결정부터 골라요. 같은 위험이라도 무엇을 고르느냐에 따라 작업이 서기도 하고 계속 가기도 해요.

여섯 개를 이 기준으로 나누면 이래요.
| 훅 | 도는 때 | 하는 일 | 결정 |
|---|---|---|---|
| grep 폭주 막기 | PreToolUse | grep 식의 반복이 100 이상이거나 드라이브 전체를 뒤지면 실행하지 않아요 | 막기 |
| 남은 grep 정리 | Stop · SessionStart | 10분 넘게 돌았거나 메모리 4GB를 넘은 grep만 꺼요 | 알리기 |
| Chrome 끄기 확인 | PreToolUse | Chrome을 끄는 명령일 때만 승인 창을 띄워요 | 묻기 |
| 코덱스 지킴이 | PreToolUse · Stop · SessionStart | 일하는 코덱스가 있으면 새 호출을 막고, 부모가 죽었거나 40분 넘게 돌며 멈춘 것은 꺼요 | 막기 · 알리기 |
| 폴더 신뢰 맞추기 | SessionStart | 대소문자만 다른 같은 폴더의 신뢰 설정을 맞춰요 | 조용히 고치기 |
| 점검 밀림 알림(이 저장소만) | SessionStart | 밀린 주간·월간 점검, 다시 볼 날이 지난 결정, 늦어진 AI 소식을 알려요 | 알리기 |
기계가 숫자나 상태로 판단할 수 있으면 막고, 사람의 뜻을 들어야 하면 묻고, 멈출 까닭이 없으면 알리기만 해요. 묻기는 사람이 자리를 비운 동안 작업 전체를 세워 두기 때문에, 이 운영에서는 Chrome 하나에만 써요.
훅 스크립트 자체가 오류로 죽을 때도 정해 둘 수 있어요. 10월 8일 Claude Code 2.1.295에서 명령형 훅에 onFailure: "block" 설정이 생겼고, 켜면 훅이 실패했을 때 작업을 막아요(10월 둘째 주 AI 소식). 막는 훅은 스크립트가 죽으면 위험한 명령이 그대로 지나갈 수 있고, 알리는 훅은 죽어도 작업이 서지 않아야 해요. 그래서 이 설정은 막는 훅에 어울린다고 봐요. 운영자의 훅은 아직 이 설정을 쓰지 않아요.
훅 하나 거는 순서
- Claude Code에서
/hooks를 쳐서 지금 걸린 훅부터 봐요. 읽기 전용 목록이고, 훅마다 사용자 설정·프로젝트 설정·로컬 설정·플러그인 가운데 어디서 왔는지 보여 줘요. - 도는 때를 골라요. 실행을 막으려면 PreToolUse, 치우려면 Stop과 SessionStart, 세션을 열 때 알려 줄 것은 SessionStart예요.
- 결정을 골라요. Chrome은 사람이 시켰을 때는 꺼도 되는 일이라 묻기로 했어요.
- 스크립트를 써요. 훅은 표준입력으로 JSON을 받고, PreToolUse라면
tool_input.command에 실행하려는 명령이 들어 있어요. 아무것도 찍지 않고 끝나면 평소처럼 실행돼요. 아래 예시는 Chrome을 끄려는 명령이 오면 사람에게 묻는 훅을 짧게 줄인 코드예요.
# Chrome을 끄는 명령이면 실행 전에 사람에게 묻는다(ask)
import json, re, sys
data = json.load(sys.stdin)
cmd = str((data.get("tool_input") or {}).get("command", ""))
kill_chrome = [
r"taskkill\b.*?/+im\s+\"?chrome", # taskkill /IM chrome.exe
r"stop-process\b.*?-name\s+\"?chrome", # Stop-Process -Name chrome
r"\b(pkill|killall)\b.*chrome",
]
if any(re.search(p, cmd, re.I) for p in kill_chrome):
print(json.dumps({"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "ask",
"permissionDecisionReason": "Chrome을 끄는 명령이에요. 사람이 직접 시킨 경우에만 승인하세요."
}}, ensure_ascii=False))
permissionDecision에 deny를 넣으면 막기, ask면 묻기예요. 막을 때는 이유와 대안을 permissionDecisionReason에 꼭 적어요. Claude가 그 글을 읽고 다른 방법을 찾아요. 종료 코드 2로 끝내도 막히지만, 이유를 함께 넘기려면 JSON이 편해요.
- 설정 파일에 등록해요. 모든 프로젝트에 걸려면
~/.claude/settings.json에 이렇게 넣어요.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash|PowerShell",
"hooks": [
{ "type": "command", "command": "python \"C:/Users/<내 계정>/.claude/hooks/no_kill_chrome.py\"", "timeout": 10 }
]
}
]
}
}
matcher는 도구 이름이고, |로 여럿을 묶어요. <내 계정>은 윈도우 사용자 이름으로 바꾸세요. 윈도우에서 명령 훅은 Git Bash가 깔려 있으면 bash로, 없으면 PowerShell로 돌아요. 운영자 설정은 python 실행 파일을 전체 경로로 적어 두었어요. 훅이 도는 셸에서 python을 못 찾으면 그렇게 쓰세요.
timeout을 짧게 잡아요. 단위는 초이고 기본값이 600초라서, 명령마다 도는 훅이 멈추면 오래 기다리게 돼요. 운영자는 10~20초, 이 사이트 점검 훅은 30초로 잡았어요.- 직접 넣어 시험해요. 실행하려는 명령을 흉내 낸 JSON을 스크립트에 흘려 넣으면 돼요.
echo '{"tool_input":{"command":"taskkill /IM chrome.exe /F"}}' | python no_kill_chrome.py
2026년 10월 10일 이 글의 코드에 명령 네 개를 넣어 본 결과예요.
| 넣은 명령 | 결과 |
|---|---|
taskkill /IM chrome.exe /F |
ask |
Stop-Process -Name chrome -Force |
ask |
taskkill //IM chrome.exe //F(Git Bash에서 쓰는 꼴) |
ask |
grep -n chrome README.md |
출력 없음, 그대로 실행 |
낱말 «chrome»이 들어 있다고 다 걸리면 문서 검색까지 막혀요. 실제로 끄는 명령의 모양만 골라내야 해요.
막혔던 곳
승인 창 때문에 작업이 자꾸 멈췄어요
Codex CLI는 두 개를 동시에 돌리면 실패해요. 이 문제로 승인 창이 뜨며 작업이 서는 일이 생기자, 2026년 9월 30일 운영자가 이렇게 말했어요.
«나는 승인땜에 레포가 멈추는 걸 진짜 넘 싫어해 코덱스가 쓸데없이 도는거 직접확인후 판단해서 종료하는 방향은 안돼?»
지금 코덱스 지킴이는 묻지 않아요. 부르기 직전과 답을 마칠 때, 세션을 열 때 코덱스 프로세스를 직접 봐요. 부모 프로세스가 이미 죽은 것과 40분 넘게 돌았는데 CPU가 2초 동안 거의 움직이지 않은 것은 꺼요. 일하는 중인 것이 있으면 새 호출만 막고, «끝나면 다시 하라»는 이유를 Claude에게 돌려줘요. 운영자가 직접 연 코덱스 창은 건드리지 않아요. 이 일은 검색 명령 하나가 PC를 멈춘 날의 «다음 날 생긴 일»에도 적었어요.
시간 제한이 끝나도 grep이 살아 있었어요
9월 29일 메모리를 61GB까지 먹은 grep 하나가 PC를 멈춰 세웠어요. 도구의 시간 제한으로 Claude 쪽 명령만 끝나면 실제 grep 프로세스는 남아서 계속 자랄 수 있어요. 그래서 명령 직전에 막는 훅과, 답을 마칠 때마다 남은 것을 치우는 훅을 한 쌍으로 걸었어요. 사고 경위는 검색 명령 하나가 PC를 멈춘 날에 자세히 적었어요.
같은 폴더가 두 번 등록돼 상태 표시가 사라졌어요
같은 9월 29일, VS Code에서 연 폴더는 경로가 소문자 드라이브(c:/Users/...)로 넘어와 이미 쓰던 폴더(C:/Users/...)와 다른 폴더로 등록됐어요. 신뢰하지 않은 쪽에서는 상태 줄 같은 명령이 실행되지 않아 사용량 표시가 사라졌어요. 지금은 세션을 열 때 훅이 이미 신뢰한 폴더와 대소문자만 다른 항목을 찾아 신뢰를 맞춰요. 처음 보는 폴더를 새로 신뢰하지는 않고, 바꾸기 전에 설정 파일을 백업해요.
예약해 둔 점검이 세션과 함께 사라져요
이 사이트는 AI가 스스로 주간·월간 점검을 해요. 2026년 10월 10일 Claude Code의 예약 실행으로 점검을 걸어 보니, 예약은 그 세션 안에서만 살고 반복 예약은 7일 뒤 끝난다고 나왔어요. 그래서 저장소의 점검 스크립트를 세션을 열 때마다 돌리는 SessionStart 훅을 같이 걸었어요. 밀린 것이 없으면 아무것도 찍지 않고, 있으면 한 줄만 찍어 Claude가 읽는 맥락에 넣어요. 실패해도 세션이 열리도록 항상 0으로 끝나요.
근거
- Claude Code 공식 문서, Hooks reference · 2026-10-10 확인. 이벤트, 설정 파일 위치,
permissionDecision값(allow·deny·ask·defer), 종료 코드 2, 기본 timeout 600초, 윈도우의 기본 셸, 세션 시작 훅의 평문 출력이 맥락에 들어가는 것이 적혀 있어요. - 운영자 PC의 사용자 설정과 훅 스크립트 다섯 개 · 2026-10-10 열어 확인. 기준값(반복 100, 10분·4GB, 40분·CPU)과 운영자 말은 스크립트 머리 주석과 운영자의 작업 규칙 문서에서 그대로 옮겼어요.
- Claude Code 변경 기록 · 2026-10-10 확인. 2.1.295(10-08)의
onFailure: "block"항목이에요. - 이 사이트 저장소의 프로젝트 설정과 점검 스크립트 · 2026-10-10.
- 글 속 예시 코드는 2026-10-10에 명령 네 개를 넣어 실제로 돌려 봤어요.
이 글을 만든 방법
- 바탕운영자가 실제로 돌린 작업의 기록(작업 일지·설정 파일·오류 기록)
- 쓴 쪽AI(Claude)가 썼어요
- 독립 검수2026-10-10에 쓴 AI와 다른 AI가 원본과 대조해 통과시켰어요
- 사실 확인2026-10-10
발행 2026-10-10