Claude Code로 코드 짜다 보면 이런 상황이 생겨요.
Claude: 구현 완료했습니다!
나: (확인해보니) lint 에러 10개, 테스트 2개 실패, .env 파일 커밋됨
Hooks는 Claude가 특정 동작을 하기 전/후에 자동으로 스크립트를 실행해요. 이 문제를 구조적으로 막아요.
Hooks가 뭔가
Claude 동작 흐름:
파일 수정 전 → PreToolUse Hook 실행
→ (실패하면 Claude 동작 중단)
파일 수정
파일 수정 후 → PostToolUse Hook 실행
세션 종료 전 → Stop Hook 실행
즉, Claude가 코드를 짜는 중간중간에 자동 검증이 들어가요. 문제 있으면 Claude가 스스로 고쳐요.
설정 방법
.claude/hooks/ 폴더에 JSON 파일로 설정해요.
.claude/
└── hooks/
└── default.json
기본 구조:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "실행할 명령어"
}
]
}
]
}
}
matcher는 어떤 Claude 툴 사용 시 실행할지 지정해요.
주요 matcher:
Write → 파일 새로 생성할 때
Edit → 파일 수정할 때
MultiEdit → 여러 파일 동시 수정할 때
Bash → bash 명령 실행할 때
Read → 파일 읽을 때
실전 설정 1 — TypeScript 프로젝트
.claude/hooks/default.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "cd $PROJECT_ROOT && pnpm typecheck 2>&1 | head -20"
},
{
"type": "command",
"command": "cd $PROJECT_ROOT && pnpm lint --fix 2>&1 | tail -10"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "echo '실행 명령: '$TOOL_INPUT | grep -E 'rm -rf|curl.*|.env' && echo 'BLOCKED' && exit 1 || exit 0"
}
]
}
]
}
}
실제 동작:
Claude: payment.ts 파일 수정 완료
→ Hook 자동 실행: pnpm typecheck
→ 에러 발견: "Property 'amount' does not exist on type 'Payment'"
→ Hook 자동 실행: pnpm lint --fix
→ 5개 자동 수정됨
→ Claude가 결과 보고 스스로 타입 에러 수정
→ 다시 typecheck 통과 확인
→ 완료 보고
Claude한테 말 안 해도 타입 에러랑 lint 에러는 스스로 잡아요.
실전 설정 2 — 보안 자동 스캔
.claude/hooks/security.sh:
#!/bin/bash
# 위험한 패턴 감지
MODIFIED_FILE="$1"
# .env 파일 실수로 커밋하려는지 체크
if echo "$MODIFIED_FILE" | grep -qE "\.env$|\.env\.local"; then
echo "🚨 경고: .env 파일은 커밋하면 안 됩니다!"
exit 1
fi
# 하드코딩된 시크릿 감지
if grep -qE "(api_key|password|secret|token)\s*=\s*['\"][^'\"]{8,}" "$MODIFIED_FILE" 2>/dev/null; then
echo "🚨 경고: 하드코딩된 시크릿 감지됨! 환경변수로 이동하세요."
grep -nE "(api_key|password|secret|token)\s*=\s*['\"][^'\"]{8,}" "$MODIFIED_FILE"
exit 1
fi
echo "✅ 보안 체크 통과"
exit 0
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/security.sh $TOOL_OUTPUT_PATH"
}
]
}
]
}
}
실제 동작:
Claude: config.ts 파일 생성
→ 보안 Hook 실행
→ "api_key = 'sk-1234abcd...'" 감지
→ 🚨 경고 출력, exit 1
→ Claude가 경고 보고 자동으로 수정:
→ process.env.API_KEY 로 변경
→ 다시 보안 체크 통과
→ 완료
시크릿 하드코딩을 Claude가 스스로 잡아서 고쳐요.
실전 설정 3 — 테스트 자동 실행
파일 수정 후 관련 테스트만 자동으로 돌려요.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/run-related-tests.sh $TOOL_OUTPUT_PATH"
}
]
}
]
}
}
.claude/hooks/run-related-tests.sh:
#!/bin/bash
MODIFIED_FILE="$1"
# 테스트 파일 자체면 그냥 실행
if echo "$MODIFIED_FILE" | grep -q "\.test\."; then
pnpm test "$MODIFIED_FILE"
exit $?
fi
# 소스 파일이면 대응하는 테스트 파일 찾아서 실행
TEST_FILE="${MODIFIED_FILE/src\//tests/}"
TEST_FILE="${TEST_FILE/.ts/.test.ts}"
if [ -f "$TEST_FILE" ]; then
echo "🧪 관련 테스트 실행: $TEST_FILE"
pnpm test "$TEST_FILE"
exit $?
else
echo "⚠️ 테스트 파일 없음: $TEST_FILE"
echo "테스트를 작성해주세요."
exit 0
fi
실제 동작:
Claude: src/services/payment.service.ts 수정
→ Hook: tests/services/payment.service.test.ts 자동 실행
→ 테스트 결과:
✓ 정상 결제 처리 (23ms)
✗ 잔액 부족 시 에러 반환 → FAILED
Expected: AppError(400)
Received: undefined
→ Claude가 실패 본 후 자동으로 수정
→ 테스트 재실행 → 전체 통과
→ 완료 보고
실전 설정 4 — PR 전 최종 검사
세션 종료 전 자동으로 전체 체크해요.
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/pre-commit-check.sh"
}
]
}
]
}
}
.claude/hooks/pre-commit-check.sh:
#!/bin/bash
echo "🔍 세션 종료 전 최종 체크..."
FAILED=0
# 1. 타입 체크
echo "1/4 타입 체크..."
if ! pnpm typecheck; then
echo "❌ 타입 에러 있음"
FAILED=1
fi
# 2. lint
echo "2/4 Lint 체크..."
if ! pnpm lint; then
echo "❌ Lint 에러 있음"
FAILED=1
fi
# 3. 테스트
echo "3/4 테스트 실행..."
if ! pnpm test; then
echo "❌ 테스트 실패"
FAILED=1
fi
# 4. .env 파일 staged 여부
echo "4/4 민감 파일 체크..."
if git diff --cached --name-only | grep -qE "\.env"; then
echo "❌ .env 파일이 staged됨! git reset HEAD .env 실행 필요"
FAILED=1
fi
if [ $FAILED -eq 0 ]; then
echo "✅ 모든 체크 통과! PR 올려도 됩니다."
else
echo "⚠️ 수정 필요한 항목이 있습니다."
fi
실제 동작:
나: /exit (세션 종료)
→ Stop Hook 자동 실행:
1/4 타입 체크... ✅ 통과
2/4 Lint 체크... ✅ 통과
3/4 테스트 실행... ❌ 2개 실패
4/4 민감 파일 체크... ✅ 통과
⚠️ 수정 필요한 항목이 있습니다.
→ Claude: 테스트 실패 자동 수정 후 재실행
→ 전체 통과 후 세션 종료
전체 hooks 파일 합본
.claude/hooks/default.json 실제 프로덕션 설정:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit|MultiEdit",
"hooks": [
{
"type": "command",
"command": "cd $PROJECT_ROOT && pnpm typecheck 2>&1 | head -20"
},
{
"type": "command",
"command": "bash .claude/hooks/security.sh $TOOL_OUTPUT_PATH"
},
{
"type": "command",
"command": "bash .claude/hooks/run-related-tests.sh $TOOL_OUTPUT_PATH"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/check-dangerous-command.sh"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "bash .claude/hooks/pre-commit-check.sh"
}
]
}
]
}
}
Hooks 전후 비교
Hooks 없이:
Claude: 기능 구현 완료!
나: PR 올리려고 보니까...
- 타입 에러 5개
- lint 에러 8개
- 테스트 3개 실패
- API 키 하드코딩 1개
나: (다시 Claude한테 설명하고 수정 요청 → 30분 낭비)
Hooks 있을 때:
Claude: 파일 수정
→ 타입 에러 감지 → 자동 수정
→ 보안 이슈 감지 → 자동 수정
→ 테스트 실패 감지 → 자동 수정
Claude: 기능 구현 완료! (모든 체크 통과)
나: PR 바로 올림
📌 관련 글
CLAUDE.md 잘 쓰는 법
CLAUDE.md 잘 쓰는 법 — 세션마다 시니어 개발자를 고용하는 효과
Claude Code를 처음 쓰면 이런 일이 반복돼요.세션 1: "우리 프로젝트는 TypeScript 씁니다"세션 2: 또 "TypeScript 써요"세션 3: 또또 "TypeScript요..."Claude Code는 매 세션마다 기억을 초기화하고 시작해요.아무
cell-devlog.tistory.com
Claude Code 4레이어 컨텍스트 시스템
매번 설명 반복하다 지쳤다면 — Claude Code 4레이어 컨텍스트 시스템
Claude Code를 처음 쓰면 이런 상황이 반복돼요.세션 1: "우리 프로젝트는 TypeScript 쓰고, Fastify야, 테스트는 Vitest야"세션 2: 또 설명세션 3: 또 설명매번 새 Claude한테 온보딩을 반복하는 거예요. 이게
cell-devlog.tistory.com
'AI Development' 카테고리의 다른 글
| Claude Code 토큰 낭비 없애는 법 — 컨텍스트 관리 완전 가이드 (0) | 2026.04.14 |
|---|---|
| Git Worktrees + Claude Code — 혼자서 팀처럼 병렬 개발하는 법 (0) | 2026.04.13 |
| 매번 설명 반복하다 지쳤다면 — Claude Code 4레이어 컨텍스트 시스템 (1) | 2026.04.13 |
| AI 에이전트에 Shell Access 주면 안 되는 이유 — 실제 해킹 사례와 방어법 (0) | 2026.04.13 |
| Claude Advisor Strategy 실전 가이드 — Opus 성능을 Sonnet 비용으로 (0) | 2026.04.13 |