부모 에이전트가 delegate_task 또는 spawn_agent를 호출하면 core/agent/sub_agent.py의 SubAgentManager가 격리된 서브에이전트를 띄웁니다. 실행은 core/orchestration/isolated_execution.py의 IsolatedRunner가 맡습니다. 독립 작업은 실제로 병렬 실행되며 서브에이전트 경로에 별도 TaskGraph는 없습니다. 스폰과 종료마다 SUBAGENT_STARTED / SUBAGENT_COMPLETED / SUBAGENT_FAILED 훅이 발화합니다. 장기 자식의 완료는 SQLite mailbox를 통해 안전한 부모 루프 경계에 전달됩니다.
백그라운드 협업
delegate_task는 완료까지 기다리는 fan-out/best-of-N 도구입니다. 장기 작업은 spawn_agent로 안정적인 task_id를 받고 부모 작업을 계속합니다. 제어 도구는 각각 list_agents, wait_agent, interrupt_agent, send_message, followup_task입니다. 대기 시간이 끝나도 자식은 취소되지 않습니다.
| 동작 | 의미 |
|---|---|
send_message | 새 세대를 시작하지 않고 실행 중인 자식에게 컨텍스트를 큐잉 |
followup_task | 실행 중이면 다음 루프 경계에 전달하고, 종료 상태면 같은 자식 세션을 재개 |
최신 상태와 메일박스 전달은 프로젝트 sessions.db의 collaboration_runs와 collaboration_mailbox에 저장합니다. 이 둘은 제어 상태를 투영하며 별도 transcript를 만들지 않습니다. 자식의 대화, 도구 호출, 훅, trajectory는 messages와 append-only session_events에 독립 롤아웃으로 남습니다. mailbox는 자식 checkpoint 저장 뒤 승인됩니다. 재개는 완료된 도구 호출을 런타임이 자동 재생하지 않지만 모델이 같은 부작용을 다시 요청할 수 있으므로 exactly-once 계약은 아닙니다.
한도
| 노브 | 기본값 | 비고 |
|---|---|---|
max_depth | 1 | 서브에이전트는 다시 서브에이전트를 띄울 수 없습니다. 깊이 가드가 오류 결과를 반환합니다 |
max_total_subagents | 15 | 부모 세션당 고유 자식 상한; manager 재생성·resume에도 유지 |
timeout_s | 600초 | GEODE_SUBAGENT_TIMEOUT_S env로 조절, [10, 3600]으로 clamp |
time_budget_s | 0 (꺼짐) | 선택적 wall-clock 예산 |
denied_tools / working_dirs | 비어 있음 | 도구 차단 목록과 샌드박스 작업 디렉터리 추가 |
레인: 동시성의 단위
모든 실행 경로는 core/orchestration/lane_queue.py의 레인을 통과합니다. SessionLane이 같은 세션 키를 직렬화하고(다른 키는 병렬), 그 다음 글로벌 레인이 전체 동시성을 잡습니다.
| 레인 | 동시성 | 비고 |
|---|---|---|
global | max_concurrent=50 | 프로덕션 기본값 (core/wiring/container.py) |
gateway | 설정값 | 메신저 인바운드 |
anthropic-api | 레인별 설정 | Anthropic PAYG API 동시성 보호 |
seed-generation | 레인별 설정 | 시드 파이프라인 |
SessionLane은 세션 키 256개까지 유지하고 유휴 키를 정리합니다.
격리의 실제 경계
격리는 프로세스와 산출물 수준에서 일어납니다. 서브에이전트는 별도 워커 프로세스로 돌고, 산출물은 <run_dir>/sub_agents/<task_id>/ 아래에 쌓이며, 부모는 반환된 요약만 받습니다 (core/orchestration/isolated_execution.py).
메모리 쓰기 격리는 툴킷 구성으로 통제합니다. 기본 _default 툴킷은 읽기 전용이라 서브에이전트는 공유 메모리에 쓸 수 없습니다. 단, memory_save가 포함된 툴킷(예: general_purpose)을 명시하면 공유 ProjectMemory에 직접 기록됩니다. 동시 쓰기를 피하려면 쓰기 도구가 없는 툴킷을 주는 것이 통제 수단입니다.
도구와 능력의 상속
서브에이전트가 받는 것은 선언된 툴킷으로 해석된 네이티브 도구 핸들러입니다. frontmatter의 toolkit: 이름이 먼저, 레거시 tools: 목록이 다음, 둘 다 없으면 읽기 전용 _default입니다. 부모의 MCP 연결과 스킬 레지스트리는 워커 프로세스로 전달되지 않습니다 (core/agent/worker.py는 네이티브 핸들러만 구성). 자세한 해석 규칙은 도구와 툴셋을 참고합니다.
선택적 적대적 검토
중요한 문서, 설계, PR, 공개 결론을 반증 관점에서 검토할 때는 기존 reviewer 역할을 선택합니다. 부모가 최종 산출물의 판본, 목표, 판정 계약, 원근거와 제외 범위를 먼저 고정합니다. 작성자의 설명이나 이전 리뷰 점수는 검토에 필요한 경우에만 전달합니다. 다음은 delegate_task의 요청 인자 예시입니다.
{
"task_type": "analyze",
"role": "reviewer",
"task_description": "Review the frozen artifact and source evidence supplied with this task against its stated goal and acceptance contract."
}core/agent/subagent_roles.py의 역할은 grep_files와 read_document만 허용합니다.core/agent/subagent_protocol.py가 프롬프트 소스 디렉터리의 reviewer.md를 워커에 전달합니다. 새 역할이나 승격 게이트는 아닙니다.
결과는 기존 findings JSON입니다. 형식 검증 성공이나 빈 목록은 PASS 또는 병합 승인이 아닙니다. 부모가 근거를 대조하고 미확인 범위를 별도로 기록하며, 필요한 테스트와 CI는 그대로 수행합니다.
결과와 오류 분류
완료 봉투는 SubResult 하나입니다. success, output, error, duration과 사용량 롤업 (prompt_tokens, completion_tokens, usd_spent)을 담습니다. 구독이나 CLI 레인에서 사용량을 제공하지 않으면 0으로 기록됩니다.
실패 모드
| 증상 | 원인 | 해법 |
|---|---|---|
| 서브에이전트가 또 위임하려다 실패 | max_depth=1 가드 | 의도된 동작입니다. 위임 구조를 부모에서 평탄화합니다 |
| 10분쯤에서 timeout 상태로 종료 | 기본 timeout_s=600 | GEODE_SUBAGENT_TIMEOUT_S를 올립니다 (상한 3600) |
| 실행 중인 자식에게 보낸 메시지가 즉시 반영되지 않음 | 메일박스는 안전한 루프 경계에서 소비됨 | wait_agent로 상태를 확인하고, 필요하면 followup_task로 다음 세대를 시작합니다 |
| 자식 실행 중 소유 런타임이 종료됨 | 실행 중 프로세스는 다른 런타임이 인계하지 않음 | 상태가 interrupted로 복구되면 부작용을 확인한 뒤 명시적으로 followup_task를 호출합니다 |
다음
- 도구와 툴셋. 툴킷 매니페스트와 해석 순서.
- 안쪽 agentic 루프. 위임을 시작하는 쪽.
- serve와 게이트웨이. 레인이 보호하는 데몬.