본문 바로가기
Claude Code agent

Claude Code Hooks로 파일 저장 시 자동 포맷팅 걸기

by 오소리 이랩 2026. 8. 5.
Claude Code 활용 팁

Claude Code로 코드를 저장할 때마다 포맷터와 린트를 수동으로 돌리고 계신가요?
Hooks를 한 번만 설정하면, 파일 저장과 동시에 자동으로 코드가 정리됩니다.

📌 3줄 요약

  • Hooks는 Claude Code에서 파일 저장 시 포맷터·린트를 자동 실행해주는 기능입니다.
  • settings.jsonPostToolUse 이벤트로 등록하며, matcher로 Write|Edit을 지정합니다.
  • 포맷팅 → 린트 순서로 복합 Hook을 걸면 코드 스타일과 품질을 동시에 관리할 수 있습니다.

Hooks가 필요한 이유와 동작 원리

Claude Code로 코드를 작성하다 보면, 파일을 저장할 때마다 직접 포맷터를 돌리거나 린트(lint) 검사를 실행해야 할 때가 있습니다. 매번 수동으로 명령어를 치는 건 번거롭고, 깜빡 잊으면 정리 안 된 코드가 그대로 남습니다.

특히 여러 파일을 동시에 수정하는 작업에서는 한두 파일을 빠뜨리기 쉬워서, 나중에 코드 리뷰 때 지적받는 일이 생기기도 합니다. 이런 반복 작업을 사람이 기억에 의존해서 처리하는 건 비효율적이고, 실수가 쌓이면 프로젝트 전체 코드 품질이 떨어집니다.

Hooks는 Claude Code가 특정 동작을 수행할 때 자동으로 셸 명령어를 실행해주는 기능입니다. 쉽게 말하면, "파일을 저장하면 이 명령어를 대신 돌려줘"라고 미리 등록해두는 겁니다. 일종의 자동화 트리거라고 생각하시면 됩니다. 사람이 직접 명령어를 입력하지 않아도, 지정된 이벤트가 발생하면 시스템이 알아서 실행해줍니다.

🔍 Hooks 이벤트 종류

Hooks는 settings.json에 정의하며, 이벤트 종류에 따라 실행 시점이 달라집니다. 파일 저장과 관련된 이벤트는 PostToolUse로, Write나 Edit 같은 도구가 실행된 직후에 작동합니다. 이 외에도 PreToolUse(도구 실행 전), Notification(알림 발생 시) 같은 이벤트가 있어서 다양한 시점에 자동화를 걸 수 있습니다. 어떤 이벤트를 선택하느냐에 따라 Hook의 활용 범위가 크게 달라지므로, 각 이벤트의 실행 시점을 정확히 이해하는 게 중요합니다.

 

💬 제가 직접 써보니, Hooks를 한 번 설정해두면 포맷팅을 까먹을 일이 아예 없어집니다. 다만 처음에 설정 문법을 정확히 맞춰야 해서, 아래 절차를 따라 하시길 권장합니다.

settings.json에 자동 포맷팅 Hook 등록하기

Hooks 설정은 프로젝트 루트의 .claude/settings.json 파일에 작성합니다. 파일이 없다면 .claude 폴더를 만들고 settings.json을 새로 생성하면 됩니다. 이미 settings.json이 있는 경우에는 기존 내용을 건드리지 말고, hooks 키만 추가하면 됩니다.

아래는 Python 파일이 저장될 때마다 black 포맷터를 자동 실행하는 설정 예시입니다.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "black \"$CLAUDE_FILE_PATH\" --quiet 2>/dev/null || true"
      }
    ]
  }
}

matcher는 어떤 도구가 사용됐을 때 Hook을 실행할지 결정합니다. Write와 Edit를 모두 지정해야 새 파일 생성과 기존 파일 수정 양쪽에서 포맷팅이 작동합니다. Write만 넣으면 새 파일 생성 시에만, Edit만 넣으면 기존 파일 수정 시에만 Hook이 실행되므로 빠뜨리지 않도록 주의해주세요.

