Add complete Korean-language technical documentation analyzing Claude Code CLI internals, organized in a leveled guide structure (Level 1-3 + Appendix). Level 1 (입문): architecture overview, request lifecycle, key concepts Level 2 (시스템): QueryEngine, Tool system, Command system, Permission system, Agent coordinator, UI/Ink components Level 3 (심화): MCP/LSP integration, IDE bridge, Plugin/Skill system, Context compression, OAuth/Auth, Telemetry Appendix: Korean-English glossary, file map, design patterns Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
27 KiB
에이전트 오케스트레이션: 멀티에이전트 시스템 분석
1. 개요
Claude Code의 멀티에이전트(multi-agent) 오케스트레이션(orchestration) 시스템은 단일 세션 안에서 여러 서브에이전트(subagent)를 동시에 생성하고 조율하는 기반 구조다. 이 시스템은 복잡한 작업을 독립적인 단위로 분해하고 병렬 실행하여 성능과 컨텍스트 격리(context isolation)를 동시에 달성한다.
핵심 구성 요소와 파일 위치:
| 구성 요소 | 경로 |
|---|---|
| Coordinator Mode (코디네이터 모드) | src/coordinator/coordinatorMode.ts |
| AgentTool (에이전트 생성 도구) | src/tools/AgentTool/ |
| TeamCreateTool / TeamDeleteTool | src/tools/TeamCreateTool/, src/tools/TeamDeleteTool/ |
| SendMessageTool (에이전트 간 통신) | src/tools/SendMessageTool/ |
| Task 시스템 | src/tasks/ |
이 문서는 각 구성 요소의 구현 세부 사항과 상호작용 방식을 분석한다.
2. 아키텍처 다이어그램
전체 시스템의 데이터 흐름은 다음과 같다.
graph TD
User["사용자"] --> MainAgent["메인 에이전트\n(Coordinator Mode)"]
MainAgent -->|"AgentTool(subagent_type, prompt)"| Spawn["에이전트 생성 경로"]
Spawn -->|"일반 서브에이전트"| LocalAgentTask["LocalAgentTask\n(로컬 비동기 실행)"]
Spawn -->|"isolation: worktree"| Worktree["Git Worktree\n(격리된 작업 복사본)"]
Spawn -->|"isolation: remote (ant-only)"| RemoteAgentTask["RemoteAgentTask\n(원격 CCR 실행)"]
LocalAgentTask --> SubAgent["서브에이전트\n(독립 QueryEngine + 컨텍스트)"]
Worktree --> SubAgent
SubAgent -->|"task-notification XML"| MainAgent
MainAgent -->|"TeamCreateTool(team_name)"| TeamContext["팀 컨텍스트\n(TeamFile)"]
TeamContext -->|"AgentTool(subagent_type, team_name)"| Teammate["팀메이트(Teammate)\n(tmux/in-process)"]
Teammate -->|"SendMessageTool(to, message)"| Mailbox["메일박스(Mailbox)\n파일시스템 기반"]
Mailbox -->|"수신"| Teammate
Mailbox -->|"수신"| MainAgent
MainAgent -->|"SendMessageTool(to: agentId)"| SubAgent
MainAgent -->|"TeamDeleteTool()"| Cleanup["팀 정리\n(디렉터리, 컬러, 태스크)"]
SubAgent -.->|"ProgressTracker 업데이트"| TaskProgress["태스크 진행 상황\n(토큰 수, 도구 호출 수)"]
TaskProgress -.-> MainAgent
style MainAgent fill:#2d6a9f,color:#fff
style SubAgent fill:#3a7d44,color:#fff
style LocalAgentTask fill:#7d5a3c,color:#fff
style RemoteAgentTask fill:#7d3a3a,color:#fff
style TeamContext fill:#5a3a7d,color:#fff
핵심 설계 원칙: 모든 서브에이전트는 자신만의 독립적인 QueryEngine 인스턴스와 메시지 컨텍스트를 가진다. 부모 에이전트는 서브에이전트의 내부 상태를 직접 접근할 수 없으며, 오직 task-notification XML 메시지를 통해 결과를 수신한다.
3. Coordinator Mode (코디네이터 모드)
3.1 기본 동작: isCoordinatorMode()
// src/coordinator/coordinatorMode.ts
export function isCoordinatorMode(): boolean {
if (feature('COORDINATOR_MODE')) {
return isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE)
}
return false
}
코디네이터 모드는 두 겹의 게이팅(gating)을 통해 활성화된다.
- 피처 플래그(feature flag) 게이트:
feature('COORDINATOR_MODE')— Bun 번들러의bun:bundle모듈이 제공하는 빌드 타임 상수다. 플래그가false이면 번들러가 이 코드 경로 전체를 데드 코드(dead code)로 제거한다. - 환경 변수 게이트:
CLAUDE_CODE_COORDINATOR_MODE환경 변수가 truthy 값으로 설정되어야 한다.
이중 게이트 구조는 프로덕션 빌드에서 멀티에이전트 기능 코드를 완전히 제거할 수 있도록 한다.
3.2 세션 재개 시 모드 일치: matchSessionMode()
export function matchSessionMode(
sessionMode: 'coordinator' | 'normal' | undefined,
): string | undefined
저장된 세션을 재개할 때 현재 환경의 모드와 세션에 기록된 모드가 다를 수 있다. 이 함수는 process.env.CLAUDE_CODE_COORDINATOR_MODE를 런타임에 직접 수정하여 불일치를 해소한다. isCoordinatorMode()가 환경 변수를 캐시 없이 매번 직접 읽기 때문에 이 방식이 작동한다.
3.3 워커 도구 컨텍스트: getCoordinatorUserContext()
코디네이터 모드가 활성화되면 메인 에이전트는 워커(worker) 에이전트들이 어떤 도구에 접근할 수 있는지 알아야 한다. getCoordinatorUserContext()는 이 정보를 workerToolsContext 키로 반환한다.
// 내부 도구 집합 (워커에게 노출되지 않음)
const INTERNAL_WORKER_TOOLS = new Set([
TEAM_CREATE_TOOL_NAME,
TEAM_DELETE_TOOL_NAME,
SEND_MESSAGE_TOOL_NAME,
SYNTHETIC_OUTPUT_TOOL_NAME,
])
CLAUDE_CODE_SIMPLE 환경 변수가 설정된 경우 워커 도구를 Bash, Read, Edit 세 가지로만 제한하는 단순 모드도 지원한다.
3.4 코디네이터 시스템 프롬프트
getCoordinatorSystemPrompt()는 다음 단계로 구성된 멀티에이전트 워크플로를 코디네이터에게 지시하는 시스템 프롬프트를 생성한다.
| 단계 | 담당 | 목적 |
|---|---|---|
| Research (조사) | 워커 (병렬) | 코드베이스 탐색, 문제 파악 |
| Synthesis (종합) | 코디네이터 | 발견 사항 읽기, 구현 명세 작성 |
| Implementation (구현) | 워커 | 변경 적용, 커밋 |
| Verification (검증) | 워커 | 변경 사항 테스트 |
핵심 원칙은 **"절대로 이해를 위임하지 말라(Never delegate understanding)"**이다. 코디네이터는 워커의 결과를 직접 종합하여 다음 워커에게 구체적인 파일 경로, 줄 번호, 변경 내용을 포함한 지시를 작성해야 한다.
3.5 Scratchpad (스크래치패드) 게이트
function isScratchpadGateEnabled(): boolean {
return checkStatsigFeatureGate_CACHED_MAY_BE_STALE('tengu_scratch')
}
tengu_scratch 피처 게이트가 활성화되면 워커들이 퍼미션 프롬프트 없이 읽고 쓸 수 있는 공유 스크래치패드 디렉터리가 활성화된다. 스크래치패드는 워커 간 지식을 영속적으로 공유하는 메커니즘이다.
주목할 점은 isScratchpadGateEnabled()가 src/utils/permissions/filesystem.ts의 isScratchpadEnabled()와 동일한 게이트를 검사하지만 함수를 재사용하지 않는다는 것이다. 이는 filesystem.ts를 가져오면 filesystem → permissions → ... → coordinatorMode의 순환 의존성(circular dependency)이 발생하기 때문이다. 이 설계 결정은 코드 주석에 명시되어 있다.
4. AgentTool 분석
4.1 에이전트 생성 메커니즘
AgentTool.tsx는 새 에이전트를 생성하는 핵심 도구다. 입력 스키마(input schema)는 피처 플래그에 따라 동적으로 구성된다.
// 기본 입력 파라미터
const baseInputSchema = lazySchema(() => z.object({
description: z.string(), // 3-5 단어의 짧은 작업 설명
prompt: z.string(), // 에이전트에게 전달할 실제 지시
subagent_type: z.string().optional(), // 전문 에이전트 타입
model: z.enum(['sonnet', 'opus', 'haiku']).optional(),
run_in_background: z.boolean().optional(),
}));
KAIROS 피처 플래그가 활성화된 경우 cwd 파라미터(작업 디렉터리 재정의)가 추가된다. run_in_background는 CLAUDE_CODE_DISABLE_BACKGROUND_TASKS 환경 변수 또는 Fork Subagent 기능이 활성화된 경우 스키마에서 제거된다.
자동 백그라운드 타임아웃:
function getAutoBackgroundMs(): number {
if (isEnvTruthy(process.env.CLAUDE_AUTO_BACKGROUND_TASKS) ||
getFeatureValue_CACHED_MAY_BE_STALE('tengu_auto_background_agents', false)) {
return 120_000; // 2분 후 자동으로 백그라운드로 전환
}
return 0;
}
포그라운드(foreground)로 실행 중인 에이전트가 2분을 초과하면 자동으로 백그라운드로 전환된다.
4.2 AgentDefinition 타입 계층
에이전트 정의는 세 가지 소스에서 로드된다.
AgentDefinition (유니언 타입)
├── BuiltInAgentDefinition (source: 'built-in')
│ └── getSystemPrompt(params) — toolUseContext 접근 가능
├── CustomAgentDefinition (source: 'userSettings' | 'projectSettings' | ...)
│ └── getSystemPrompt() — 클로저(closure)로 마크다운 내용 캡처
└── PluginAgentDefinition (source: 'plugin')
└── getSystemPrompt() — 플러그인 메타데이터 포함
getSystemPrompt가 함수인 이유는 메모리(memory) 기능이 활성화된 경우 에이전트 메모리 프롬프트를 동적으로 결합해야 하기 때문이다. 정적 문자열이 아닌 클로저를 사용하여 이를 구현한다.
에이전트 우선순위 (덮어쓰기 순서):
built-in < plugin < userSettings < projectSettings < flagSettings < policySettings
동일한 agentType 이름이 여러 소스에 존재하면 우선순위가 높은 소스가 낮은 소스를 덮어쓴다. 예를 들어 프로젝트 설정의 커스텀 에이전트는 빌트인 에이전트를 같은 이름으로 오버라이드할 수 있다.
4.3 에이전트 로딩: loadAgentsDir.ts
getAgentDefinitionsWithOverrides(cwd)는 lodash-es/memoize로 메모화(memoize)되어 동일한 작업 디렉터리에 대해 한 번만 파일시스템을 읽는다.
마크다운 에이전트 파일 프론트매터(frontmatter) 구조:
---
name: my-agent
description: 이 에이전트를 사용할 때
model: sonnet
effort: high
permissionMode: default
isolation: worktree
memory: user
background: false
maxTurns: 50
tools: [Bash, Read, Edit]
---
에이전트 시스템 프롬프트 내용...
parseAgentFromMarkdown()은 다음을 수행한다.
isolation: 'remote'는USER_TYPE === 'ant'(Anthropic 내부 빌드)에서만 허용한다.memory필드가 설정되면FILE_WRITE_TOOL_NAME,FILE_EDIT_TOOL_NAME,FILE_READ_TOOL_NAME을 도구 목록에 자동 주입한다.HooksSchema로 훅(hook)을 파싱한다.HooksSchema가 lazy인 이유는AppState → loadAgentsDir → settings/types의 순환 의존성을 모듈 로드 시점에 끊기 위해서다.
4.4 Fork Subagent (포크 서브에이전트)
forkSubagent.ts는 부모 에이전트의 전체 대화 컨텍스트를 상속받는 자식 에이전트를 생성하는 실험적 기능을 구현한다.
export function isForkSubagentEnabled(): boolean {
if (feature('FORK_SUBAGENT')) {
if (isCoordinatorMode()) return false // 코디네이터와 상호 배타적
if (getIsNonInteractiveSession()) return false
return true
}
return false
}
포크 메커니즘의 핵심: 프롬프트 캐시 공유
모든 포크 자식은 바이트 동일(byte-identical)한 API 요청 접두사를 생성해야 캐시 히트(cache hit)가 가능하다. buildForkedMessages()는 이를 위해 다음 구조를 만든다.
[...부모 히스토리, assistant(모든_tool_use 블록), user(플레이스홀더_results..., 자식별_지시문)]
모든 tool_result 블록에 동일한 플레이스홀더 텍스트 "Fork started — processing in background"를 사용하고, 오직 마지막 텍스트 블록만 자식별로 다르게 함으로써 캐시 히트율을 극대화한다.
포크 자식 규칙 (buildChildMessage에서 강제):
포크 자식 메시지는 <fork-boilerplate> 태그로 시작하며 다음을 강제한다.
- 서브에이전트를 재귀적으로 생성하지 말 것
- 도구 호출 사이에 텍스트를 출력하지 말 것
- 응답은 반드시 "Scope:"로 시작할 것
- 파일을 수정한 경우 커밋 후 해시를 보고할 것
재귀 포크 방지는 isInForkChild()가 대화 히스토리에서 <fork-boilerplate> 태그를 탐지하는 방식으로 구현된다.
4.5 에이전트 실행: runAgent.ts
runAgent.ts는 서브에이전트의 전체 실행 수명주기(lifecycle)를 관리한다.
에이전트 전용 MCP 서버 초기화:
에이전트 정의의 프론트매터에 mcpServers가 지정된 경우, initializeAgentMcpServers()가 부모의 MCP 클라이언트에 추가로 에이전트 전용 서버를 연결한다. 에이전트 종료 시 정리 함수가 호출되어 연결을 해제한다.
파일 상태 캐시 상속:
서브에이전트는 부모의 파일 상태 캐시를 cloneFileStateCache()로 복제하여 시작한다. 이를 통해 부모가 이미 읽은 파일 정보를 서브에이전트가 재활용할 수 있다.
도구 풀(tool pool) 구성:
resolveAgentTools()는 에이전트 정의의 tools(허용 목록) 및 disallowedTools(거부 목록)을 부모의 도구 풀에 적용하여 서브에이전트의 최종 도구 집합을 결정한다.
4.6 에이전트 색상 관리
멀티에이전트 UI에서 각 에이전트를 시각적으로 구별하기 위해 agentColorManager.ts가 에이전트 타입별 색상을 관리한다. 에이전트 정의의 color 필드나 자동 할당을 통해 색상이 지정된다.
5. 팀 시스템
5.1 TeamCreateTool
TeamCreateTool은 에이전트 스웜(swarm) 기능이 활성화된 경우(isAgentSwarmsEnabled())에만 사용 가능하다.
// 팀 생성 입력 파라미터
z.strictObject({
team_name: z.string(), // 팀 이름
description: z.string().optional(),
agent_type: z.string().optional(), // 팀 리더의 역할 타입
})
팀 생성 시 수행 작업:
- 팀 파일 생성:
TeamFile구조를 파일시스템에 기록한다. 동일 이름의 팀이 이미 존재하면 새로운 고유 이름을 자동 생성한다. - 태스크 디렉터리 초기화:
resetTaskList()와ensureTasksDir()로 팀 전용 태스크 목록 디렉터리를 생성한다. 팀마다 태스크 번호가 1부터 시작한다. - 리더 팀 이름 등록:
setLeaderTeamName()을 호출하여getTaskListId()가 세션 ID 대신 팀 이름을 반환하도록 한다. - AppState 업데이트:
teamContext를 설정하여 현재 세션이 팀 컨텍스트를 인식하게 한다. - 세션 정리 등록:
registerTeamForSessionCleanup()으로 세션 종료 시 팀 디렉터리가 자동 정리되도록 한다.
리더(leader)와 팀메이트(teammate) 구분:
팀 리더는 CLAUDE_CODE_AGENT_ID 환경 변수를 설정하지 않는다. 이를 통해 isTeammate()가 리더에 대해 false를 반환하고, 인박스(inbox) 폴링(polling)을 비롯한 팀메이트 전용 동작이 리더에게는 적용되지 않는다.
5.2 TeamDeleteTool
팀 삭제는 입력 파라미터가 없는 단순한 정리 작업이다.
삭제 전 안전 검사:
const activeMembers = nonLeadMembers.filter(m => m.isActive !== false)
if (activeMembers.length > 0) {
// 활성 멤버가 있으면 삭제 거부
}
isActive !== false로 판단하는 이유는 isActive가 정의되지 않은 멤버(undefined)를 활성 상태로 간주하기 때문이다. false로 명시적으로 설정된 경우에만 유휴/종료 상태로 판단한다.
정리 순서:
- 팀 파일 및 관련 디렉터리 삭제 (
cleanupTeamDirectories) - 세션 정리 목록에서 제거 (
unregisterTeamForSessionCleanup) - 에이전트 색상 할당 초기화 (
clearTeammateColors) - 리더 팀 이름 초기화 (
clearLeaderTeamName) - AppState에서
teamContext및inbox제거
5.3 SendMessageTool (에이전트 간 통신)
SendMessageTool은 여러 통신 경로를 단일 인터페이스로 통합한다.
메시지 라우팅 결정 트리:
SendMessageTool(to, message)
├── to == "bridge:<session-id>" → 원격 제어 세션 (사용자 승인 필요)
├── to == "uds:<socket-path>" → 로컬 UDS 소켓 전송
├── to == "*" → 팀 전체 브로드캐스트
├── to == agentId (로컬 태스크) → queuePendingMessage() 또는 resumeAgentBackground()
└── to == teammateName → writeToMailbox() (파일시스템 기반)
인박스 기반 통신의 특성:
writeToMailbox()는 파일시스템의 팀 디렉터리에 메시지를 기록한다. 수신자는 자신의 인박스를 주기적으로 폴링하여 메시지를 처리한다. 이 비동기 방식은 tmux 세션이나 별도 프로세스로 실행되는 팀메이트와의 통신에 적합하다.
로컬 서브에이전트 메시지 큐잉:
로컬 에이전트 태스크(LocalAgentTask)가 실행 중인 경우 메시지를 즉시 전달하는 것이 아니라 queuePendingMessage()로 큐에 추가한다. 에이전트는 다음 도구 호출 라운드에서 큐의 메시지를 처리한다.
정지된 에이전트 자동 재개:
에이전트가 정지 상태(stopped)인 경우 SendMessageTool이 자동으로 resumeAgentBackground()를 호출하여 에이전트를 재개한다. 에이전트가 태스크 레지스트리에서 제거된 경우에도 디스크의 트랜스크립트(transcript)에서 복원할 수 있다.
구조화 메시지(structured message) 타입:
shutdown_request: 팀메이트에게 종료 요청 전송shutdown_response(approve/reject): 종료 요청에 대한 응답plan_approval_response: 플랜 모드(plan mode)에서 팀 리더의 승인/거부
6. 태스크 시스템
6.1 태스크 타입 계층
src/tasks/types.ts에 정의된 TaskState 유니언 타입은 모든 태스크 타입을 포함한다.
export type TaskState =
| LocalShellTaskState // 로컬 셸 태스크 (Bash 실행)
| LocalAgentTaskState // 로컬 에이전트 태스크 (AgentTool 생성)
| RemoteAgentTaskState // 원격 에이전트 태스크 (CCR)
| InProcessTeammateTaskState // 인-프로세스 팀메이트
| LocalWorkflowTaskState // 로컬 워크플로 태스크
| MonitorMcpTaskState // MCP 모니터 태스크
| DreamTaskState // Dream 태스크
6.2 LocalAgentTask: 로컬 에이전트 실행
LocalAgentTask는 AgentTool로 생성된 서브에이전트의 비동기 실행을 관리한다.
진행 상황 추적 (ProgressTracker):
export type ProgressTracker = {
toolUseCount: number;
latestInputTokens: number; // 누적 입력 (API가 매 턴 누적값 반환)
cumulativeOutputTokens: number; // 매 턴 출력 토큰의 합산
recentActivities: ToolActivity[];
};
입력 토큰과 출력 토큰을 별도로 추적하는 이유는 Claude API의 특성 때문이다. input_tokens는 매 요청마다 이전 컨텍스트를 포함한 누적값을 반환하므로 최신값을 유지하고, output_tokens는 턴별 값이므로 누산해야 한다.
활동 설명 해석기 (ActivityDescriptionResolver):
도구 이름과 입력을 받아 "src/foo.ts 읽기"와 같은 사람이 읽을 수 있는 활동 설명을 반환하는 함수다. 도구의 getActivityDescription() 메서드를 호출하여 생성하며, 최근 5개의 활동을 유지한다.
태스크 완료 알림:
에이전트 실행이 완료되면 다음 구조의 XML을 생성하여 부모에게 알린다.
<task-notification>
<task-id>{agentId}</task-id>
<status>completed|failed|killed</status>
<summary>{상태 요약}</summary>
<result>{에이전트의 최종 텍스트 응답}</result>
<usage>
<total_tokens>N</total_tokens>
<tool_uses>N</tool_uses>
<duration_ms>N</duration_ms>
</usage>
</task-notification>
6.3 RemoteAgentTask: 원격 실행
RemoteAgentTask는 원격 CCR(Claude Code Remote) 환경에서 실행되는 에이전트를 관리한다.
const REMOTE_TASK_TYPES = [
'remote-agent', // 일반 원격 에이전트
'ultraplan', // 대형 계획 수립
'ultrareview', // 코드 리뷰
'autofix-pr', // PR 자동 수정
'background-pr', // 백그라운드 PR 처리
] as const;
원격 태스크는 pollRemoteSessionEvents()로 원격 세션의 이벤트를 폴링하며, 완료 시 archiveRemoteSession()을 호출한다. RemoteTaskCompletionChecker 콜백을 등록하여 태스크 타입별 완료 조건을 외부에서 주입할 수 있다.
6.4 백그라운드 태스크 판별
export function isBackgroundTask(task: TaskState): task is BackgroundTaskState {
if (task.status !== 'running' && task.status !== 'pending') {
return false
}
if ('isBackgrounded' in task && task.isBackgrounded === false) {
return false // 포그라운드 태스크는 백그라운드 표시기에 나타나지 않음
}
return true
}
isBackgrounded === false(명시적 false)와 isBackgrounded === undefined(기본값)를 구분하는 것이 중요하다. undefined인 태스크는 백그라운드로 간주한다.
7. 주요 설계 결정
7.1 피처 플래그를 통한 코디네이터 모드 격리
멀티에이전트 기능은 feature('COORDINATOR_MODE') 빌드 타임 플래그로 전체 코드 경로를 조건부 컴파일한다. 이는 단순히 런타임 기능 토글이 아닌 **데드 코드 제거(dead code elimination)**를 위한 선택이다.
AgentTool.tsx의 팀메이트 관련 코드도 동일한 패턴을 사용한다.
// 타입 정의는 TypeScript 컴파일 시 제거되므로 허용
type TeammateSpawnedOutput = { ... } // 타입은 괜찮음
// 런타임 상수는 인라인 게이트 블록 내부에서만 정의
// "Multi-agent type constants are defined inline inside gated blocks
// to enable dead code elimination"
이 접근법은 멀티에이전트 기능이 비활성화된 빌드에서 번들 크기와 공격 표면(attack surface)을 최소화한다.
7.2 순환 의존성 방지를 위한 Lazy require()
AgentTool.tsx에서 Proactive 모듈을 동적으로 로드하는 패턴이 사용된다.
const proactiveModule = feature('PROACTIVE') || feature('KAIROS')
? require('../../proactive/index.js') as typeof import('../../proactive/index.js')
: null;
정적 import 대신 런타임 require()를 사용하는 것은 모듈 로드 시점의 순환 의존성을 끊기 위해서다. HooksSchema의 lazy 선언, scratchpad 게이트의 중복 구현도 같은 이유에서 비롯된다.
7.3 에이전트 격리: 컨텍스트 독립성
각 서브에이전트는 다음을 독립적으로 소유한다.
- 자체
QueryEngine인스턴스 - 부모로부터 복제된 파일 상태 캐시
- 에이전트 정의에 명시된 도구 집합
- (선택적) 격리된 Git Worktree
이 격리는 서브에이전트가 부모 컨텍스트를 오염시키거나 간섭하는 것을 방지한다. 부모와 자식 간의 유일한 통신 채널은 task-notification XML 메시지다.
7.4 Worktree 통합
isolation: 'worktree'가 지정된 에이전트는 createAgentWorktree()로 임시 Git Worktree를 생성한다. 에이전트 종료 시:
- 변경 사항이 없으면
removeAgentWorktree()로 즉시 정리 - 변경 사항이 있으면 Worktree 경로와 브랜치를 결과에 포함하여 반환
이를 통해 병렬로 실행되는 에이전트들이 서로의 파일 변경에 간섭하지 않는다.
7.5 ONE_SHOT_BUILTIN_AGENT_TYPES 최적화
export const ONE_SHOT_BUILTIN_AGENT_TYPES: ReadonlySet<string> = new Set([
'Explore',
'Plan',
])
Explore와 Plan 에이전트는 한 번 실행하고 결과를 보고하는 단발성 에이전트다. 이 에이전트들의 결과에는 agentId/SendMessage/usage 트레일러를 생략한다. 주석에 따르면 이를 통해 에이전트당 약 135자를 절약하며, 주당 3,400만 회 실행되는 Explore 에이전트 규모에서 상당한 토큰 절약이 가능하다.
7.6 에이전트 목록의 어태치먼트 메시지 전환
export function shouldInjectAgentListInMessages(): boolean {
return getFeatureValue_CACHED_MAY_BE_STALE('tengu_agent_list_attach', false)
}
에이전트 목록이 도구 설명(tool description) 안에 인라인으로 포함되면 MCP 연결, 플러그인 리로드, 권한 모드 변경 시마다 도구 스키마가 바뀌어 전체 프롬프트 캐시가 무효화된다. tengu_agent_list_attach 게이트가 활성화되면 에이전트 목록을 별도의 어태치먼트 메시지로 분리하여 도구 스키마를 정적으로 유지한다. 이는 플릿 전체 cache_creation_tokens의 10.2%를 차지하는 문제를 해결한다.
8. 정리: 오케스트레이션 흐름 요약
완전한 멀티에이전트 작업 흐름은 다음과 같다.
- 진입: 사용자 요청이 코디네이터 모드의 메인 에이전트에게 전달된다.
- 연구 단계: 메인 에이전트가 여러
AgentTool호출을 단일 메시지에 포함하여 병렬 워커를 생성한다. - 비동기 실행: 각 워커는
LocalAgentTask로 등록되어 독립적으로 실행된다. - 결과 수신: 워커 완료 시
task-notificationXML이 사용자 롤 메시지로 메인 에이전트에게 전달된다. - 종합: 메인 에이전트가 결과를 분석하고 구체적인 구현 명세를 작성한다.
- 계속:
SendMessageTool(to: agentId)로 기존 워커를 재개하거나 새 워커를 생성한다. - 팀 관리: 필요시
TeamCreateTool로 영속적인 팀 컨텍스트를 생성하고, 작업 완료 후TeamDeleteTool로 정리한다.
참고 자료
src/coordinator/coordinatorMode.ts— 코디네이터 모드 활성화, 시스템 프롬프트, 세션 재개 로직src/tools/AgentTool/AgentTool.tsx— 에이전트 생성, 백그라운드 타임아웃, 출력 스키마src/tools/AgentTool/loadAgentsDir.ts—AgentDefinition타입 계층, 마크다운/JSON 파싱src/tools/AgentTool/forkSubagent.ts— 포크 메커니즘, 캐시 공유, 재귀 방지src/tools/AgentTool/prompt.ts— 에이전트 도구 프롬프트 생성, 어태치먼트 전환src/tools/AgentTool/runAgent.ts— 에이전트 수명주기, MCP 서버, 도구 풀 구성src/tools/SendMessageTool/SendMessageTool.ts— 에이전트 간 메시지 라우팅src/tools/TeamCreateTool/TeamCreateTool.ts— 팀 생성, 태스크 디렉터리 초기화src/tools/TeamDeleteTool/TeamDeleteTool.ts— 팀 정리, 안전 검사src/tasks/LocalAgentTask/LocalAgentTask.tsx— 로컬 비동기 에이전트 태스크 관리src/tasks/RemoteAgentTask/RemoteAgentTask.tsx— 원격 CCR 에이전트 태스크src/tasks/types.ts—TaskState유니언 타입 정의