Hooks

Eleven·2026년 4월 15일

Hello, Claude Code

목록 보기
5/11

요약

Hooks는 Claude Code 라이프사이클의 특정 이벤트 시점에 자동으로 실행되는 쉘 커맨드다. CLAUDE.md가 AI 모델에게 하는 부탁이라면, Hooks는 AI를 감싸고 있는 엔진에 하는 설정이다. 그래서 모델이 어길 수 없다.


개념 정리

CLAUDE.md vs Hooks

CLAUDE.md   →  Claude 모델에게 부탁  →  모델이 어길 수 있음
Hooks       →  Claude Code 엔진이 강제  →  모델이 어길 수 없음

호출 주체 — Claude Code 엔진

Hooks 호출 판단은 Claude Code 엔진(프로그램)이 한다. Claude 모델(AI)이 아니다.

1. Claude 모델이 "Bash로 rm -rf / 실행할게요" 결정
2. Claude Code 엔진이 가로챔 → settings.json 확인
3. security-gate.sh 호출
4. exit 2 반환
5. 엔진이 실행 차단
6. Claude 모델에게 결과만 전달

Claude 모델은 3~5번 과정을 모른다. 엔진이 알아서 처리하고 결과만 알려준다.


설정 파일 위치

~/.claude/settings.json       # 전역 (모든 프로젝트)
.claude/settings.json         # 프로젝트 전용 (팀 공유 가능)

주요 이벤트 종류

이벤트발동 시점차단 가능 여부
PreToolUse툴 실행 직전가능 (exit 2)
PostToolUse툴 실행 직후불가 (후처리 전용)
UserPromptSubmit프롬프트 제출 시-
StopClaude 응답 완료 시-
SubagentStop서브에이전트 완료 시-
SessionStart/End세션 시작/종료 시-

Exit Code — 차단의 핵심

exit 0  →  허용, 계속 진행
exit 1  →  경고만 출력, 진행은 됨
exit 2  →  차단, Claude에게 에러 메시지 전달

보안이 목적이라면 반드시 exit 2를 써야 한다. exit 1은 경고만 하고 통과시킨다.


settings.json 구조

settings.json은 "어떤 이벤트에, 어떤 명령어를 실행할지" 연결하는 허브 역할이다.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "npx prettier --write \"$TOOL_INPUT_FILE_PATH\""
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "~/.claude/hooks/security-gate.sh"
      }
    ]
  }
}

단순한 경우 vs 복잡한 경우

// 단순한 경우 — 바로 씀
"command": "npx prettier --write \"$TOOL_INPUT_FILE_PATH\""

// 복잡한 경우 — 스크립트 파일로 분리
"command": "~/.claude/hooks/security-gate.sh"

보안 게이트 스크립트 예시

#!/bin/bash
INPUT=$(cat)                          # Claude가 stdin으로 보내는 JSON 읽기
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# rm -rf 패턴 차단
if echo "$CMD" | grep -qE 'rm\s+-rf\s+/'; then
  echo "위험한 명령어 감지: $CMD" >&2   # >&2 = stderr로 출력 (차단과 무관)
  exit 2                              # 실제 차단 신호
fi

# main 브랜치 직접 커밋 차단
if echo "$CMD" | grep -q "git commit" && \
   [ "$(git branch --show-current 2>/dev/null)" = "main" ]; then
  echo "main 브랜치 직접 커밋 금지" >&2
  exit 2
fi

exit 0

>&2exit 2는 별개다. >&2는 메시지 출력 방향이고, 실제 차단은 exit 2가 결정한다.


전체 연결 구조

settings.json (허브)
├── PreToolUse  → security-gate.sh 실행  (차단 가능)
└── PostToolUse → prettier 실행          (후처리)

각 스크립트는 서로 모른다. Claude Code 엔진이 이벤트 발생 시 settings.json을 보고 각각 독립적으로 호출한다.


핵심 요약 (TL;DR)

  • Hooks는 Claude Code 엔진이 강제 실행 — 모델이 어길 수 없음
  • PreToolUse가 가장 강력 — 실행 전에 차단 가능
  • exit 2 = 차단, exit 1 = 경고만, exit 0 = 허용
  • >&2는 메시지 출력 방향, 차단은 exit 2가 결정
  • settings.json이 허브 — 각 스크립트는 서로 독립적
  • CLAUDE.md는 가이드라인, Hooks는 집행자