command에는 실행할 셸 명령어를 넣습니다. $CLAUDE_FILE_PATH는 Claude Code가 방금 저장한 파일의 경로를 자동으로 넘겨주는 환경 변수입니다. 이 변수 덕분에 어떤 파일이 수정됐는지 직접 추적할 필요 없이, Hook이 알아서 해당 파일에만 포맷터를 적용합니다.

⚠️ 주의: 끝에 || true를 붙이는 이유는, 포맷터가 실패해도 Claude Code 작업 흐름이 중단되지 않도록 하기 위해서입니다. 이 부분을 빠뜨리면 포맷터 에러 한 번에 전체 작업이 멈출 수 있으니 꼭 넣어주십시오. 예를 들어 .md 파일처럼 black이 처리할 수 없는 파일이 저장됐을 때, || true가 없으면 에러가 발생하면서 Claude Code가 멈춰버립니다.

 

Claude Code Hooks로 파일 저장 시 자동 포맷팅 걸기

💬 제가 직접 설정해보니, JSON 문법 오류가 가장 흔한 실수였습니다. 쉼표 하나 빠져도 Hook 전체가 무시되니, 저장 후 Claude Code를 재시작해서 에러 없이 로드되는지 확인하는 게 좋습니다.

린트 검사까지 함께 거는 복합 Hook 설정

포맷팅만으로는 코드 품질을 보장하기 어렵습니다. 린트 검사를 함께 걸면 문법 오류나 미사용 변수 같은 문제도 저장 즉시 잡아낼 수 있습니다.

🔍 포맷팅 vs 린트의 차이

린트는 코드의 논리적 오류나 잠재적 버그까지 감지하기 때문에, 포맷팅과는 검사 영역이 다릅니다. 두 가지를 함께 사용해야 코드 스타일과 품질을 동시에 관리할 수 있습니다.

Python 프로젝트라면 ruffflake8, JavaScript 프로젝트라면 eslint를 추가하면 됩니다. 아래는 포맷팅과 린트를 순서대로 실행하는 복합 Hook 예시입니다.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "black \"$CLAUDE_FILE_PATH\" --quiet 2>/dev/null; ruff check \"$CLAUDE_FILE_PATH\" --fix --quiet 2>/dev/null || true"
      }
    ]
  }
}

세미콜론(;)으로 명령어를 연결하면 앞 명령어 실행 후 뒤 명령어가 순차로 실행됩니다. 포맷팅을 먼저 돌리고 린트를 나중에 돌리는 순서가 중요합니다. 이 순서를 지켜야 포맷터가 코드를 정리한 깨끗한 상태에서 린트가 진짜 문제만 정확히 잡아낼 수 있습니다.

⚠️ 주의: 반대 순서로 하면 린트가 잡은 포맷 문제를 포맷터가 다시 바꿔버리는 충돌이 생길 수 있습니다.

ruff check--fix 옵션을 넣으면 자동 수정 가능한 문제는 알아서 고쳐줍니다. 자동 수정이 불가능한 심각한 문제는 터미널에 경고로 표시되므로, 나중에 직접 확인하면 됩니다.

JavaScript 프로젝트에서는 이렇게 설정합니다.

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Write|Edit",
        "command": "npx prettier --write \"$CLAUDE_FILE_PATH\" 2>/dev/null; npx eslint --fix \"$CLAUDE_FILE_PATH\" 2>/dev/null || true"
      }
    ]
  }
}

💡 팁: 파일 확장자에 따라 포맷터를 다르게 적용하고 싶다면, command 안에서 셸 조건문을 쓸 수도 있습니다. 예를 들어 case "$CLAUDE_FILE_PATH" in *.py) 같은 패턴 매칭으로 언어별 분기가 가능합니다. 이 방법을 쓰면 하나의 Hook으로 Python, JavaScript, TypeScript 등 여러 언어를 동시에 관리할 수 있어서 설정 파일이 깔끔해집니다.

 

Claude Code Hooks로 파일 저장 시 자동 포맷팅 걸기

