Recent Posts
Recent Comments
반응형
«   2025/11   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30
Archives
Today
Total
관리 메뉴

오늘도 공부

Claude Code 훅(Hook) 완벽 가이드: 개발 워크플로우를 자동화하는 11가지 방법 본문

AI/Claude code

Claude Code 훅(Hook) 완벽 가이드: 개발 워크플로우를 자동화하는 11가지 방법

행복한 수지아빠 2025. 11. 25. 10:45
반응형

Claude Code는 AI 기반 코딩 어시스턴트로, 다양한 훅(Hook) 이벤트를 통해 개발 프로세스를 세밀하게 제어할 수 있습니다. 이 글에서는 각 훅의 용도와 실제 활용 예제를 상세히 살펴보겠습니다.

훅(Hook)이란?

훅은 Claude Code의 실행 흐름에서 특정 시점에 발생하는 이벤트입니다. 각 훅에서 커스텀 로직을 실행하여 프롬프트 강화, 권한 관리, 보안 정책 적용 등을 자동화할 수 있습니다.

1. SessionStart - 세션 초기화

핵심 질문: 초기 컨텍스트나 환경 설정이 필요한가?

용도:

  • 프로젝트 컨텍스트 로드
  • 환경 변수 설정
  • 시작 스크립트 실행

실제 예제:

# .claude/hooks/session_start.py
def on_session_start():
    """세션 시작 시 프로젝트 환경 설정"""
    
    # 1. 프로젝트 README 자동 로드
    with open('README.md', 'r') as f:
        context = f.read()
    
    # 2. 코딩 스타일 가이드 주입
    style_guide = """
    이 프로젝트의 코딩 규칙:
    - Flutter Clean Architecture 패턴 사용
    - Riverpod 2.0+ 상태관리
    - 한국어 주석 필수
    - 테스트 커버리지 80% 이상 유지
    """
    
    # 3. 현재 브랜치 정보
    import subprocess
    branch = subprocess.check_output(['git', 'branch', '--show-current']).decode().strip()
    
    return {
        'project_context': context,
        'style_guide': style_guide,
        'current_branch': branch
    }

2. UserPromptSubmit - 프롬프트 전처리

핵심 질문: 사용자 프롬프트에 컨텍스트를 추가하거나 검증이 필요한가?

용도:

  • 프롬프트에 추가 정보 자동 삽입
  • 부적절한 요청 차단
  • 프롬프트 로깅

실제 예제:

# .claude/hooks/user_prompt_submit.py
def on_user_prompt_submit(prompt):
    """프롬프트 제출 전 검증 및 강화"""
    
    # 1. 금지된 키워드 체크
    forbidden_keywords = ['production_api_key', 'delete_database']
    if any(keyword in prompt.lower() for keyword in forbidden_keywords):
        return {
            'block': True,
            'reason': '위험한 작업이 감지되었습니다.'
        }
    
    # 2. 컨텍스트 자동 추가
    enhanced_prompt = f"""
    {prompt}
    
    [추가 컨텍스트]
    - 현재 작업 중인 기능: 블록체인 지갑 연동
    - 기술 스택: Flutter 3.24 + Riverpod + Web3dart
    - 테스트 필수: 모든 public 메서드에 단위 테스트 작성
    """
    
    # 3. 프롬프트 로깅
    log_prompt(prompt, enhanced_prompt)
    
    return {'enhanced_prompt': enhanced_prompt}

3. PermissionRequest - 권한 자동화

핵심 질문: 이 권한 요청을 자동으로 승인/거부해야 하나?

용도:

  • 파일 접근 권한 자동 관리
  • API 호출 승인
  • 감사 로그 작성

실제 예제:

