본문 바로가기
Claude

[Claude Code] Hooks 분석 : 개발 워크플로우를 통제하는 자동화

by coding_whale 2026. 5. 18.
반응형

인공지능 기반 개발 도구의 시대에서 가장 중요한 과제는 "어떻게 하면 AI의 자율성을 살리면서도 사고를 치지 않게 제어할 것인가"이다. 클로드 코드(Claude Code)는 마치 손이 아주 빠른 신입 개발자 같아서 일을 척척 해내지만, 가끔 너무 성급하게 중요한 설정을 건드리거나 코드 포맷을 망가뜨리는 실수를 하곤 한다.

이러한 문제를 깔끔하게 해결해 주는 안전장치가 바로 훅(Hooks)이다. 쉽게 말해 훅은 "클로드 코드가 일하는 중간중간에 우리가 미리 걸어두는 자동 센서이자 브레이크"다. 

 

[Claude Code] 서브에이전트(Subagents) 시스템

1. 도입부 (Introduction)대규모 언어 모델(LLM)을 활용한 개발에서 가장 큰 적은 '노이즈'다. 복잡한 버그를 잡기 위해 수십 개의 파일을 읽고 방대한 로그를 분석하다 보면, 정작 중요한 지침들이 컨

myblog01150.tistory.com

 

 

1. 핵심 개념 및 이론: 훅(Hooks)이란 무엇인가?

클로드 코드에서 훅(Hooks)은 일종의 "센서가 달린 자동 경비원"과 같다. 클로드 코드가 프로젝트 안에서 움직이는 라이프사이클(생명 주기)의 중요 길목마다 경비원이 서서 감시하는 것이다.

단순히 알림만 보내는 것이 아니라, 클로드 코드가 위험한 행동을 하려고 하면 "잠깐, 그 문은 열지 마!(차단)"라고 막아서거나, "이 도구를 쓰기 전에 사용 설명서부터 읽어봐(컨텍스트 주입)" 하고 개입할 수 있다.

 

2. 상세 가이드 및 심층 분석

2.1. 훅 이벤트 라이프사이클: 언제 실행될까?

클로드 코드가 일하는 순서에 따라 발생하는 핵심 이벤트들을 알기 쉽게 정리했다.

이벤트 이름 한 줄 비유 차단 가능 여부 실제 언제 사용하나요?
SessionStart "출근 인사와 오늘의 업무 브리핑" No 오늘 해야 할 일이나 현재 브랜치 정보를 클로드에게 알려줄 때
Setup "작업 시작 전 장비 점검" No 프로젝트에 필요한 라이브러리가 잘 깔려 있는지 체크할 때
UserPromptSubmit "질문지를 건네받기 직전 검사" Yes (Exit 2) 질문에 비밀번호나 API 키 같은 민감 정보가 포함되어 있는지 검사할 때
PreToolUse "도구를 쓰기 직전 검문검색" Yes (JSON) rm -rf 같은 컴퓨터를 포맷하는 명령어를 쓰지 못하게 원천 차단할 때
PermissionRequest "동의 구하기 직전 자동 승인" Yes (JSON) 안전한 명령어(예: 테스트 실행)는 묻지 말고 알아서 통과시킬 때
PostToolUse "작업이 끝난 뒤 뒷정리" No 소스코드를 수정하자마자 자동으로 예쁘게 줄바꿈(포맷팅)을 맞출 때
PostToolUseFailure "사고 수습 회의" No 에러가 나서 도구가 실패했을 때 복구 힌트를 제공할 때
Stop "퇴근 전 최종 업무 검사" Yes (Exit 2) "테스트가 깨졌으니 퇴근하지 말고 고쳐라" 하고 다시 일 시킬 때
CwdChanged "방을 옮길 때마다 공기 청정" No 폴더를 바꿀 때마다 그 폴더에 맞는 환경 변수를 자동으로 바꿀 때

 

2.2. Matcher 패턴 설계: 누구에게 작동시킬까?

훅을 만들 때 "모든 상황"에 작동하게 하면 컴퓨터가 너무 느려진다. 그래서 "특정 상황에만 작동해라" 하고 필터를 거는 것이 matcher다.

  • 비워두거나 "*": 무조건 작동한다. (예: 어떤 일이 생기든 무조건 알림을 울릴 때)
  • 단순히 글자만 쓰기 ("Bash", "Edit|Write"): 해당 도구를 쓸 때만 딱 작동한다.
  • 정규식 쓰기 ("mcp__.*__write.*"): 조금 더 복잡한 패턴을 찾는다. 예를 들어, 외부 서버(MCP)의 도구들 중에서 글쓰기 기능이 있는 도구만 콕 집어 감시할 때 유용하다.

 

