muaco Tech Note

Claude Codecode.claude.com

Claude Code 훅(hooks) 설정법파일 수정·커밋 전 작업 가로채기

Claude Code 훅을 설정해 위험한 명령은 막고, 수정된 파일은 기록하고, 커밋 전에는 테스트를 자동으로 돌립니다.

안녕하세요, muaco입니다.

이 글로 할 수 있는 일

이 글을 끝까지 따라 하면 Claude Code에 자동 검문소 세 개가 생깁니다. 첫째는 rm -rf 같은 지우기 명령을 막는 검문소입니다. 둘째는 Claude가 고친 파일을 목록으로 남기고 셋째는 커밋하기 전에 테스트를 먼저 돌립니다.

이런 검문소를 훅(hooks)이라고 부릅니다. 설정 파일에 몇 줄 적어 두기만 하면 Claude에게 매번 부탁하지 않아도 같은 규칙이 지켜집니다. 이 글은 2026년 10월 1일 기준 공식 문서를 보고 썼습니다.

훅이 걸리는 시점

식당 주방을 떠올려 보세요. 요리사가 재료를 쓰기 전에 한 번, 요리를 낸 뒤에 한 번 점검할 수 있습니다. 훅도 정해진 순간에만 움직이는데, 문서는 이 순간을 이벤트라고 부릅니다.

이벤트는 서른 개가 넘지만 처음에는 아래 넷만 알아도 충분합니다.

  • PreToolUse: Claude가 도구를 쓰기 직전입니다. 여기서 막으면 명령이 아예 실행되지 않습니다.
  • PostToolUse: 도구 사용이 성공한 직후입니다. 이미 실행이 끝났으므로 막지는 못하고 뒷정리나 기록을 맡습니다.
  • Stop: Claude가 답변을 마칠 때입니다.
  • SessionStart: 대화 세션이 시작되거나 다시 열릴 때입니다.

어떤 도구에 반응할지는 매처(matcher)로 고릅니다. Bash라고 쓰면 명령 실행에만, Edit|Write라고 쓰면 파일 수정과 작성 두 가지에 반응합니다.

설정 파일은 네 군데에 둘 수 있습니다

훅은 설정 파일 안의 hooks 항목에 적습니다. 어느 파일에 적느냐에 따라 적용 범위가 달라집니다.

파일 위치적용 범위팀과 공유
~/.claude/settings.json내 컴퓨터의 모든 프로젝트안 됨
.claude/settings.json이 프로젝트됨. 저장소에 커밋합니다
.claude/settings.local.json이 프로젝트, 나만안 됨. git에서 빠집니다
관리형 정책 설정회사 전체관리자가 배포합니다

같은 항목이 여러 파일에 있으면 관리형, 명령줄, 로컬, 프로젝트, 사용자 순으로 앞쪽이 이깁니다. 다만 목록 형태의 설정은 하나만 고르지 않고 합쳐서 적용합니다. 이 글에서는 팀과 나눠 쓰기 좋은 .claude/settings.json을 씁니다.

미리 갖춰야 할 것

  • Claude Code 설치와 로그인. 터미널에서 claude를 입력했을 때 대화 화면이 떠야 합니다.
  • 작업할 프로젝트 폴더. 셋째 예시는 git 저장소와 테스트 명령이 있어야 확인됩니다.
  • jq. 훅이 받은 정보를 읽어 내는 작은 프로그램입니다. 공식 예시도 jq가 PATH(터미널이 프로그램을 찾는 경로 목록)에 있어야 돈다고 적어 둡니다.
  • 운영체제. 이 글은 macOS와 Linux 기준입니다. Windows용 PowerShell 예시는 공식 문서에 따로 있습니다.

따라 하기: 검문소 세 개 세우기

준비

따라 하기
  1. 터미널에서 프로젝트 폴더로 이동한 뒤 mkdir -p .claude/hooks를 입력하세요. 훅 스크립트를 한곳에 모아 두려는 준비입니다. ls .claude를 쳤을 때 hooks가 보이면 됩니다.
  2. jq --version을 입력해 보세요. 버전 숫자가 나오면 통과이고 "command not found"가 나오면 jq부터 설치해야 합니다.

스크립트 작성

