Claude Code 라이프사이클 후크 입문 — 세션의 '전후'를 자동화하기
서론
Claude Code를 사용하기 시작하면, "매번 세션 시작 시에 같은 사전 작업을 하고 있다", "도구가 실행되기 전에 자동으로 체크를 넣고 싶다"라는 상황에 직면하게 된다. 그 니즈에 부응하는 것이 바로 **라이프사이클 후크 (Lifecycle Hooks)**다.
후크를 사용하면 Claude Code의 내부 이벤트(세션 시작·도구 실행 전후·컴팩트 전후 등)에 대해 쉘 커맨드(Shell Command)나 프롬프트 인젝션(Prompt Injection)을 삽입할 수 있다. CI의 후크나 Git 후크와 개념은 같지만, AI 에이전트의 워크플로우에 통합되어 있다는 점이 특징이다.
본 기사에서는 후크의 설정 방법, 이용 가능한 이벤트 종류, 실전 유스케이스를 차례대로 해설한다.
후크의 종류와 트리거 타이밍
2025년 시점에서 이용 가능한 후크 이벤트는 다음과 같다.
| 이벤트 | 트리거 타이밍 |
|---|
SessionStart | Claude Code의 세션이 시작되었을 때 |
Stop | Claude Code가 사용자에 대한 응답을 정지할 때 |
PreCompact | 컨텍스트 압축 (/compact)이 실행되기 직전 |
PostCompact | 컨텍스트 압축이 완료된 직후 |
UserPromptSubmit | 사용자가 프롬프트를 전송했을 때 |
PreToolUse | 도구 (Bash, Read, Edit 등)가 실행되기 직전 |
PostToolUse | 도구 실행이 완료된 직후 |
각 후크는 type으로서 command (쉘 커맨드 실행) 또는 prompt (프롬프트 삽입)를 선택할 수 있다.
설정 파일의 기본 구조
후크는 ~/.claude/settings.json (글로벌) 또는 프로젝트 직하의 .claude/settings.json (프로젝트 로컬)에 기술한다.
{
"hooks": {
"SessionStart": [
...
주요 항목 설명
| 키 | 필수 | 설명 |
|---|
type | ✓ | command 또는 prompt |
command | type=command 시 | 실행할 쉘 커맨드 |
prompt | type=prompt 시 | Claude에게 삽입할 프롬프트 텍스트 |
timeout | — | 타임아웃 초 단위 (기본 30초) |
matcher | — | PreToolUse/PostToolUse에서 도구 이름을 필터링 |
matcher 사용법
PreToolUse와 PostToolUse에서는 matcher를 통해 후크를 필터링할 수 있다.
matcher에 MCP 도구 이름도 지정할 수 있다.
{
"matcher": "mcp__some-mcp__some_tool"
}
matcher를 생략하면 모든 도구에 적용된다. 무거운 체크를 모든 도구에 적용하면 성능에 영향을 줄 수 있으므로 주의해야 한다.
후크의 종료 코드와 차단
command 후크의 종료 코드에는 의미가 있다.
| 종료 코드 | 동작 |
|---|
0 | 정상 계속 |
1 | 에러 로그 (계속 진행) |
2 | 차단 (도구 실행 또는 응답을 중지) |
종료 코드 2를 사용하면 "이 Bash 커맨드는 실행 금지"라는 안전장치를 만들 수 있다.
rm -rf, git push --force origin main, DROP TABLE 등을 검출하여 차단한다.
#!/bin/bash
INPUT="$CLAUDE_TOOL_INPUT"
...
settings.json에 등록:
"PreToolUse": [
{
"matcher": "Bash",
...
CLAUDE_TOOL_INPUT
환경 변수에 도구로의 입력 내용이 JSON 문자열로서 전달된다. Bash 도구의 경우 명령 문자열이 여기에 들어간다.
실전 예시 2: 세션 시작 시 컨텍스트 자동 로드 (SessionStart)
매번 수동으로 "이 프로젝트는 ~"라고 설명하는 것은 비효율적이다. SessionStart 후크를 통해 필요한 파일을 자동으로 읽어오게 한다.
SessionStart 후크의 표준 출력(stdout)은 그대로 Claude의 시스템 프롬프트(System Prompt)에 주입된다. 이를 사용하면 일일 정보, 프로젝트 상태, 규칙 등을 매번 자동으로 삽입할 수 있다.
실전 예시 3: 중지 시 자동 커밋 (Stop)
Stop 이벤트로 작업 종료 타이밍을 감지하여, 자동으로 git commit을 실행한다.
주의: Stop 후크는 응답이 완료될 때마다 실행된다. 빈도가 높을 경우 git diff --quiet 등을 사용하여 변경 사항이 없을 때는 스킵하도록 구현한다.
실전 예시 4: 사용자 입력을 게이트하기 (UserPromptSubmit)
UserPromptSubmit은 사용자가 프롬프트를 전송하는 순간에 실행된다. 후크 측에서 특정 키워드를 감지하여 처리를 삽입할 수 있다.
#!/bin/bash
PROMPT="$CLAUDE_USER_PROMPT"
...
CLAUDE_USER_PROMPT 환경 변수에 사용자의 프롬프트 텍스트가 전달된다.
실전 예시 5: prompt 타입 후크로 확인 단계 넣기
특정 도구가 호출되기 전에 Claude 스스로에게 확인 프롬프트를 삽입할 수 있다.
"PreToolUse": [
{
"matcher": "mcp__someservice__delete_resource",
...
type: prompt인 경우, command 대신 prompt 필드에 텍스트를 작성한다. Claude가 해당 텍스트를 받아 사용자에게 확인 다이얼로그(Dialog)로서 기능한다.
실전 예시 6: 압축 전에 로그 저장 (PreCompact)
/compact로 컨텍스트가 압축되기 전에 중요한 정보를 파일에 기록해 둔다.
#!/bin/bash
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
...
후크 개발 베스트 프랙티스 (Best Practices)
1. 반드시 timeout을 설정할 것
후크가 행(Hang) 상태에 빠지면 Claude Code 전체가 멈춘다. 무거운 처리는 비동기화하고, timeout으로 중단 설정을 한다.
{
"type": "command",
"command": "bash ~/.claude/hooks/my-hook.sh",
...
2. stderr와 stdout을 구분해서 사용할 것
- stdout: Claude의 컨텍스트에 주입됨 (SessionStart만 해당)
- stderr: 로그 및 에러 메시지 (사용자에게는 표시되지만 컨텍스트에는 들어가지 않음)
의도하지 않은 데이터가 컨텍스트에 섞이지 않도록, 로그는 >&2를 사용하여 stderr로 보낸다.
3. 환경 변수 목록
후크 실행 시 Claude Code로부터 전달되는 주요 환경 변수:
| 변수 | 내용 |
|---|
CLAUDE_TOOL_INPUT | 도구로의 입력 (JSON 문자열) |
CLAUDE_TOOL_NAME | 도구 이름 (PreToolUse/PostToolUse) |
CLAUDE_USER_PROMPT | 사용자 프롬프트 (UserPromptSubmit) |
CLAUDE_SESSION_ID | 세션 ID |
4. matcher는 구체적으로 좁힐 것
PreToolUse의 matcher
없이 무거운 처리를 작성하면, 모든 도구 호출 (Read, Grep, Glob, Edit 등) 시 매번 실행된다. 반드시 matcher를 사용하여 대상 도구를 좁혀야 한다.
요약
Claude Code의 라이프사이클 후크 (Lifecycle Hooks)를 능숙하게 사용하면 다음과 같은 것들을 실현할 수 있다:
- 보안 (Security): 위험한 명령어를
PreToolUse + exit 2로 차단
- 자동화 (Automation):
SessionStart로 컨텍스트 자동 로드, Stop으로 자동 커밋
- 확인 게이트 (Confirmation Gate):
type: prompt를 통해 AI가 자율적으로 확인 다이얼로그를 삽입
- 로그 축적 (Log Accumulation):
PreCompact / PostCompact로 세션 상태를 영속화
후크는 작은 쉘 스크립트 (Shell Script)로 시작할 수 있지만, 이를 쌓아 올리면 Claude Code의 동작을 대폭 커스터마이징할 수 있다. 우선 SessionStart를 통해 자주 사용하는 정보를 자동으로 로드하는 것부터 시도해 보자.
Discussion