다음에 알아볼 것

  • Module 05: MCP — 외부 도구(GitHub, DB, Slack)를 Claude에 연결하는 방법
  • Hooks + CLAUDE.md + Subagents 세 가지를 조합한 완성형 자동화 구조
  • async: true 옵션으로 Hook을 백그라운드에서 실행하는 패턴


[Series] Claude Code Fundamentals - Hooks

Summary

Hooks are shell commands that execute automatically at specific lifecycle events in Claude Code. If CLAUDE.md is a request made to the AI model, Hooks are settings applied to the engine that wraps the AI. That is why the model cannot override them.


Key Concepts

CLAUDE.md vs Hooks

CLAUDE.md   →  Request to Claude model  →  Model can ignore it
Hooks       →  Enforced by Claude Code engine  →  Model cannot override it

Who Triggers Hooks — The Claude Code Engine

Hooks are triggered by the Claude Code engine (the program), not the Claude model (the AI).

1. Claude model decides: "I'll run rm -rf / via Bash"
2. Claude Code engine intercepts → checks settings.json
3. Calls security-gate.sh
4. Script returns exit 2
5. Engine blocks the action
6. Only the result is sent back to the Claude model

The Claude model is unaware of steps 3–5. The engine handles it and only reports the outcome.


Configuration File Location

~/.claude/settings.json       # Global (all projects)
.claude/settings.json         # Project-specific (team-shareable)

Key Event Types

EventWhen it firesCan block?
PreToolUseBefore a tool executesYes (exit 2)
PostToolUseAfter a tool completesNo (post-processing only)
UserPromptSubmitWhen user submits a prompt-
StopWhen Claude finishes responding-
SubagentStopWhen a subagent completes-
SessionStart/EndSession start or end-

Exit Code — The Core of Blocking

exit 0  →  Allow, continue
exit 1  →  Warning only, continues anyway
exit 2  →  Block, send error message to Claude

For security purposes, always use exit 2. exit 1 only warns — it does not block.


settings.json Structure

settings.json acts as the hub that connects events to commands.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "command": "npx prettier --write \"$TOOL_INPUT_FILE_PATH\""
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash",
        "command": "~/.claude/hooks/security-gate.sh"
      }
    ]
  }
}

Simple vs Complex Cases

// Simple — write the command inline
"command": "npx prettier --write \"$TOOL_INPUT_FILE_PATH\""

// Complex — separate into a script file
"command": "~/.claude/hooks/security-gate.sh"

Security Gate Script Example

#!/bin/bash
INPUT=$(cat)                          # Read JSON sent via stdin from Claude Code
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# Block rm -rf pattern
if echo "$CMD" | grep -qE 'rm\s+-rf\s+/'; then
  echo "Dangerous command detected: $CMD" >&2   # >&2 = output to stderr (unrelated to blocking)
  exit 2                                        # Actual blocking signal
fi

# Block direct commits to main branch
if echo "$CMD" | grep -q "git commit" && \
   [ "$(git branch --show-current 2>/dev/null)" = "main" ]; then
  echo "Direct commits to main branch are not allowed" >&2
  exit 2
fi

exit 0

>&2 and exit 2 are separate concerns. >&2 controls where the message is sent. exit 2 is what actually blocks the action.


Full Connection Structure

settings.json (hub)
├── PreToolUse  → security-gate.sh  (can block)
└── PostToolUse → prettier          (post-processing)

Each script is independent — they do not call each other. The Claude Code engine reads settings.json at each event and calls them separately.


TL;DR

  • Hooks are enforced by the Claude Code engine — the model cannot override them
  • PreToolUse is the most powerful — can block before execution
  • exit 2 = block, exit 1 = warning only, exit 0 = allow
  • >&2 controls message output direction; blocking is decided by exit 2
  • settings.json is the hub — each script is fully independent
  • CLAUDE.md is the guideline. Hooks is the enforcer.

0개의 댓글