따라 하기
  1. .claude/hooks/block-rm.sh 파일을 만들고 아래 내용을 넣으세요. 공식 문서의 예시 그대로이며 명령에 rm -rf가 들어 있으면 거절합니다.
    #!/bin/bash
    # .claude/hooks/block-rm.sh
    COMMAND=$(jq -r '.tool_input.command')
    

    if echo "$COMMAND" | grep -q 'rm -rf'; then jq -n '{ hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: "Destructive command blocked by hook" } }' else exit 0 fi

  2. .claude/hooks/test-before-commit.sh 파일을 만들고 아래 내용을 넣으세요. npm test 자리에는 팀에서 실제로 쓰는 테스트 명령을 적습니다.
    #!/bin/bash
    if ! npm test >&2; then
      echo "테스트가 실패해 커밋을 멈췄습니다. 실패한 테스트를 먼저 고치세요." >&2
      exit 2
    fi
    exit 0
    여기서 핵심은 exit 2입니다. 종료 코드 2를 돌려주면 Claude Code가 커밋을 막고 안내 문구를 Claude에게 전합니다.
  3. chmod +x .claude/hooks/*.sh를 입력하세요. 실행 권한이 없으면 훅이 불리지 않습니다. ls -l .claude/hooks로 보았을 때 맨 앞에 x가 섞여 있으면 됩니다.

설정 등록

따라 하기
  1. 이미 .claude/settings.json이 있다면 파일을 새로 만들지 말고 hooks 항목만 옮겨 붙이세요. 통째로 덮어쓰면 팀이 넣어 둔 권한 설정이 사라집니다. 파일이 없다면 아래 내용으로 새로 만듭니다.
    {
      "hooks": {
        "PreToolUse": [
          {
            "matcher": "Bash",
            "hooks": [
              {
                "type": "command",
                "if": "Bash(rm *)",
                "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/block-rm.sh",
                "args": []
              },
              {
                "type": "command",
                "if": "Bash(git commit *)",
                "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/test-before-commit.sh",
                "args": []
              }
            ]
          }
        ],
        "PostToolUse": [
          {
            "matcher": "Edit|Write",
            "hooks": [
              {
                "type": "command",
                "command": "jq -r '.tool_input.file_path' >> \"$CLAUDE_PROJECT_DIR/.claude/edited-files.log\""
              }
            ]
          }
        ]
      }
    }
  2. 파일을 저장하세요. 훅 설정은 저장하는 순간 실행 중인 세션에도 다시 읽히므로 Claude Code를 재시작하지 않아도 됩니다.

확인

따라 하기
  1. Claude Code에서 /hooks를 입력하세요. PreToolUse와 PostToolUse 옆에 등록된 훅 개수가 보이면 제대로 읽힌 상태입니다. 이 화면은 보기 전용이라 여기서 고치지는 못합니다.
  2. 시험은 반드시 빈 폴더로만 하세요. 훅이 제대로 걸리지 않았다면 실제로 지워집니다. mkdir hook-test로 빈 폴더를 만든 뒤 Claude에게 "rm -rf로 hook-test 폴더를 지워 줘"라고 부탁합니다. "Destructive command blocked by hook"이라는 문구와 함께 거절되면 성공입니다.
  3. Claude에게 아무 파일이나 한 줄 고쳐 달라고 해 보세요. 그다음 cat .claude/edited-files.log를 입력했을 때 고친 파일 경로가 찍혀 있으면 기록 훅이 도는 상태입니다.
  4. 테스트가 일부러 실패하는 상태에서 Claude에게 커밋을 부탁해 보세요. 커밋이 멈추고 Claude가 실패 원인을 살피기 시작하면 셋째 훅도 제대로 걸린 상태입니다.

막히기 쉬운 세 군데

/hooks에 아무것도 안 보입니다

무엇이 보이나요? 훅 개수가 0이거나, 세션을 시작할 때 Settings Error 창이 뜹니다. 설정 파일의 JSON 문법이 틀리면 Claude Code가 그 파일을 건너뛰기 때문입니다.

이럴 때는 /status를 입력해 Setting sources 줄에 Shared project 설정이 있는지 보세요. 없다면 claude doctor로 거부된 항목을 확인하고 쉼표나 괄호가 빠진 곳을 고칩니다.

훅은 등록됐는데 막히지 않습니다

스크립트가 exit 1로 끝나면 Claude Code는 이를 막지 않아도 되는 오류로 보고 그대로 진행합니다. 막는 힘은 종료 코드 2나 permissionDecision: "deny"에만 있습니다.

스크립트 끝의 종료 코드를 확인해 보세요. 실행 권한이 없거나 경로가 틀린 경우도 있으니 claude --debug-file /tmp/claude-debug.log로 시작해 기록을 열어 봅니다. 경로를 못 찾았는지, 실행 권한이 없는지가 이 기록에 남습니다.

파일 수정 훅으로 변경을 되돌리려 했습니다

PostToolUse에서 종료 코드 2를 돌려줘도 파일은 이미 고쳐진 뒤입니다. 문서에 따르면 이 경우 오류 문구만 Claude에게 보여 줍니다.

작업 자체를 막아야 한다면 PreToolUse에 거세요. PostToolUse는 기록, 알림, 뒷정리처럼 이미 일어난 일을 다루는 자리입니다.

여기서 더 나아가려면

훅이 여럿 쌓여 헷갈릴 때는 설정에 "disableAllHooks": true를 넣어 잠시 모두 끌 수 있습니다. 명령 대신 "type": "prompt"로 Claude 모델에게 판단을 맡기는 훅도 있습니다. 세션이 시작될 때 현재 브랜치 정보를 알려 주는 SessionStart 훅부터 하나 더 만들어 보세요.

이상으로 글 마치겠습니다.

출처

#Claude Code#훅#hooks#설정#settings.json#자동화#테스트#커밋

같은 분류의 글