# .claude/hooks/permission_request.py
def on_permission_request(request):
    """권한 요청 자동 처리"""
    
    # 1. 읽기 전용 파일은 자동 승인
    if request['type'] == 'file_read':
        safe_extensions = ['.dart', '.json', '.yaml', '.md']
        if any(request['path'].endswith(ext) for ext in safe_extensions):
            return {'approve': True, 'log': True}
    
    # 2. 민감한 파일 접근은 자동 거부
    sensitive_paths = ['.env', 'secrets/', 'private_keys/']
    if any(path in request['path'] for path in sensitive_paths):
        return {
            'deny': True,
            'reason': '민감한 파일 접근이 차단되었습니다.',
            'notify_user': True
        }
    
    # 3. 파일 쓰기는 백업 후 승인
    if request['type'] == 'file_write':
        backup_file(request['path'])
        return {'approve': True, 'backup_created': True}
    
    # 4. 그 외는 사용자에게 확인 요청
    return {'require_user_confirmation': True}

4. PreToolUse - 도구 실행 전 제어

핵심 질문: 도구 실행을 허용, 수정 또는 차단해야 하나?

용도:

  • 위험한 명령어 차단
  • 파라미터 자동 수정
  • 보안 정책 적용

실제 예제:

# .claude/hooks/pre_tool_use.py
def on_pre_tool_use(tool_name, parameters):
    """도구 사용 전 보안 검증"""
    
    # 1. 위험한 쉘 명령어 차단
    if tool_name == 'bash':
        dangerous_commands = ['rm -rf', 'sudo', 'chmod 777', 'dd if=']
        if any(cmd in parameters['command'] for cmd in dangerous_commands):
            return {
                'block': True,
                'reason': '위험한 명령어가 감지되었습니다.',
                'alternative': '안전한 대안을 제안합니다.'
            }
    
    # 2. API 호출 시 rate limit 체크
    if tool_name == 'api_call':
        if not check_rate_limit(parameters['endpoint']):
            return {
                'block': True,
                'reason': 'API rate limit 초과',
                'retry_after': 60
            }
    
    # 3. 파일 경로 자동 수정
    if tool_name == 'file_write':
        if not parameters['path'].startswith('safe_directory/'):
            parameters['path'] = f"safe_directory/{parameters['path']}"
            return {
                'modify': True,
                'modified_parameters': parameters,
                'reason': '안전한 디렉토리로 경로 수정'
            }
    
    return {'allow': True}

5. PostToolUse - 도구 실행 후 처리

핵심 질문: 결과를 검증하거나 후처리가 필요한가?

용도:

  • 코드 포맷팅 자동 실행
  • 린터 실행
  • 실행 결과 피드백

실제 예제:

# .claude/hooks/post_tool_use.py
def on_post_tool_use(tool_name, result):
    """도구 실행 후 자동 처리"""
    
    # 1. Dart 파일 생성 시 자동 포맷팅
    if tool_name == 'create_file' and result['path'].endswith('.dart'):
        import subprocess
        subprocess.run(['dart', 'format', result['path']])
        
        # 린트 체크
        lint_result = subprocess.run(
            ['dart', 'analyze', result['path']], 
            capture_output=True
        )
        
        if lint_result.returncode != 0:
            return {
                'warning': '린트 오류가 발견되었습니다.',
                'lint_output': lint_result.stderr.decode(),
                'suggest_fix': True
            }
    
    # 2. 테스트 파일 생성 시 자동 실행
    if tool_name == 'create_file' and '_test.dart' in result['path']:
        test_result = subprocess.run(
            ['flutter', 'test', result['path']],
            capture_output=True
        )
        
        return {
            'test_passed': test_result.returncode == 0,
            'test_output': test_result.stdout.decode()
        }
    
    # 3. Git 커밋 자동 생성
    if tool_name == 'file_write':
        subprocess.run(['git', 'add', result['path']])
        return {'git_staged': True}

6. Notification - 알림 커스터마이징

핵심 질문: 사용자에게 어떤 방식으로 알림을 보낼까?

용도:

  • 데스크톱 알림
  • 로그 기록
  • Slack/Discord 메시지 전송

실제 예제:

