Skip to main content

라이프사이클 훅 (Hooks)

Claude Code 이벤트에 자동 실행되는 셸 스크립트 시스템입니다. (.ai-core v2.1.0 기준)

6개 Hook 종류

Hook트리거실행 방식주요 기능
UserPromptSubmit사용자 메시지 제출동기환경 검증, 컨텍스트 주입, 미확인 리포트 체크
PreToolUse도구(Write/Edit) 실행 전동기위험 파일 경고, 자동 백업
PostToolUse도구(Write/Edit) 실행 후동기보안 검사, 테스트 체크, 문서 정합성
PreCompact컨텍스트 압축 전동기진행 중 work 파일/특허 문서 감지, 상태 저장
PostCompact컨텍스트 압축 후동기저장된 상태 복원 안내, Claude에게 재주입
Stop세션 종료동기+백그라운드세션 요약, Git 기록, handoff 자동 저장

bootstrap.sh 흐름

모든 hooks의 진입점입니다. settings.json에서 절대 경로로 호출됩니다.

Claude Code 이벤트 발생

settings.json → hook 정의

bash $HOME/.../bootstrap.sh {hook-name}

bootstrap.sh → PROJECT_ROOT 결정 → exec hooks/{hook-name}.sh

개별 hook 실행

settings.json 등록 예시

{
"hooks": {
"UserPromptSubmit": [{
"command": "bash $HOME/.../bootstrap.sh user-prompt-submit"
}],
"Stop": [{
"command": "bash $HOME/.../bootstrap.sh stop"
}]
}
}

PROJECT_ROOT 결정 순서

1. SCRIPT_DIR (bootstrap.sh 위치) → 2단계 상위 디렉토리
2. config/detail.json → paths.project_root (있으면 사용)
3. fallback: 추론값 사용

개별 Hook 경로 변수

각 hook 파일 상단에서 공통적으로 설정합니다.

SCRIPT_DIR="$(dirname "$0")"                    # .claude/hooks/
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" # multi-saas-kit/
AI_CORE_DIR="$PROJECT_ROOT/.ai-core" # .ai-core/
DATA_AI_DIR="$PROJECT_ROOT/.ai-core/data" # .ai-core/data/
CONFIG_DIR="$AI_CORE_DIR/config" # .ai-core/config/

stop.sh 포그라운드/백그라운드 구조

stop.sh는 다른 hooks와 달리 2단계로 실행됩니다. 포그라운드에서 필수 작업을 마친 뒤, 시간이 오래 걸리는 작업은 백그라운드(disown)로 넘깁니다.

[포그라운드] (Claude Code가 대기)
├── /-skip-all 감지 → 즉시 종료
├── stdin에서 JSON 입력 읽기 (transcript_path, session_id)
├── Git 요약 출력
├── AI Memory 제안
├── Handoff 자동 저장 (auto_save_handoff)
└── 백그라운드 태스크 시작

[백그라운드] (disown, Claude Code 대기 없음)
├── Transcript 추출
├── 프로젝트 로그 동기화
├── 세션 요약 생성 (LLM 폴백 체인)
├── RAG 임베딩
├── 컨텍스트 아카이브
└── 체크리스트 검증
함수 스코핑 주의

run_heavy_tasks_background() 호출은 모든 함수 정의가 완료된 후에 실행됩니다. 함수를 정의하기 전에 백그라운드로 넘기면 함수를 찾지 못하는 스코핑 문제가 발생합니다. (v2.0.0에서 수정됨)

PostToolUse lib 모듈 구조

post-tool-use.sh는 진입점(약 100줄)이며, 실제 기능은 lib/ 폴더의 모듈로 분리되어 있습니다.

post-tool-use.sh (진입점)
├── source lib/config-loader.sh ← 설정 읽기
├── source lib/session-manager.sh ← 세션 ID 감지, 폴더 생성
├── source lib/security-scanner.sh ← SQL Injection, XSS, 시크릿, 디버그 코드
├── source lib/extended-checks.sh ← 포트 검증, 문서 계층 검사
├── source lib/semgrep-auto.sh ← Semgrep 자동 실행 (백그라운드)
├── source lib/test-check.sh ← 테스트 파일 존재 확인
├── source lib/doc-consistency.sh ← 문서 정합성 (특허 용어/참조)
├── source lib/deep-security.sh ← 심층 보안 (Critical 시 서브에이전트 안내)
├── source lib/transcript-sync.sh ← Transcript 동기화, RAG, 체크리스트
└── source lib/check-reporter.sh ← 결과 리포트 + 실행 상태 배너

검사 모듈 on/off 제어

global.jsonpost_tool_use_checks 섹션에서 각 모듈을 제어합니다.

모듈config 키대상기본값
Semgrep 자동 실행semgrep_auto코드 파일 (.php, .js 등)OFF
테스트 존재 확인test_check코드 파일 (.php, .py, .go)OFF
문서 정합성doc_consistencymd 파일 (특허 문서 특화)OFF
심층 보안 분석deep_securityCritical 이슈 발견 시OFF

실행 상태 배너

매 Write/Edit 후 검사 현황을 테이블로 표시합니다.

┌──────────────────────────────────────────────┐
│ PostToolUse 검사 현황 │
│ semgrep │ SKIP │ config: disabled │
│ test-check │ PASS │ │
│ doc-check │ SKIP │ 비대상 파일 │
│ deep-sec │ SKIP │ config: disabled │
└──────────────────┴───────┴────────────────────┘

set +e 규칙

모든 hooks는 set +e로 실행합니다. 내부 명령 실패가 hook 전체를 중단하지 않습니다.

# 올바른 패턴
set +e

# 사용 금지 (단일 명령 실패로 전체 hook 중단)
set -e
왜 set -e를 쓰면 안 되는가

Claude Code는 hook exit code로 성공/실패를 판단합니다.

  • exit 0: 성공 (stdout 출력이 Claude 컨텍스트에 주입)
  • exit != 0: 실패 ("Failed with non-blocking status code" 표시)

set -e를 사용하면 jq 파싱 실패 같은 사소한 오류가 전체 hook을 중단시켜, 보안 검사나 컨텍스트 주입이 누락됩니다.

stdout vs stderr

출력대상
stdoutClaude 컨텍스트에 주입됨 (Claude가 읽음)
stderr터미널에만 표시 (디버그용)

파일 구조

.claude/hooks/
├── bootstrap.sh ← 모든 hooks 진입점
├── user-prompt-submit.sh ← UserPromptSubmit
├── pre-tool-use.sh ← PreToolUse
├── post-tool-use.sh ← PostToolUse (진입점 → lib/ 로드)
├── pre-compact.sh ← PreCompact
├── post-compact.sh ← PostCompact
├── stop.sh ← Stop (포그라운드+백그라운드)
├── lib/ ← PostToolUse 모듈
│ ├── config-loader.sh
│ ├── session-manager.sh
│ ├── security-scanner.sh
│ ├── extended-checks.sh
│ ├── semgrep-auto.sh
│ ├── test-check.sh
│ ├── doc-consistency.sh
│ ├── deep-security.sh
│ ├── transcript-sync.sh
│ └── check-reporter.sh
└── prompt-context/ ← UserPromptSubmit 주입 컨텍스트
├── 001-environment.md
├── 002-project-context.md
├── 003-checklist-status.md
└── 004-multi-llm-opinions.md

관련 문서