2.3. Exec Form vs Shell Form: 컴퓨터에게 일 시키는 두 가지 방식

훅 유형이 "type": "command"일 때, 내부적으로 명령어를 실행하는 방식이 두 가지로 나뉜다. 이 차이를 아는 것이 매우 중요하다

1. Exec Form (안전제일! 적극 추천)

args 배열을 사용해 옵션들을 쪼개서 적는 방식이다.

  • 장점: 중간에 쉘(sh, bash 등)이 개입하지 않고 컴퓨터가 바로 프로그램을 실행한다. 공백이나 한글, 특수문자가 섞여 있어도 컴퓨터가 오해하지 않고 안전하게 한 묶음으로 받아들인다. 해킹(인젝션 공격) 위험이 전혀 없다.
  • 주의점: 파이프라인(|)이나 리다이렉션(>) 같은 편리한 쉘 기호들을 쓸 수 없다.

 

2. Shell Form (편리함 중심)

args 필드를 아예 안 적고 command에 한 줄로 길게 적는 방식이다.

  • 장점: 우리가 평소에 터미널에 치는 것처럼 &&나 > 같은 기호를 마음껏 쓸 수 있어 편리하다.
  • 주의점: 파일 이름이나 경로에 공백이 있으면 명령어가 중간에 쪼개져서 에러가 난다. 보안상 위장 명령어 공격에 취약할 수 있어 조심해야 한다.

 

 

2.4. 실무 필수 시나리오 4선 구현 코드

시나리오 1. 지키고 싶은 핵심 파일 편집 강제 차단하기 (PreToolUse)

클로드가 프로젝트 안에서 .env 파일(비밀번호가 들어있는 파일)을 멋대로 고치지 못하게 경비원을 세우는 방법이다.

먼저 검문소 역할을 할 스크립트를 작성하여 .claude/hooks/protect_files.sh 경로에 저장하고 실행 권한(chmod +x)을 부여한다.

#!/bin/bash
# .claude/hooks/protect_files.sh
# 클로드가 중요한 파일을 고치려고 하면 감시하고 차단하는 스크립트다.

# 클로드가 건네준 작업 정보(JSON 형식)를 통째로 읽는다.
INPUT_JSON=$(cat)

# 그 정보 중에서 클로드가 고치려고 하는 '대상 파일의 경로'만 쏙 뽑아낸다.
TARGET_PATH=$(echo "$INPUT_JSON" | jq -r '.tool_input.file_path // empty')

# 고치려는 파일 정보가 없으면 그냥 안심하고 통과시킨다.
if [ -z "$TARGET_PATH" ]; then
    exit 0
fi

# 절대로 고치면 안 되는 금지어(민감 파일 패턴) 목록을 정한다.
PROTECTED_PATTERNS=(".env" "settings.local.json" "deploy.pem" "secrets/")

for pattern in "${PROTECTED_PATTERNS[@]}"; do
    # 고치려는 파일 이름에 금지어가 들어있는지 검사한다.
    if [[ "$TARGET_PATH" == *"$pattern"* ]]; then
        # 금지어에 걸리면 경고 메시지를 화면에 출력하고 '종료 코드 2'를 던진다!
        # 종료 코드 2는 "당장 이 행동을 멈춰라!" 하고 시스템에 제동을 거는 약속된 신호다.
        echo "보안 경고: 중요 파일인 $TARGET_PATH ($pattern) 은 고칠 수 없습니다!" >&2
        exit 2
    fi
done

# 검문을 무사히 통과하면 성공(0) 코드를 보낸다.
exit 0

이 경비원 스크립트를 클로드 코드의 규칙에 등록하기 위해 프로젝트 폴더의 .claude/settings.json 파일을 열고 다음과 같이 설정해 준다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "if": "Edit(*)",
            "command": "bash",
            "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/protect_files.sh"],
            "statusMessage": "보안 접근성 통제 체계 검증 중..."
          },
          {
            "type": "command",
            "if": "Write(*)",
            "command": "bash",
            "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/protect_files.sh"],
            "statusMessage": "보안 접근성 통제 체계 검증 중..."
          }
        ]
      }
    ]
  }
}

 

시나리오 2. 코드를 고치면 자동으로 줄 맞춤 정렬하기 (PostToolUse)