# .claude/hooks/notification.py
def on_notification(notification_type, message):
    """커스텀 알림 처리"""
    
    # 1. 중요 이벤트는 Slack으로 전송
    if notification_type in ['error', 'security_alert']:
        send_slack_message(
            channel='#dev-alerts',
            message=f"🚨 Claude Code Alert: {message}",
            priority='high'
        )
    
    # 2. 작업 완료 시 데스크톱 알림
    if notification_type == 'task_complete':
        from plyer import notification
        notification.notify(
            title='Claude Code',
            message=message,
            app_name='Claude Code',
            timeout=10
        )
    
    # 3. 모든 알림 로깅
    with open('.claude/logs/notifications.log', 'a') as f:
        timestamp = datetime.now().isoformat()
        f.write(f"[{timestamp}] {notification_type}: {message}\n")

7. Stop - 작업 완료 검증

핵심 질문: Claude가 작업을 완료했나, 아니면 계속해야 하나?

용도:

  • 작업 완료 검증
  • 에러 체크
  • 추가 작업 강제

실제 예제:

# .claude/hooks/stop.py
def on_stop(task_context):
    """작업 완료 검증 및 후처리"""
    
    # 1. 필수 파일 생성 체크
    required_files = ['main.dart', 'test/main_test.dart', 'README.md']
    missing_files = [f for f in required_files if not os.path.exists(f)]
    
    if missing_files:
        return {
            'continue': True,
            'reason': f'필수 파일이 누락되었습니다: {", ".join(missing_files)}',
            'additional_prompt': f'다음 파일들을 생성해주세요: {", ".join(missing_files)}'
        }
    
    # 2. 테스트 통과 확인
    test_result = subprocess.run(['flutter', 'test'], capture_output=True)
    if test_result.returncode != 0:
        return {
            'continue': True,
            'reason': '테스트가 실패했습니다.',
            'error_output': test_result.stderr.decode()
        }
    
    # 3. 코드 품질 체크
    analyze_result = subprocess.run(['dart', 'analyze'], capture_output=True)
    if 'error' in analyze_result.stdout.decode().lower():
        return {
            'continue': True,
            'reason': '코드 분석에서 오류가 발견되었습니다.'
        }
    
    # 4. 모든 검증 통과
    return {
        'complete': True,
        'summary': generate_task_summary(task_context),
        'metrics': {
            'files_created': len(task_context['created_files']),
            'test_coverage': calculate_coverage(),
            'duration': task_context['duration']
        }
    }

8. SubagentStop - 서브에이전트 검증

핵심 질문: 서브에이전트가 작업을 완료했나?

용도:

  • 병렬 작업 검증
  • 서브태스크 완료 확인
  • 의존성 체크

실제 예제:

# .claude/hooks/subagent_stop.py
def on_subagent_stop(subagent_id, task_result):
    """서브에이전트 작업 검증"""
    
    # 1. UI 컴포넌트 서브에이전트
    if subagent_id == 'ui_builder':
        if not os.path.exists('lib/presentation/screens/'):
            return {
                'continue': True,
                'reason': 'UI 화면 파일이 생성되지 않았습니다.'
            }
    
    # 2. API 연동 서브에이전트
    if subagent_id == 'api_integrator':
        # API 테스트 실행
        api_test_passed = run_api_tests()
        if not api_test_passed:
            return {
                'continue': True,
                'reason': 'API 연동 테스트 실패',
                'retry_count': task_result.get('retry_count', 0) + 1
            }
    
    # 3. 의존성 체크
    if not validate_dependencies(subagent_id, task_result):
        return {
            'continue': True,
            'reason': '다른 서브에이전트 작업이 완료되지 않았습니다.'
        }
    
    return {'complete': True}

9. PreCompact - 컨텍스트 압축 전 저장

핵심 질문: 컨텍스트 압축 전에 저장할 정보가 있나?

용도:

  • 중요 컨텍스트 보존
  • 대화 히스토리 백업
  • 상태 정보 저장

실제 예제:

