Claude Code의 hooks를 이용한 자동 체크 기능 구현
요약
본 기사는 Claude Code의 'hooks' 메커니즘을 활용하여 에이전트 동작에 결정론적인 자동 검사 기능을 구현하는 방법을 다룹니다. hooks는 AI의 판단과 무관하게 특정 이벤트(예: 도구 사용 전후) 발생 시 지정된 명령을 강제 실행할 수 있게 합니다. 이를 통해 파일 포맷팅이나 위험 명령어 차단 같은 안정적인 워크플로우를 구축할 수 있습니다.
핵심 포인트
- hooks는 AI 판단이 아닌, 결정론적 이벤트 기반으로 동작합니다.
- PostToolUse로 편집 후 자동 포맷팅을 구현할 수 있습니다.
- PreToolUse를 이용해 위험한 도구 사용을 사전에 차단 가능합니다.
- 후크 설정은 `.claude/settings.json`에 작성하며 스코프가 중요합니다.
Claude Code의 hooks를 이용한 자동 검사 구현
개요
Claude Code에는 에이전트 동작의 주요 지점에서 사용자가 정의한 명령을 실행할 수 있는 hooks라는 메커니즘이 있습니다. "파일을 편집하면 자동으로 포맷팅하기", "위험한 명령을 실행하기 전에 차단하기"와 같은 처리를 프롬프트 요청이 아닌, **결정론적인 후크(deterministic hook)**로 삽입할 수 있습니다.
프롬프트에서 "편집 후에는 반드시 prettier를 적용해 줘"라고 부탁하더라도 지켜지거나 안 될 때가 있습니다. hooks는 AI의 판단에 의존하지 않고, 지정된 이벤트 발생 시 반드시 명령이 실행된다는 것이 본질적인 차이점입니다.
본 기사에서는 다음 내용을 실습(hands-on)으로 구현합니다.
PostToolUse를 이용한 편집 후 자동 포맷팅PreToolUse를 이용한 위험 명령어 차단Stop을 이용한 작업 완료 시 테스트 실행
환경 설정
- Claude Code (CLI)
- macOS / Linux (Windows는 WSL 권장)
jq(후크에 전달되는 JSON을 처리하기 위함. 예:brew install jq)
hooks의 설정은 .claude/settings.json에 작성합니다. 배치 위치에 따라 스코프가 달라집니다.
| 파일 | 스코프 |
|---|---|
~/.claude/settings.json | 사용자 전체 |
<repo>/.claude/settings.json | 프로젝트 (팀 공유 및 커밋 대상) |
<repo>/.claude/settings.local.json | 프로젝트 (개인용, gitignore 대상) |
hooks의 기본 구조
hooks는 "이벤트"별로 matcher(대상 도구 이름에 대한 정규 표현식)와 실행 명령 조합을 등록합니다.
{
"hooks": {
"PostToolUse": [
...
주요 이벤트 (공개 사양으로 제공되는 것):
| 이벤트 | 발화 타이밍 |
|---|---|
PreToolUse | 도구 실행 직전 (차단 가능) |
PostToolUse | 도구 실행 직후 |
UserPromptSubmit | 사용자가 프롬프트를 전송했을 때 |
Stop | 에이전트가 응답을 마칠 때 |
SubagentStop | 서브 에이전트가 끝날 때 |
SessionStart | 세션 시작 시 |
matcher는 Bash / Edit / Write / Read 등의 도구 이름에 매치됩니다. Edit|Write처럼 정규 표현식으로 여러 개 지정할 수 있습니다.
후크로 전달되는 입력 값
후크 명령에는 표준 입력(stdin)을 통해 JSON이 전달됩니다. 내용은 이벤트에 따라 다르지만, PreToolUse / PostToolUse에서는 대략 다음 형태를 가집니다.
{
"session_id": "xxxx",
"transcript_path": "/path/to/transcript.jsonl",
...
jq를 사용하여 필요한 필드를 추출하고 처리합니다.
실습 1: 편집 후 자동 포맷팅 (PostToolUse)
Edit / Write가 실행되면, 해당 대상 파일에 포맷팅을 적용합니다. 편집 대상의 경로는 tool_input.file_path에 들어 있습니다.
{
"hooks": {
"PostToolUse": [
...
명령어가 길어지면 스크립트로 분리하는 것이 가독성이 좋습니다. .claude/hooks/format.sh 파일을 준비합니다.
#!/usr/bin/env bash
set -euo pipefail
file_path=$(jq -r '.tool_input.file_path // empty')
...
{
"hooks": {
"PostToolUse": [
...
이렇게 하면 AI가 편집할 때마다 포맷팅이 실행되어, 차이가 포매터 규격에 맞게 정렬됩니다.
실습 2: 위험 명령어 차단 (PreToolUse)
PreToolUse는 실행 전에 발화하며, **종료 코드(exit code)**를 통해 도구 실행을 중지시킬 수 있습니다.
- 종료 코드
0: 허용(그대로 실행) - 종료 코드
2: 블록. stderr의 내용이 Claude에게 피드백됨 - 그 외: 비블록 에러 처리
.claude/hooks/guard.sh
:
#!/usr/bin/env bash
set -euo pipefail
command=$(jq -r '.tool_input.command // empty')
...
{
"hooks": {
"PreToolUse": [
...
블록 시에 stderr로 작성된 메시지는 Claude에게 반환되므로, 에이전트는 '왜 멈췄는지'를 이해하고 다른 수단을 취하려고 합니다. 단순한 거부가 아니라 이유가 있는 가드레일이 되는 것이 핵심입니다.
더 세밀하게 제어하고 싶다면, 종료 코드 대신 stdout에 JSON을 출력하는 방법도 있습니다.
echo '{"decision": "block", "reason": "운영 환경용 파괴적 명령어는 수동 확인이 필요합니다"}'
exit 0
핸즈온 3: 완료 시 테스트 실행 (Stop)
에이전트가 응답을 마치는 Stop
이벤트에서 가벼운 체크를 수행합니다.
{
"hooks": {
"Stop": [
...
Stop은 툴에 연결되지 않기 때문에 matcher는 필요하지 않습니다. 여기서 테스트나 타입 체크를 실행하여 실패를 조기에 시각화할 수 있습니다. 무거운 처리를 매번 돌리면 경험이 나빠지므로, lint나 tsc --noEmit 등 가벼운 것부터 시작하는 것이 좋습니다.
확인 방법
-
.claude/settings.json에 hooks를 작성합니다. - Claude Code를 재시작합니다 (설정 재로드용). -
동작 확인:
-
PostToolUse: 임의 파일을 수정하게 하고, 포맷팅이 실행되는지 차이점(diff)으로 확인.
-
PreToolUse:
rm -rf
포함하는 명령어를 실행시켜 블록되는지 확인. -
Stop: 응답 종료 후 lint가 실행되는지 로그로 확인.
-
프록시(hook) 자체는 샘플 JSON을 넣어 직접 테스트할 수 있습니다.
echo '{"tool_input":{"command":"rm -rf /"}}' | bash .claude/hooks/guard.sh
echo "exit=$?" # => exit=2가 나오면 성공
주의점
- hooks는 당신의 권한으로 쉘을 실행합니다. 신뢰할 수 없는 리포지토리의
.claude/settings.json을 그대로 사용하지 마세요. 내용을 반드시 검토해야 합니다. - 명령어가 멈추면 세션이 대기됩니다. 타임아웃이나|| true로 빨리 반환하는 설계를 해야 합니다. -PostToolUse의 포매터가 파일을 추가로 수정할 수 있다는 점에 주의하세요. 무한 루프가 발생하지 않도록, hooks 내부에서 에이전트의 툴을 호출하지 마세요. - 경로는 리포지토리 루트 기준으로 작성해야 합니다. 상대 경로의 기준점을 착각하기 쉽습니다. - 팀에서 공유할 경우.claude/settings.json은 커밋하고, 개인 설정은.claude/settings.local.json으로 분리하세요. - 사양(이벤트명・입력 JSON 필드)은 버전에 따라 변경될 수 있으므로, 도입 시 공식 문서를 통해 최신 정보를 확인해야 합니다.
요약
- hooks는 AI의 '요청 기반' 약속을 결정론적인 자동 처리로 바꾸는 메커니즘입니다. -
PostToolUse에서 포맷팅,PreToolUse에서 가드레일,Stop에서 완료 시 체크가 실용적인 3종 세트입니다. - 입력은 stdin의 JSON, 제어는 종료 코드(2로 블록) 또는 stdout의 JSON을 사용합니다. - 본질은 쉘 실행이므로, 보안 검토와 경량화를 잊지 마세요.
'프롬프트로 부탁하기'에서 'hook으로 보장하기'로. 지켜줬으면 하는 규칙일수록, hooks에 구현할 가치가 있습니다.
Discussion

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