에이전트 시스템

AgentTool, SendMessageTool, 다중 에이전트 스폰 — 하나의 Claude 인스턴스가 다른 인스턴스에 작업을 위임하는 방법.

01

개요

Claude Code의 에이전트 시스템은 하나의 Claude 인스턴스가 다른 인스턴스에 작업을 위임할 수 있게 합니다. 에이전트는 독립적인 대화 컨텍스트와 도구 세트를 가지며, 부모 에이전트와 메시지를 주고받으면서 복잡한 작업을 분할 정복합니다.

다루는 소스 파일: AgentTool.tsSendMessageTool.tsagentRegistry.tsforkAgent.tsworktree.ts

에이전트 시스템은 세 가지 핵심 축으로 구성됩니다:

02

에이전트 타입과 우선순위

에이전트는 세 가지 타입으로 분류되며, 동일한 이름의 에이전트가 여러 소스에서 정의될 경우 우선순위에 따라 하나만 활성화됩니다.

3가지 에이전트 타입

우선순위 체계

동일한 agentType의 에이전트가 여러 소스에서 정의되면 다음 순서로 우선순위가 적용됩니다:

// 에이전트 우선순위 (높음 → 낮음)
// 뒤의 그룹이 앞의 그룹을 덮어쓰므로 policySettings가 최고 우선순위
// 1. built-in       — 시스템 내장, 가장 낮은 우선순위
// 2. plugin         — MCP/플러그인 제공
// 3. userSettings   — ~/.claude/settings.json
// 4. projectSettings — .claude/settings.json
// 5. flag           — CLI 플래그로 전달
// 6. policySettings — MDM/엔터프라이즈 정책, 최고 우선순위
주의사항

동일한 agentType에서 두 에이전트가 동일한 이름으로 등록되면 우선순위가 높은 소스의 에이전트가 선택됩니다. policySettings에서 정의한 에이전트가 projectSettings 에이전트보다 우선합니다.

03

6개 빌트인 에이전트

Claude Code에는 여섯 개의 빌트인 에이전트가 내장되어 있으며, 각각 특화된 역할을 담당합니다.

// 빌트인 에이전트 정의 예시
const verificationAgent = {
  name: 'Verification',
  type: 'built-in',
  background: true,   // 항상 비동기 — 유일한 빌트인
  description: '구현 결과 검증 에이전트',
}
04

동기/비동기 생명주기

에이전트는 동기 또는 비동기로 실행될 수 있습니다. 비동기 실행 여부는 shouldRunAsync 함수가 6가지 조건을 평가하여 결정합니다.

shouldRunAsync 6개 조건

  1. 에이전트 정의에 background: true 하드코딩: Verification 에이전트처럼 항상 비동기
  2. 호출 시 run_in_background: true 파라미터: 명시적 비동기 요청
  3. 코디네이터 모드 활성화: 코디네이터는 워커를 비동기로 스폰
  4. 팀 컨텍스트 내 실행: 팀 메이트 간 비동기 실행
  5. 현재 에이전트 깊이 제한 초과: 중첩 깊이가 너무 깊으면 비동기 전환
  6. 사용자 설정 오버라이드: 설정에서 특정 에이전트의 비동기 여부를 강제
flowchart TD A["AgentTool 호출"] --> B{"shouldRunAsync?"} B -->|"동기"| C["인프로세스 실행"] C --> D["결과 직접 반환"] B -->|"비동기"| E["백그라운드 스폰"] E --> F["SendMessageTool로 상태 조회"] F --> G["완료 시 결과 수집"] style A fill:#c47a50,color:#1a1816 style D fill:#6e9468,color:#1a1816 style G fill:#6e9468,color:#1a1816
딥 다이브 — 인프로세스 팀메이트와 run_in_background

인프로세스 팀메이트가 run_in_background: true로 호출되면 즉시 비동기 실행으로 전환됩니다. 이는 동일 프로세스 내에서 Promise 기반 비동기 실행을 사용하며, AgentTool이 즉시 오류를 발생시키지 않고 백그라운드에서 작업을 수행합니다.

05

포크 패스와 프롬프트 캐시 공유

포크 에이전트는 부모 대화의 컨텍스트를 복제하여 독립적인 분기를 생성합니다. 이때 핵심 최적화는 바이트 동일 접두사를 통한 프롬프트 캐시 공유입니다.

바이트 동일 접두사

포크 자식은 부모와 동일한 placeholder 텍스트를 사용합니다. 이 텍스트가 동일하면 Anthropic API의 서버 측 프롬프트 캐시에서 동일한 캐시 접두사를 공유하게 됩니다. 결과적으로 부모가 이미 캐시한 수만 토큰의 시스템 프롬프트와 도구 정의를 자식이 재활용할 수 있어, API 비용과 지연 시간이 크게 절감됩니다.

// 포크 에이전트 — 바이트 동일 접두사로 캐시 공유
// 부모와 자식이 동일한 도구 목록 + 시스템 프롬프트를 사용
// → API 서버에서 동일 캐시 히트
const forkChild = {
  systemPrompt: parentSystemPrompt,  // 바이트 동일
  tools: parentTools,                // 바이트 동일
  messages: [parentPrefix, ...forkSpecificMessages],
}
딥 다이브 — 왜 placeholder가 동일해야 하는가?

