본문으로 건너뛰기

© 2026 Molayo

Zenn헤드라인2026. 05. 14. 08:35

Claude Code의 hook 메커니즘: JSON과 exit 코드로 만드는 최소한의 안전장치

요약

Claude Code의 'hook' 메커니즘은 도구(tool) 실행 전후에 커스텀 로직을 삽입하는 안전장치입니다. 이 기사는 쉘 스크립트 예시를 통해 hook 내부에서 JSON 데이터가 어떻게 흐르고, exit 코드가 어떤 의미로 사용되는지 구체적으로 설명합니다. 이를 이해하면 개발자가 원하는 조건(예: 특정 명령어 차단)에 따라 도구 실행을 제어하는 최소한의 안전장치를 직접 만들 수 있습니다.

핵심 포인트

  • hook은 Claude Code가 외부 도구를 사용하기 직전에 쉘 명령어를 호출하여 작동한다.
  • 훅 스크립트는 표준 입력(stdin)으로 JSON 문자열을 받고, `jq`와 같은 도구로 필요한 데이터를 추출해야 한다.
  • 특정 조건에서 `exit 2`를 반환하고 에러 메시지를 출력하면, Claude Code는 이를 '중단' 사유로 해석하여 다음 행동을 결정한다.
  • 훅의 동작 여부를 확인하기 위해 임시 파일에 JSON 내용을 저장하는 디버깅 hook을 사용하는 것이 매우 유용하다.

Claude Code에는 「hook」이라는, 도구의 실행 전후에 작은 처리를 끼워 넣는 메커니즘이 있습니다. 공식 문서에 적혀 있기는 하지만, 처음 읽었을 때는 「여러 종류의 hook이 있구나」 하고 멈춰버리기 쉽습니다.

이 기사는 hook 안에서 실제로 어떤 일이 일어나고 있는지――JSON이 어떻게 흐르고, exit 코드(exit code)로 무엇이 결정되는지――를, 5줄짜리 쉘 스크립트(shell script) 예시를 통해 다시 구성하여 설명하는 해설입니다. 쉘(shell)을 조금이라도 쓸 줄 아는 사람이라면, 다 읽을 때쯤에는 스스로 안전장치를 하나 만들 수 있게 될 것입니다.

hook의 동작 메커니즘

Claude Code가 도구(Bash, Read, Edit 등)를 사용하기 직전에, 설정에서 지정한 쉘 명령어를 호출합니다. 호출된 명령어는 표준 입력(standard input)으로부터 JSON 문자열을 받아, 어떤 처리를 수행한 뒤, 표준 출력(standard output)과 표준 에러 출력(standard error output)에 무언가를 쓰고, exit 코드(exit code)를 반환합니다.

흐름도는 다음과 같습니다.

Claude Code
│
│ 도구를 사용하고 싶음 (예: Bash로 "ls -la" 실행)
...

JSON의 내용은 도구의 종류에 따라 조금 다릅니다. Bash라면 tool_input.command에 명령 문자열이, Read/Edit/Write라면 tool_input.file_path에 파일 경로가 들어 있습니다. 이것만 기억하면 hook의 90%는 작성할 수 있습니다.

5줄로 작성 가능한 최소한의 예시

rm -rf 명령을 받으면 중단한다」는 hook을 작성해 보겠습니다.

#!/bin/bash
INPUT=$(cat)
CMD=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
...

5줄(공백을 포함하면 6줄)입니다. 내용을 순서대로 살펴보겠습니다.

1행: 쉘의 종류를 선언합니다. 이는 관용구입니다.

2행: 표준 입력의 모든 내용을 INPUT이라는 변수에 넣습니다. hook 호출 단계에서 JSON 문자열이 표준 입력으로 흘러 들어옵니다.

3행: jq라는 JSON 처리 도구를 사용하여 tool_input.command 키의 값을 추출합니다. // empty 부분은 만약 키가 없다면 빈 문자열을 반환한다는 보험입니다.

4행: 추출한 명령 문자열에 rm -rf 또는 rm -fr 패턴이 포함되어 있다면, exit 2로 hook 처리를 종료합니다. exit 코드 2는 「중단」을 의미합니다.

5행: 여기까지 왔다면 아무런 문제가 없으므로, exit 0으로 「통과」 신호를 보냅니다.

이 스크립트를 ~/.claude/hooks/rm-guard.sh에 저장하고, 실행 권한을 부여합니다.

chmod +x ~/.claude/hooks/rm-guard.sh

그리고 ~/.claude/settings.json에 「Bash 도구를 실행하기 전에 이 스크립트를 거쳐줘」라고 등록합니다.

