Claude Code Agent Loop Deep Dive (2): 후크(Hooks)를 프로그래밍 가능한 개입 지점으로 활용하기
요약
본 글은 Claude Code Agent Loop의 후크(Hooks) 메커니즘을 심층 분석합니다. 후크는 에이전트 루프 내에 맞춤 로직을 삽입하는 일반적인 방법으로, 단순한 권한 승인 이상의 다양한 커스터마이징 기능을 제공합니다. 26가지 이벤트와 라이프사이클 단계를 통해 개발자가 세션 시작부터 파일 변경까지 전 과정에 개입할 수 있음을 설명합니다.
핵심 포인트
- 후크는 에이전트 루프 내 맞춤 로직 삽입의 일반 메커니즘입니다.
- 권한 승인(PermissionRequest)은 후크 기능 중 하나일 뿐입니다.
- 세션, 도구, 태스크 등 26가지 라이프사이클 이벤트가 존재합니다.
- 후크를 통해 특정 동작을 차단하거나 결과를 수정할 수 있습니다.
이전 글에서는 루프 내에서의 권한 승인에 대해 설명했습니다. 즉, LLM이 tool_use를 방출했지만 도구가 실제로 실행되기 전, 가로채기 계층(interception layer)을 통해 사용자에게 결정권을 부여하는 방식입니다.
하지만 사용자는 단순히 도구 승인을 넘어 루프에 훨씬 더 많은 맞춤 로직을 추가하고 싶어 할 수 있습니다:
- 실행되기 전에 모든 Bash 명령어를 검사합니다;
- 편집(Edit) 후마다 포매터(formatter)를 실행합니다;
- 세션 시작 시 공유 프로젝트 규칙을 불러옵니다;
- 압축(compaction) 전에 대화 내용을 스냅샷합니다;
- 다른 확인 작업을 수행할 때까지 루프가 멈추는 것을 방지합니다.
이 모든 것이 바로 **후크(Hooks)**입니다. 후크는 에이전트 루프 내에 맞춤 로직을 삽입하는 일반적인 메커니즘이며, 권한 승인은 이 일반적인 기능의 한 가지 전문화된 사용 사례일 뿐입니다.
본 글에서는 다음 질문들을 다룹니다:
- 어떤 종류의 후크 이벤트가 존재하며, 루프 내 어느 위치에 자리 잡고 있습니까?
- 후크는 어떤 입력을 받고 어떤 출력을 하나요?
- 후크가 특정 동작을 차단하거나 그 결과를 수정할 수 있나요?
- 후크가 멈추거나 실패하면 어떻게 되나요?
스물여섯 개의 후크 이벤트
Claude Code는 기본적인 이벤트 시스템이 암시하는 것보다 훨씬 더 많은 후크 위치를 가지고 있습니다. Claude Code v2.1.220에서는 이 26가지 이벤트가 라이프사이클 단계별로 자연스럽게 그룹화되어 있습니다.
세션 라이프사이클 (Session lifecycle)
SessionStart— 새로운 세션이 시작됩니다SessionEnd— 세션이 종료됩니다Setup— 초기 설정입니다ConfigChange— 구성 파일이 변경됩니다
사용자 입력 및 유도 (User input and elicitation)
UserPromptSubmit— 사용자가 제출한 프롬프트가 루프에 들어가기 전입니다Elicitation/ElicitationResult— 사용자 명확화(clarification)를 요청하고 받은 시점입니다
도구 라이프사이클 (Tool lifecycle)
PreToolUse— 모든 도구 실행 전에 발생합니다PostToolUse— 성공적인 도구 실행 후에 발생합니다PostToolUseFailure— 도구 실패 후에 발생합니다PermissionRequest— 승인이 필요할 때 발생합니다PermissionDenied— 승인 거부 후에 발생합니다
턴 완료 (Turn completion)
Stop— 루프가 모델이 도구 사용을 반환하지 않아 종료하려는 경우StopFailure— 중지 처리가 자체적으로 실패하는 경우
태스크 라이프사이클 (Task lifecycle)
TaskCreated— 태스크가 생성됨TaskCompleted— 태스크가 완료됨
컨텍스트 압축 (Context compaction)
PreCompact— 압축 전PostCompact— 압축 후InstructionsLoaded—CLAUDE.md와 같은 지침이 로드된 후
서브 에이전트 및 팀 (Subagents and teams)
SubagentStart— 서브 에이전트가 시작됨SubagentStop— 서브 에이전트가 중지됨TeammateIdle— 협업 작업에서 팀원이 유휴 상태가 됨
파일 및 워크스페이스 (Files and workspace)
FileChanged— 현재 액션 외부에서 파일이 변경됨CwdChanged— 작업 디렉토리가 변경됨WorktreeCreate/WorktreeRemove— 워크트리가 생성되거나 제거됨
기타 (Miscellaneous)
Notification— 알림이 트리거됨
모든 이벤트는 루프의 특정 지점에 매핑됩니다. 사용자는 settings.json에서 이벤트 이름 아래에 핸들러를 등록하며, Claude Code는 해당 지점에 도달할 때 자동으로 이를 호출합니다.
네 가지 실행기 유형 (Four executor types)
hooks 설정은 핸들러를 구현하는 네 가지 방법을 지원합니다.
1. command: 셸 명령어 (shell command)
이것이 가장 일반적인 형태입니다. Claude Code는 후크 지점에서 서브 프로세스를 실행합니다.
{
"hooks": {
"PostToolUse": [{
...
후크는 $CLAUDE_FILE_PATHS와 같은 환경 변수를 통해 입력을 받고, 표준 출력(stdout)과 종료 코드를 통해 결정을 전달합니다.
2. prompt: LLM 판단 (LLM judgment)
이 실행기는 모델에 프롬프트를 전송합니다:
{ "type": "prompt", "prompt": "이 변경 사항이 보안 문제를 야기하는지 평가하세요. YES 또는 NO만 답변해주세요." }
사용자가 결정론적 로직을 작성하기보다 모델에게 요청하는 것이 더 나은 경우 유용합니다.
3. agent: 서브 에이전트 태스크 (subagent task)
에이전트 후크는 전체 서브 에이전트를 시작합니다:
{ "type": "agent", "agentType": "general-purpose", "prompt": "..." }
프롬프트 후크(prompt hook)보다는 무겁지만, 서브 에이전트가 자체적으로 완전한 루프를 실행할 수 있습니다.
4. http: 웹훅 (webhook)
HTTP 후크는 이벤트를 외부 서비스로 전송합니다:
{ "type": "http", "url": "https://internal-hooks.company.com/pre-tool-use" }
이는 크로스 머신 자동화(cross-machine automation)를 지원합니다. 예를 들어, 보안팀은 모든 Claude Code 사용자에 대한 PreToolUse에 대해 평가하는 중앙 정책 서비스(central policy service)를 유지할 수 있습니다.
이러한 실행기들(executors)은 쉘 스크립트(shell script), 일회성 LLM 판단(one-shot LLM judgment), 완전한 서브 에이전트, 그리고 원격 정책 서비스라는 네 가지 복잡성 수준에 걸쳐 작동합니다.
후크를 이용해 차단 및 수정하기
후크는 단순한 관찰자(observer)가 아닙니다. 이벤트에 따라 루프 동작을 변경할 수 있습니다.
차단 (Blocking)
후크는 decision: "block"을 반환하거나 코드 2로 종료될 수 있습니다. 루프는 차단 분기(blocking branch)를 따릅니다. 예를 들어, 차단된 PreToolUse는 도구 실행을 막고 LLM에게 is_error 도구 결과를 반환합니다.
컨텍스트 수정 (Modifying context)
후크는 additional_context를 반환할 수 있습니다. Claude Code는 이를 <attachment>로 도구 결과에 추가하므로, LLM은 다음 결정에서 해당 주석(annotation)을 볼 수 있습니다. 이는 특히 도구 실행 후에 유용합니다. 후크가 결과를 검사하고 추가 경고나 설명을 첨부할 수 있기 때문입니다.
{
"continue": true,
"decision": "block",
...
continue: false는 전체 루프를 종료합니다. 차단의 정확한 의미는 이벤트에 따라 다릅니다:
| 이벤트 | 블록의 효과 |
|---|---|
PreToolUse | 도구가 실행되지 않으며, LLM은 is_error 결과를 받습니다 |
| ... |
동기식, 비동기식 및 재개 가능한 후크
후크는 기본적으로 동기적(synchronous)입니다. 루프는 후크가 반환될 때까지 기다립니다. 기본 제한 시간은 관대한 편이며, TOOL_HOOK_EXECUTION_TIMEOUT_MS = 10 min으로 설정되어 있습니다. 이는 후크에 LLM 호출이나 CI 트리거가 포함될 수 있기 때문입니다. 만약 이 시간을 초과하면, 후크는 종료되고 루프는 계속 진행됩니다.
대신 후크를 비동기적(asynchronous)으로 만들 수도 있습니다:
{ "type": "command", "command": "...", "async": true }
async: true는 fire-and-forget 방식입니다. 루프가 즉시 계속 진행됩니다.asyncRewake: true는 더 미묘합니다. 비동기 후크가 코드 2로 종료되면, LLM을 재활성화(re-wakes) 합니다.
asyncRewake를 사용하면 장시간 백그라운드 작업이 대화에 처리할 가치가 있는 무언가가 생겼음을 알릴 수 있습니다. 5분짜리 코드 분석은 사용자에게 차단되지 않고 실행될 수 있으며, 결과가 준비되면 자동으로 모델로 제어권을 반환합니다. 이는 루프를 위한 우아한 이벤트 기반 깨우기 메커니즘입니다.
후크가 실패하면 어떻게 될까요?
예상치 못한 후크 실패(0 또는 2가 아닌 종료 코드, 유효하지 않은 JSON, 또는 예외)는 루프를 충돌시키지 않습니다. Claude Code는 non_blocking_error 경로를 따릅니다:
- 오류를 기록합니다;
- 도구는 사전 도구(pre-tool) 케이스에서 계속 진행되거나, 사후 도구(post-tool) 케이스에서 기존 결과를 사용합니다;
- 사용자는 일반적으로 방해되는 오류를 보지 못합니다.
그 철학은 후크가 주 경로가 아니라 선택적 향상 기능이라는 것입니다. 고장 난 향상이 에이전트를 망가뜨려서는 안 됩니다. 예외는 `decision:
권한 승인(Permission approval)은 단 하나의 좁은 질문에 답합니다. 즉, 도구 호출이 진행될 수 있는지 여부입니다. 후크(Hooks)는 이 아이디어를 26개의 위치 전반으로 일반화합니다. Claude Code 소스 코드를 수정하지 않고도 사용자는 다음 작업을 수행할 수 있습니다:
- 세션 시작 시 조직 전체의 프로젝트 규칙 주입;
- 모든 도구 호출 전에 감사 로그 작성;
- 압축(compaction) 전에 대화 상태 백업;
- 테스트가 완료되기 전에 루프가 멈추는 것을 방지;
- 작업 디렉터리가 변경될 때 다른 규칙을 자동으로 로드.
각각은 루프 자체에 대한 맞춤형 개입입니다.
요약 (Summary)
- **26개의 후크 이벤트(hook events)**가 루프 생명주기(lifecycle)의 중요한 단계를 다룹니다.
- 네 가지 실행기(executors)—
command,prompt,agent, 그리고http—는 스크립트부터 원격 서비스까지 다양합니다. - 후크를 사용하여 **차단(block)**하고, **컨텍스트 수정(modify context)**하며, 루프 상태 전환을 강제할 수 있습니다.
- 후크는 동기(sync), 비동기(async), 그리고 비동기 재활성화(asyncRewake) 실행을 지원합니다. 후자(latter)는 백그라운드 작업이 완료된 후 LLM을 깨울 수 있습니다.
- 예상치 못한 실패는 비차단적이며, 명시적인 결정은 존중됩니다.
- 권한 승인은 특화된 후크 사용 사례입니다:
PermissionRequest이벤트가 이를 프로그래밍 가능하게 만듭니다.
다음 기사에서는 구체적인 도구 실행을 검토합니다. 여러 개의 tool_use 블록이 함께 도착할 때, 어떤 것이 병렬로 실행될 수 있는지, 어떤 것은 순차적으로 유지되어야 하는지, 그리고 도구 실패가 어떻게 모델에 보이는 결과(model-visible results)가 되는지를 다룹니다.
참고 자료 (References)
주요 구현 위치 (Claude Code v2.1.220):
src/entrypoints/sdk/coreTypes.ts— 후크 이벤트 열거형(hook-event enumeration)src/schemas/hooks.ts— 네 가지 실행기 (command,prompt,agent,http)src/utils/hooks.ts— 중앙 디스패처,executeHooks(), 및executePreToolHooks()src/services/tools/toolHooks.ts— 사전/사후 도구 후크 트리거(pre/post tool hook triggers)src/query/stopHooks.ts— 중지 후크 루프 차단(Stop-hook loop blocking)src/hooks/toolPermission/PermissionContext.ts— 승인 경쟁에서 권한 후크 참여(permission-hook participation in the approval race)
더 읽어보기: Claude Code hooks documentation.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기