Anthropic API의 프롬프트 캐시는 요청의 접두사를 기준으로 캐시 키를 생성합니다. 시스템 프롬프트, 도구 정의, 초기 메시지가 바이트 단위로 동일하면 서버는 이전 요청의 캐시된 KV 상태를 재사용합니다. 포크 에이전트가 도구 목록을 건너뛰거나 순서를 바꾸면 캐시 미스가 발생하여 수만 토큰을 재처리해야 합니다. 이를 방지하기 위해 포크 에이전트는 canUseTool로 런타임에서 도구 사용을 제한하되, 도구 목록 자체는 부모와 동일하게 유지합니다.

06

워크트리 격리

에이전트가 파일시스템 변경을 수반하는 작업을 수행할 때, git worktree를 사용하여 메인 작업 디렉토리와 격리된 환경에서 작업합니다.

워크트리 스마트 정리

에이전트가 완료되면 워크트리의 상태에 따라 정리 전략이 달라집니다:

// 워크트리 정리 로직
async function cleanupWorktree(worktreePath: string) {
  const hasChanges = await hasTrackedChanges(worktreePath)
  if (!hasChanges) {
    await removeWorktree(worktreePath)  // 워크트리 + 브랜치 삭제
  }
  // 변경 있으면 보존 — 부모/사용자가 검사
}
07

SendMessageTool과 에이전트 프론트매터

SendMessageTool은 실행 중인 에이전트에 메시지를 보내는 도구입니다. 비동기 에이전트의 상태를 조회하거나, 추가 지시를 전달하거나, 결과를 수집하는 데 사용됩니다.

에이전트 프론트매터 필드

에이전트 정의 파일에는 다음과 같은 프론트매터 필드가 포함됩니다:

08

핵심 요약

핵심 포인트

  • 에이전트는 built-in, plugin, user/project 세 가지 타입으로 분류되며, 뒤의 그룹이 앞의 그룹을 덮어쓰므로 policySettings > flag > projectSettings > userSettings > plugin > built-in 순으로 우선순위가 적용됩니다
  • 6개 빌트인 에이전트(General Purpose, Explore, Plan, Verification, Fork, StatuslineSetup) 중 Verification만 background: true가 하드코딩되어 항상 비동기로 실행됩니다
  • shouldRunAsync는 6가지 조건(background 하드코딩, run_in_background 파라미터, 코디네이터 모드, 팀 컨텍스트, 깊이 제한, 설정 오버라이드)을 평가합니다
  • 포크 에이전트는 부모와 바이트 동일한 도구 목록을 유지하여 API 프롬프트 캐시를 공유하고, canUseTool로 런타임에서 도구 접근을 제한합니다
  • 워크트리 스마트 정리는 git 추적 변경이 없으면 워크트리와 브랜치를 즉시 삭제하고, 변경이 있으면 검사를 위해 보존합니다
  • SendMessageTool은 비동기 에이전트와의 통신 채널로, 상태 조회, 지시 전달, 결과 수집에 사용됩니다
09

지식 확인

퀴즈 — 5문제

Q1. 동일한 agentType에서 두 에이전트가 충돌할 때 최고 우선순위를 갖는 소스는?

  • A) built-in
  • B) plugin
  • C) projectSettings
  • D) policySettings
뒤의 그룹이 앞의 그룹을 덮어쓰므로 policySettings가 가장 높은 우선순위를 갖습니다. 정답은 D) policySettings입니다.

Q2. 포크 자식이 부모와 동일한 placeholder 텍스트를 사용하는 목적은?

  • A) 도구 실행을 건너뛰기 위해
  • B) 바이트 동일 API 요청 접두사로 프롬프트 캐시를 공유하기 위해
  • C) 사용자에게 상태 메시지를 표시하기 위해
  • D) 하위 에이전트 생성을 방지하기 위해
포크 자식은 부모와 바이트 단위로 동일한 접두사를 유지하여 Anthropic API 서버의 프롬프트 캐시를 공유합니다. 도구 목록과 시스템 프롬프트가 동일하면 서버는 이전 요청의 캐시된 KV 상태를 재사용하여 수만 토큰의 재처리를 방지합니다.

Q3. 인프로세스 팀메이트가 run_in_background: true로 호출되면 어떻게 되나요?

  • A) 비동기로 실행됨
  • B) AgentTool이 즉시 오류를 발생시킴
  • C) 동기 실행으로 폴백됨
  • D) 큐에 대기됨
run_in_background: trueshouldRunAsync의 6가지 조건 중 하나로, 인프로세스 팀메이트라도 이 플래그가 설정되면 Promise 기반 비동기 실행으로 전환됩니다.

Q4. 에이전트가 git 추적 변경 없이 워크트리 작업을 완료하면 어떻게 정리되나요?

  • A) main 브랜치에 자동 병합
  • B) 워크트리와 브랜치를 즉시 삭제
  • C) 부모 검사를 위해 보존
  • D) 변경 사항을 stash에 저장
워크트리 스마트 정리는 git 추적 변경이 없으면 보존할 이유가 없으므로 워크트리와 연결된 브랜치를 즉시 삭제합니다. 변경이 있는 경우에만 검사를 위해 보존합니다.

Q5. background: true가 하드코딩된 유일한 빌트인 에이전트는?

  • A) Explore
  • B) Plan
  • C) Verification
  • D) General Purpose
Verification 에이전트만 background: true가 하드코딩되어 있어 항상 비동기로 실행됩니다. 다른 빌트인 에이전트는 호출 시 조건에 따라 동기/비동기가 결정됩니다.
0 / 5