💬 제가 직접 써보니, 복합 Hook의 실행 시간이 길어지면 Claude Code 응답이 살짝 느려지는 느낌이 있었습니다. 포맷터와 린트 모두 --quiet 옵션을 넣어 출력을 최소화하면 체감 속도가 개선됩니다.

설정 후 검증하는 방법과 실전 팁

Hook을 등록했으면 실제로 작동하는지 반드시 확인해야 합니다. 가장 간단한 검증법은 일부러 포맷이 어긋난 파일을 Claude Code에게 수정하게 하고, 저장 직후 파일 내용을 확인하는 것입니다. 이 방법이 가장 확실한 이유는, Hook이 실제 Claude Code 도구 실행 흐름 안에서 작동하는지를 직접 눈으로 볼 수 있기 때문입니다.

검증 절차

1
들여쓰기를 일부러 틀린 테스트 파일을 만들고, Claude Code에게 "이 파일에 주석 한 줄 추가해줘"라고 요청해보십시오.
2
저장 직후 파일을 열었을 때 들여쓰기가 자동으로 정리되어 있으면 Hook이 정상 작동하는 겁니다.
3
만약 들여쓰기가 그대로라면 Hook이 실행되지 않은 것이므로, 설정 파일을 다시 점검해야 합니다.

작동하지 않을 때 체크리스트

1
settings.json의 JSON 문법을 점검하십시오.
2
command에 적은 도구(black, ruff, prettier 등)가 현재 환경에 설치되어 있는지 확인합니다. 터미널에서 black --version이나 npx prettier --version 같은 명령어로 설치 여부를 빠르게 확인할 수 있습니다.
3
가상 환경을 쓰고 있다면, Claude Code가 해당 가상 환경의 도구를 인식할 수 있는지도 함께 점검하세요.

💡 실전 팁: PreToolUse로 저장 전 검사하기

PreToolUse 이벤트에 Hook을 걸면, 파일을 수정하기 전에 검사를 먼저 돌릴 수도 있습니다.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write",
        "command": "echo '파일 저장 전 검사 시작' >> /tmp/hook_log.txt"
      }
    ]
  }
}

이렇게 로그를 남기면 Hook이 언제 실행됐는지 추적할 수 있어서 디버깅에 편리합니다. 다만 PreToolUse에서 검사가 실패해도 파일 저장 자체를 막지는 않으니, 차단 목적이라면 별도 로직이 필요합니다.

PostToolUse와 PreToolUse를 조합하면 저장 전후로 이중 검증 체계를 만들 수 있어서, 팀 프로젝트에서 코드 품질을 더 엄격하게 관리할 수 있습니다.

 

Claude Code Hooks로 파일 저장 시 자동 포맷팅 걸기
Claude Code Hooks로 파일 저장 시 자동 포맷팅 걸기

💬 제가 직접 운영해보니, Hook은 한 번 세팅하면 거의 손댈 일이 없습니다. 단, 프로젝트마다 .claude/settings.json에 따로 설정해야 하므로, 자주 쓰는 Hook은 템플릿으로 저장해두면 새 프로젝트 시작할 때 시간을 아낄 수 있습니다. GitHub 저장소에 .claude/settings.json을 함께 커밋해두면, 팀원들도 같은 Hook 설정을 자동으로 공유할 수 있어서 협업 시 코드 스타일 통일에 큰 도움이 됩니다.

✍️ 마치며

Claude Code Hooks는 파일 저장 시 포맷터와 린트를 자동으로 실행해서, 수동 작업과 실수를 한꺼번에 없애주는 기능입니다. settings.json에 몇 줄만 추가하면 설정이 끝나고, 한 번 세팅하면 프로젝트가 끝날 때까지 거의 손댈 일이 없습니다. 포맷팅 → 린트 순서의 복합 Hook으로 시작해보시고, 익숙해지면 PreToolUse까지 조합하여 이중 검증 체계를 만들어 보세요.

#ClaudeCode #Hooks #자동포맷팅 #린트자동화 #settingsjson #개발자동화 #코드품질