{
"hooks": {
"PreToolUse": [
...

이것만으로 Claude Code가 rm -rf 명령을 내리는 순간, 반드시 중단되는 상태가 됩니다.

JSON 내용 확인 절차

hook을 작성하기 시작하면, 「tool_input 안의 어떤 키에 무엇이 들어 있는가?」가 궁금해집니다. 공식 문서를 보는 것이 정석이지만, 또 다른 지름길이 있습니다.

「실행될 때마다 받은 JSON을 파일로 쓰는 것만 하는 hook」을 일시적으로 등록하여 실제 내용을 확인하는 것이 빠릅니다.

#!/bin/bash
cat > "/tmp/hook-debug-$(date +%s).json"
exit 0

이것을 ~/.claude/hooks/debug-dump.sh로 등록하면, Claude Code가 도구를 사용할 때마다 /tmp/hook-debug-{시각}.json이라는 파일이 늘어납니다. 내용을 jq .로 정렬해서 보면, 「아, 여기에 command가 들어 있구나」, 「session_id의 형태는 이런 UUID구나」라는 것을 직접적인 경로로 확인할 수 있습니다.

5분이면 결과를 알 수 있으므로, 새로운 hook 패턴을 시도할 때의 첫 단계로 매우 편리합니다. 공식 문서의 설명과 실제 내용의 대응 관계를 확인하면, 그 이후의 hook을 작성하는 것이 갑자기 쉬워질 것입니다.

exit 코드의 구분 사용

exit 코드의미
0통과. Claude Code는 그대로 도구 (tool)를 실행한다.
...
exit 2를 사용할 때는, 표준 에러 출력 (standard error output)에 「왜 중단했는지」에 대한 메시지를 작성해 두면, Claude Code가 그 이유를 해석하여 다음 동작을 판정합니다. 예를 들어 다음과 같습니다.
echo "인증 관련 파일에 대한 액세스는 중단했습니다: $TARGET" >&2
exit 2

이렇게 하면 Claude Code는 「아, 인증 파일에 접근하려다 중단되었구나, 다른 방법을 생각하자」라고 판단하는 경로로 들어갈 수 있습니다. 내용이 없는 exit 2라면 Claude Code도 무엇이 일어났는지 판단할 수 없으므로, 메시지는 작성해 두는 것이 좋습니다.

자주 빠지는 함정

첫째, jq가 설치되어 있지 않은 환경에서는 동작하지 않는다. 대부분의 상황에서 jq는 필요하므로, Mac이라면 brew install jq, Ubuntu라면 apt install jq로 설치해 둔다.

둘째, 쉘 스크립트 (shell script)에 실행 권한이 부여되지 않았다. chmod +x를 잊으면 Claude Code는 스크립트를 호출하지 못하고, hook은 없는 것으로 간주하여 동작한다. 「hook을 설정했는데도 동작하지 않는다」는 가장 큰 원인은 이것이다.

셋째, 설정 파일 ~/.claude/settings.json의 JSON 구문 오류. 끝부분의 불필요한 ,나 큰따옴표 오류로 인해 파일 전체의 읽기 단계에서 실패한다. 실패했을 때의 신호는 나오지 않으므로, 「설정했는데도 동작하지 않는다」고 느껴진다면 jq . ~/.claude/settings.json으로 구문을 가장 먼저 확인한다.

넷째, hook 안에서 표준 출력 (standard output)에 불필요한 내용을 작성한다. 표준 출력의 내용은 경우에 따라 Claude Code의 판단 입력이 되므로, 불필요한 echo는 삼간다. 디버깅 단계에서는 표준 에러 출력(>&2)에 작성하는 것이 정답이다.

스스로 키워나가는 방향

5줄짜리 rm-guard.sh에서 시작하여, 익숙해지면 조건을 추가하고 싶어질 것입니다. 「이것만은 반드시 지키고 싶다」는 규율을 하나씩 쉘 스크립트 형태로 늘려가는 느낌입니다.

공개된 장소에 동일한 계통의 모음이 공유되고 있습니다. 예를 들어 https://github.com/yurukusa/cc-safe-setup (MIT 라이선스)에는 hook 예시가 700건 넘게 있습니다. 스스로 전부 작성하기 전에 기존 형태를 참고하면 「아, 이런 작성 방식도 있구나」라고 배울 수 있습니다.

공식 문서는 https://docs.claude.com/en/docs/claude-code/hooks입니다. PostToolUseStop, SessionStart 등, PreToolUse 이외의 진입점에 대한 설명도 있습니다.

쉘을 조금 쓸 줄 아는 사람에게 hook은 「자신의 작업 규율을 코드로 구현하는 장소」로서 흥미로운 영역이라고 생각합니다. 5줄부터 시작할 수 있으니, 관심 있는 분은 오늘 밤 1시간 동안 시도해 보세요.

AI 자동 생성 콘텐츠

본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
2

댓글

0