클로드가 코드를 다 고치고 나면, 자동으로 코드 정리 도구인 prettier를 실행해 줄바꿈과 들여쓰기를 예쁘게 맞춰주는 설정이다.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "node",
            "args": [
              "${CLAUDE_PROJECT_DIR}/node_modules/prettier/bin/prettier.cjs",
              "--write",
              "${tool_input.file_path}"
            ],
            "statusMessage": "Prettier 포맷팅 코드 스타일 가다듬는 중..."
          }
        ]
      }
    ]
  }
}
  • ${tool_input.file_path} 덕분에 클로드가 방금 만진 그 파일만 찾아서 정확하게 이쁘게 정렬해 준다.

 

시나리오 3. 폴더를 바꿀 때마다 개발 환경 설정(direnv) 자동 적용하기

개발할 때 폴더마다 사용하는 비밀 환경 변수가 다를 때가 있다. 클로드가 cd 명령으로 폴더를 옮겨 다닐 때마다 그 폴더에 맞는 환경 설정 파일(.envrc)을 알아서 읽어서 세팅하게 만드는 훅이다.

전체 프로젝트에 적용되도록 개인 홈 폴더 아래 ~/.claude/settings.json에 적어준다.

{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash >> \"$CLAUDE_ENV_FILE\"",
            "statusMessage": "세션 기동 시 direnv 전역 변수 동기화 중..."
          }
        ]
      }
    ],
    "CwdChanged": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "direnv export bash >> \"$CLAUDE_ENV_FILE\"",
            "statusMessage": "작업 경로 변경에 따른 direnv 동적 변수 갱신 중..."
          }
        ]
      }
    ]
  }
}

 

시나리오 4. 클로드가 승인을 기다릴 때 컴퓨터 화면에 알림창 띄우기

클로드가 복잡한 작업을 하다가 "사용자님, 이거 실행해도 될까요?" 하고 승인을 기다리거나 작업을 다 마쳤을 때, 터미널을 안 보고 있어도 알림이 오도록 내 운영체제에 맞게 설정하는 방법이다. 전역 파일인 ~/.claude/settings.json에 추가하여 세팅한다.

matcher를 permission_prompt|idle_prompt로 지정했기 때문에 클로드가 권한 승인을 기다리거나(permission_prompt), 모든 일을 마치고 쉴 때(idle_prompt) 내 화면에 정확하게 푸시 알림이 발송된다.

{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt|idle_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "osascript",
            "args": [
              "-e",
              "display notification \"클로드 코드가 대기 중입니다. 작업 흐름을 검토하고 승인해 주십시오.\" with title \"Claude Code 알림\""
            ]
          }
        ]
      }
    ]
  }
}

 

2.5. 구조화된 JSON 입출력 통제 규격

단순히 "된다/안된다"를 넘어 세밀하게 조종하고 싶을 때는, 훅이 끝날 때 화면에 JSON 형식의 텍스트를 출력하도록 프로그래밍하면 된다. 컴퓨터는 훅이 성공(종료 코드 0)하면서 출력 결과에 단 하나의 JSON만 있을 때 이를 분석해서 규칙에 반영한다.

자주 쓰는 제어 옵션들

{
  "continue": true,
  "stopReason": "에러가 발생해서 클로드 코드를 강제로 정지시키고 화면에 보여줄 메시지",
  "suppressOutput": false,
  "systemMessage": "클라이언트 화면 전면에 빨간색 경고창으로 띄워줄 공지사항",
  "terminalSequence": "\u001b]777;notify;알림 제목;알림 내용\u0007"
}
  • continue: 이걸 false로 주면 클로드가 하던 행동을 그 자리에서 즉시 멈추고 사용자의 입력을 기다리는 대기 상태로 돌아간다.

 

 

3. 실무 팁 및 주의사항 (이것만은 꼭 조심하자!)

3.1. 보안 정책의 절대 법칙: 훅이 이길까, 거부 규칙이 이길까?

"내가 훅으로 특정 도구 실행을 자동으로 허용해 줬으니까 괜찮겠지?" 라고 오해하기 쉽다. 하지만 클로드 코드의 보안 위계질서는 매우 완고하다.

설령 훅이 허용(allow)해 줬더라도, 전역 설정 파일의 거부 목록(permissions.deny)에 해당 명령어가 적혀 있으면 시스템은 무조건 거부 목록을 우선순위로 적용하여 차단한다. 

우선순위 요약: 거부 규칙(Deny) > 훅 허용(Hook Allow) > 물어보기(Ask)

 