# .claude/hooks/pre_compact.py
def on_pre_compact(context):
    """컨텍스트 압축 전 중요 정보 보존"""
    
    # 1. 중요 결정사항 저장
    important_decisions = extract_decisions(context['conversation'])
    save_to_file('.claude/decisions.json', important_decisions)
    
    # 2. 생성된 파일 목록 보존
    created_files = context.get('created_files', [])
    save_to_file('.claude/file_history.json', {
        'timestamp': datetime.now().isoformat(),
        'files': created_files
    })
    
    # 3. 프로젝트 상태 스냅샷
    project_state = {
        'current_task': context.get('current_task'),
        'completed_features': context.get('completed_features'),
        'pending_tasks': context.get('pending_tasks'),
        'git_commit': get_current_commit_hash()
    }
    save_to_file('.claude/state_snapshot.json', project_state)
    
    # 4. 압축 시 유지할 핵심 정보 반환
    return {
        'preserve': {
            'project_context': context.get('project_readme'),
            'coding_standards': context.get('style_guide'),
            'current_task': context.get('current_task')
        }
    }

10. SessionEnd - 세션 종료 처리

핵심 질문: 세션 종료 시 정리 작업이나 통계 저장이 필요한가?

용도:

  • 분석 리포트 생성
  • 세션 데이터 저장
  • 정리 작업 실행

실제 예제:

# .claude/hooks/session_end.py
def on_session_end(session_data):
    """세션 종료 시 정리 및 리포트 생성"""
    
    # 1. 세션 통계 생성
    statistics = {
        'duration': session_data['end_time'] - session_data['start_time'],
        'tasks_completed': len(session_data['completed_tasks']),
        'files_created': len(session_data['created_files']),
        'files_modified': len(session_data['modified_files']),
        'api_calls': session_data['api_call_count'],
        'tokens_used': session_data['token_usage']
    }
    
    # 2. 개발 리포트 생성
    report = f"""
# Claude Code 세션 리포트
생성일: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}

## 세션 통계
- 작업 시간: {statistics['duration']}
- 완료 작업: {statistics['tasks_completed']}개
- 생성 파일: {statistics['files_created']}개
- 수정 파일: {statistics['files_modified']}개

## 생성된 파일
{chr(10).join(f"- {f}" for f in session_data['created_files'])}

## 다음 작업 제안
{generate_next_tasks(session_data)}
"""
    
    with open(f".claude/reports/session_{session_data['session_id']}.md", 'w') as f:
        f.write(report)
    
    # 3. Git 커밋 자동 생성 (옵션)
    if session_data.get('auto_commit', False):
        subprocess.run(['git', 'add', '.'])
        subprocess.run([
            'git', 'commit', '-m', 
            f"Claude Code 세션: {statistics['tasks_completed']}개 작업 완료"
        ])
    
    # 4. 임시 파일 정리
    cleanup_temp_files()
    
    # 5. 백업 생성
    create_backup(session_data)
    
    return {
        'report_path': f".claude/reports/session_{session_data['session_id']}.md",
        'statistics': statistics
    }

실전 활용: 모바일앱 프로젝트 설정 예시

모바일 앱 개발에 최적화된 훅 설정:

# .claude/config.yaml
hooks:
  session_start:
    - load_project_context
    - set_flutter_environment
    - load_blockchain_config
  
  user_prompt_submit:
    - enhance_with_korean_context
    - validate_security_prompts
    - add_testing_reminder
  
  pre_tool_use:
    - check_blockchain_operations
    - validate_wallet_access
    - enforce_security_policies
  
  post_tool_use:
    - auto_format_dart_files
    - run_unit_tests
    - update_documentation
  
  session_end:
    - generate_progress_report
    - backup_code
    - suggest_next_tasks

project_context:
  name: "Flutter App"
  tech_stack:
    - Flutter 3.24
    - Riverpod 2.5+
    - Web3dart
    - Drift Database
  
  coding_standards:
    - Clean Architecture
    - 한국어 주석
    - 80% 테스트 커버리지
    - 린트 오류 0건

마무리

Claude Code의 훅 시스템을 활용하면 반복적인 작업을 자동화하고, 코드 품질을 일관되게 유지하며, 보안을 강화할 수 있습니다. 프로젝트의 특성에 맞게 훅을 설정하여 생산성을 극대화하세요.

 

반응형