3.2. JSON 검증 실패 에러: 갑자기 작동을 안 해요!

훅을 열심히 만들어 등록했는데 갑자기 JSON validation failed 같은 이상한 에러가 나면서 훅이 뻗는 경우가 있다.

이건 훅 스크립트에 문제가 있는 게 아니라, 내 터미널 환경 설정 파일(.bashrc 혹은 .zshrc)에 환영 문구 같은 쓸데없는 텍스트(echo "Hello User!" 등)가 적혀 있어서 그렇다. 훅이 실행될 때 이 환영 문구가 훅의 출력 결과(JSON) 앞에 섞여서 들어가면서 컴퓨터가 JSON을 읽지 못하고 오작동하는 것이다.

# 오염되어 망가진 출력의 예
Zsh 환경 로드 완료 (Apple Silicon ARM64) <- 이 쓰레기 글자가 앞에 섞여버림!
{"hookSpecificOutput": {"hookEventName": "PreToolUse", "permissionDecision": "allow"}}

이를 해결하려면 터미널 환경 설정 파일의 모든 echo 지점을 다음과 같이 대화형 세션 체크 조건절로 감싸주어야 한다.

# ~/.zshrc 또는 ~/.bashrc 파일 내부 조치
# 실제로 사람이 터미널을 열고 대화식(i)으로 쓸 때만 환영 인사를 하도록 가둔다.
if [[ $- == *i* ]]; then
    echo "Zsh 환경 로드 완료 (Apple Silicon ARM64)"
fi
  • 이렇게 해주면 백그라운드에서 조용히 실행되는 훅 세션에서는 문구가 출력되지 않아 JSON 오염을 원천 차단할 수 있다.

 

3.3. Stop 훅의 무한 루프 지옥 방지하기

Stop 훅은 클로드가 일을 끝내고 쉴 때 작동한다. 이때 우리가 훅으로 "코드가 잘 되는지 테스트해보고, 통과 안 하면 멈추지 말고 계속 고쳐라!" 하고 강제로 차단(decision: block)하고 지시를 내릴 수 있다.

하지만 조심해야 한다. 클로드가 지시를 받고 열심히 코드를 고친 다음, 일을 끝내고 또 쉬려고 할 때 또 똑같은 Stop 훅이 작동해서 클로드에게 계속 일을 시키는 무한 굴레에 빠지게 된다.

이 무한 루프 지옥을 막으려면 훅 스크립트가 실행될 때 "이미 멈춤 훅에 의해 가동되어 한 번 고치고 온 상태인가?"를 감시하는 변수인 stop_hook_active를 반드시 체크해서 예외 통과를 시켜주어야 한다.

#!/bin/bash
# .claude/hooks/safe_stop_check.sh

INPUT_JSON=$(cat)

# 이미 멈춤 훅에 의해 연장해서 일하고 돌아온 상태인지 확인한다.
STOP_HOOK_ACTIVE=$(echo "$INPUT_JSON" | jq -r '.stop_hook_active')

if [ "$STOP_HOOK_ACTIVE" = "true" ]; then
    # 이미 일하고 왔다면 또 막지 말고 쉴 수 있도록 통과(0)시켜서 무한 루프를 멈춘다!
    exit 0
fi

# ... 이곳에 실제 빌드 검증 및 테스트 구동 로직을 작성한다 ...
# 만약 빌드가 깨졌다면 일을 더 하라고 지시한다.
if ! npm run build; then
    echo "{\"decision\": \"block\", \"reason\": \"방금 고친 코드 때문에 빌드가 깨졌습니다. 원인을 고치기 전까진 퇴근할 수 없습니다.\"}"
    exit 0
fi

exit 0

 

 

3. 마무리

클로드 코드의 훅(Hooks)은 복잡한 인프라나 어려운 개념이 아니다. 조금 귀찮을 수 있는 규칙과 뒷정리를 경비원(쉘 스크립트)들에게 위임해서 안전하게 관리하는 똑똑한 자동화 장치일 뿐이다.

중요한 파일에 가림막을 쳐서 해킹을 막고, 코드를 고치면 자동으로 예쁘게 정렬하게 만들며, 화면을 안 보고 쉴 때는 소리로 알림을 울리게 설정해 두자. 이렇게 나만의 자동 센서들을 이식해 놓으면, 클로드 코드는 제멋대로 행동하는 불안한 도구가 아니라 내 코딩 습관과 스타일을 파악하여 도움을 줄 것이다.

 

반응형