오케스트레이션·멀티에이전트 — 횡단분석
오케스트레이션·멀티에이전트 — 횡단분석
한 줄 요약
오케스트레이션 = 한 명의 만능 에이전트로 다 처리하지 않고 여러 일꾼을 나눠 부리는 방식이다. 왜 배우나 — 큰 작업을 안전하게 병렬화하면서 메인 컨텍스트를 깨끗하게 지키는 설계는 7개 하네스가 거의 같은 곳으로 수렴하는데, 그 “자연법칙”과 갈림길을 알면 내 스택에 무엇을 차용할지 보인다.
그림 — 위임의 생명주기와 두 비교축
비교의 칼끝은 두 가지다 — ① 무엇을 통신 매체로 쓰는가(같은 프로세스 안 컨텍스트 격리 vs 디스크/파일시스템 vs OS 프로세스), ② 누가 일감을 쪼개고 라우팅하는가(모델 자율 vs 규칙/메타데이터 vs 의존성 그래프 분석). 이 두 축에서 7개가 정확히 갈린다.
flowchart TD
A(["리더 에이전트<br/>큰 작업 받음"]) --> B{"일감을 누가 쪼개나?"}
B -->|모델 자율| C1["CC · Codex"]
B -->|"규칙·메타데이터"| C2["OMC · 내 패턴"]
B -->|의존성 그래프| C3[ouroboros]
B -->|"위임 안 함, 분류만"| C4[fable-ish]
C1 --> D{"통신 매체는?"}
C2 --> D
C3 --> D
D -->|"컨텍스트 격리<br/>in-process"| E1["가볍고 빠름<br/>벤더 락인"]
D -->|"파일시스템<br/>tasks·outbox·heartbeat"| E2["영속·감사가능<br/>분산복잡도"]
D -->|"OS 프로세스<br/>타사 CLI"| E3["벤더 탈출<br/>보안레이어 필요"]
E1 --> F(["워커 실행: 별도 창/스레드/세션"])
E2 --> F
E3 --> F
F --> G(["요약·영수증만 반환<br/>raw는 격리·차단"])
G --> H(["리더가 회수·병합·다음 단계"])
쉽게 풀기
큰 회사의 팀장 한 명을 떠올려 보자. 작은 일은 직접 하지만, 큰 프로젝트가 오면 직접 다 하지 않고 팀원에게 나눠 맡긴다. 멀티에이전트가 바로 이 구조다. 그런데 “잘 나눠 맡기는 팀장”이 되려면 네 가지를 정해야 한다.
- 왜 나눠 맡길까? 팀장 책상이 서류로 뒤덮이면 판단이 흐려진다. 팀원에게 조사·로그·테스트 같은 잡다한 작업을 통째로 떠넘기고, 결론(요약)만 보고받으면 팀장 머릿속이 깨끗하게 유지된다. 이게 위임의 진짜 1차 목적이다. 일을 나누는 것보다 메인 컨텍스트를 더럽히지 않는 것이 핵심이다.
- 누가 일을 쪼개나? ① 팀원의 자기소개서(
description)를 읽고 팀장이 직감으로 배정하거나, ② “다중 파일 작업은 무조건 executor에게”처럼 사규(규칙)로 정하거나, ③ 작업 간 선후 관계를 분석해 자동으로 순서를 짜는 방식이 있다. - 어떻게 보고받나? 팀원이 100쪽 보고서를 그대로 팀장 책상에 올리면 책상이 다시 더러워진다. 그래서 요약 한 장만 올리고, 원본은 캐비닛에 보관해 두었다가 필요할 때만 꺼낸다(gajae의 영수증
agent://<id>). - 사고를 어떻게 막나? 팀원이 또 팀원을 무한히 뽑거나(재귀 폭발), 동시에 100명이 같은 문서를 고치면(충돌) 회사가 망한다. 그래서 깊이 제한·동시성 상한·충돌 중재 같은 안전장치를 둔다.
반대로 fable-ish는 “팀원을 아예 안 뽑는” 미니멀리스트 팀장이다. 혼자 일하되, 출구마다 검문소(quick/normal/deep/blocked 분류 게이트)를 세워 “검증 안 끝났으면 못 나간다”를 강제한다. 오케스트레이션을 안 하는 것도 하나의 선택임을 보여주는 대조 표본이다.
핵심 정리
7개 프레임워크를 두 비교축으로 압축하면 다음과 같다. (필드/스키마는 대표값만, 정확한 전체는 각 기능노트 참조.)
| 프레임워크 | 일감 쪼개는 주체 | 통신 매체 | 한 줄 특이점 |
|---|---|---|---|
| Claude Code | 모델 자율(위임 판단) | in-process 컨텍스트 | named subagent는 1단 중첩·요약만 반환 |
| Codex | 모델 자율(사용자 명시 필요) | in-process ThreadId | 과학자 닉네임 풀·depth/slot으로 재귀 제한 |
| OMC | 규칙·메타데이터 | 네이티브=컨텍스트 / 브리지=파일시스템 | 타사 CLI를 OS 프로세스 워커로 + 거버넌스·감사 |
| gajae-code | 모델 자율 + 모호성 게이팅 | 워크트리 + receipt 참조 | 4명 초과 병렬 시 증명 5필드 강제 |
| ouroboros | 의존성 그래프(+LLM 보강) | in-process / job / plugin 봉투 | AC 의존성 위상정렬로 자동 병렬·충돌 중재 |
| fable-ish | (위임 없음) 분류만 | 훅 + 장부 | 유일하게 멀티에이전트를 의도적으로 안 함 |
| 내 패턴 | 규칙·메타데이터 | in-process(OMC와 동일) | 저자≠리뷰어 거버넌스를 한국어로 재강제 |
[!note] 멀티에이전트가 모두 수렴하는 5가지 “자연법칙” 실제 구현한 6개(fable-ish 제외)는 서로 베끼지 않았는데도 같은 다섯 가지로 수렴한다.
- 컨텍스트 격리 = 존재 이유. 별도 창/스레드/세션. 정당화 문장이 전부 똑같다 — 대량 출력이 서브 창에 갇히고 메인엔 결론만 올라온다. CC·Codex가 공유하는 단어가 “context rot/pollution”.
- 요약·참조만 반환. raw를 도로 부으면 격리가 무의미. gajae
outputRef=agent://<id>(필요 시 다시 읽기)가 가장 정교. (단 보편 법칙은 아님 — Claude는 “자세한 결과는 컨텍스트를 먹는다”고 경고하는 수준이고, gajae는 raw를 artifact로 보존한다.)- 재귀 폭발 억제. 다만 “전부 금지”는 아니다 →
hard block(CC named) /bounded recursion(Codex depth·slot) /explicit spawns(gajae) /prompt-governed(OMC worker preamble)로 갈린다.- 동시성 상한. Codex
reserve_spawn_slotCAS, gajaemapWithConcurrencyLimit, ouroboros_plan_parallel_workers, OMC tmux 패인 N.- 역할 = 시스템 프롬프트 = 책임 경계.
<Role>에 “responsible for / NOT responsible for”를 박아 중복·월권을 막는다.
[!note] 분기점 — 누가 왜 다르게 했나(트레이드오프) 통신 매체 — in-process(CC·Codex·내패턴)는 가볍고 회수 즉각적이나 벤더 락인. 파일시스템(OMC 브리지·ouroboros job·gajae receipt)은 영속·감사가능하나 폴링 지연·파일락 등 분산복잡도. OS 프로세스+타사 CLI(OMC 시그니처)는 벤더 탈출이 되나 위험플래그 때문에 sanitize·감사 동반 필수. 왜? CC/Codex는 코어 하네스라 자기 런타임 신뢰→in-process로 충분, OMC는 플러그인이라 코어를 못 고쳐 바깥으로 나감, ouroboros는 자기개선 루프라 세대 간 재개=영속이 필수. 충돌 처리 — ouroboros는 사후 중재(
LevelCoordinator, 충돌 없으면 비용0), gajae는 격리+cherry-pick 병합, OMC는 거버넌스로 동시 작업면 축소 + team엔 heartbeat·worktree·merge drain·conflict audit 운영면, CC·Codex 코어엔 충돌 메커니즘이 없어 읽기 위주 위임을 권장.
실제 예시
각 하네스의 핵심 형식·트리거를 실물로 본다(파일경로 주석 유지).
# Claude Code: agents/*.md frontmatter (대표 필드)
# 실제 지원: disallowedTools/permissionMode/maxTurns/skills/mcpServers/hooks/effort/color/initialPrompt 등
# 근거: _원문아카이브/claude-code/sub-agents.md:277
name: silent-failure-hunter
description: |
자동위임 트리거 예시를 description 안에 직접 박는다.
<example>Context/user/assistant/<Task invocation></example> # 위임 타이밍 학습
tools: [Read, Grep]
isolation: worktree # git 격리 복사본 실행
# 본문 = 하위세션 시스템 프롬프트. named subagent는 CC 전체 시스템프롬프트 미상속(CLAUDE.md+git만).
# 단, forked subagent는 부모 대화·시스템프롬프트·도구·모델·기록을 상속한다(sub-agents.md:914).
// Codex: spawn_agent 도구 (Rust). v1/v2 도구면이 다르다.
// v2: task_name + message 필수, service_tier 있음 (multi_agents_spec.rs:80)
// v1: fork_context (multi_agents_spec.rs:555) ← "fork_turns" 아님
// spawned agent는 same tools + 자기 subagent spawn 가능 → 재귀는 depth/slot으로 "제한"(금지 아님)
// 닉네임 풀 101개, 마지막 Jason (agent_names.txt:101). 소진 시 "Newton the 2nd" 서수
// 회수: wait_agent 또는 <subagent_notification>. v2엔 send_message/followup_task/interrupt_agent/list_agents 추가(spec_plan.rs:701)
// OMC: 두 갈래 멀티에이전트
// (a) 네이티브 — 오케스트레이터 TodoWrite 분해 → Task(subagent_type="oh-my-claudecode:<name>")
// .md 본문 = 하위세션 시스템프롬프트. registry 모델은 TS AgentConfig에서 해석(definitions.ts:263)
// "NEVER spawn"은 team worker 프로토콜에만 적용(worker-bootstrap.ts:246).
// native executor는 read-only explore/architect/외부상담 허용(executor.md:63)
// (b) 브리지 — /team N:codex "..." → child_process.spawn으로 tmux 패인마다 codex/gemini를 OS 프로세스로
// 통신 매체 = 파일시스템(tasks/*.json·outbox·heartbeat·shared-memory), 파일락 폴 루프
// bridge daemon provider validation = codex|gemini (mcp-team-bridge.ts:168)
// 감사로그 0o600 JSONL + 거버넌스(delegation_only) — "통제되는 멀티에이전트"
// gajae-code: 모호성 게이팅 — 4명 초과 병렬이면 SpawnPlanReceipt 5필드 강제
// 근거: packages/coding-agent/src/task/spawn-gate.ts
const receipt = {
whyParallel: "...", // 왜 병렬이어야 하는가
whyNotLocal: "...", // 왜 로컬에서 못 하는가
independence: "...", // 작업 간 독립성
expectedReceiptShape: "...",
maxInlineTokens: 2000,
};
// 부모는 풀텍스트 아닌 영수증만 받음: outputRef=agent://<id> + sha256
// BANNED_RAW_TASK_KEYS로 receipt 표면누출 차단(receipt.ts:54)
// 단 full raw output은 <id>.md로 보존되고 agent://<id>가 그 파일을 가리킴(task.md:119)
// "await 타임아웃=관찰창, 실패신호 아님" 규약(AGENTS.md:44) — 자동취소 금지
# ouroboros: 일감을 모델이 아니라 의존성 그래프가 쪼갠다
# DependencyAnalyzer가 structured signal에 LLM dependency pass를 합쳐 레벨그래프 생성(dependency_analyzer.py:369)
# 스테이지 직렬 · 스테이지 내 AC 병렬(anyio.task_group)
# 모델은 Seed 전체가 아니라 자기 AC 1개 + 형제경계 + 직전레벨 컨텍스트 + 코디네이터 경고만 받음
# LevelCoordinator: 레벨 끝 Write/Edit 충돌 감지 → 충돌 있을 때만 중재(coordinator.py)
# stall 900s CancelScope를 메시지마다 리셋 + 30s heartbeat
# 핵심 장기작업 표면: job_id/status/wait/result (job_handlers.py:930)
# _subagent 봉투는 OpenCode plugin mode에서만 emit, 그 외 runtime은 in-process(subagent.py:748)
요약 & 셀프체크
- 위임의 1차 목적은 일을 나누는 게 아니라 메인 컨텍스트를 깨끗하게 지키는 것이다. 그래서 격리·요약반환·재귀억제·동시성상한·역할경계 5가지로 모두 수렴한다.
- 두 비교축은 통신 매체(컨텍스트/파일시스템/OS프로세스)와 일감 쪼개는 주체(모델 자율/규칙/그래프)다. 코어냐 플러그인이냐 자기개선이냐가 선택을 갈랐다.
- 내 스택(CC+OMC+Codex)에 바로 이식 가능한 것 — gajae의
SpawnPlanReceipt하드 게이트,agent://<id>+sha256영수증, ouroboros의LevelCoordinator충돌 게이트와 stall reset+heartbeat. 이미 강한 것 — 저자≠리뷰어 거버넌스.
[!question] 스스로 답해보기
- “컨텍스트 격리”가 위임의 본질이라면, 격리해 놓고도 워커가 raw 출력을 메인에 그대로 올리면 무엇이 무너지는가? 이를 막는 패턴 두 개를 들어라.
- 같은 “OMC”인데 네이티브와 브리지가 통신 매체가 다른 이유는? 플러그인이라는 제약이 어떻게 OS 프로세스+보안레이어로 이어졌는지 설명하라.
- ouroboros가 일감을 “모델이 아니라 그래프로 쪼갠다”는 표현이 정확히는 왜 절반만 맞는가?
연결
기능노트:
- CC_60_subagents · CC_90_plugins-and-omc-teams
- CX_60_subagents-multi-agent
- OMC_30_subagents · OMC_80_teams-bridge-runtime
- GJ_40_subagents-and-task-delegation
- OB_40_orchestrator-execution-loop · OB_60_mcp-server-tools-and-subagents
- FB_40_task-classification-engine · FB_개요(오케스트레이션 2점 근거)
- MINE_50_subagents-format
소스/문서:
/mnt/d/6study/10_프레임워크분석/_원문아카이브/claude-code/sub-agents.md(frontmatter 표·named/forked·모델/도구 해결·--agentsJSON)/home/seunghyeong/harness-work/claude-code/plugins/pr-review-toolkit/agents/silent-failure-hunter.md(<example>+<Task invocation>)/home/seunghyeong/harness-work/codex/codex-rs/core/src/agent/role.rs·registry.rs·control.rs(role 정적맵·닉네임·depth) +templates/agents/orchestrator.md+multi_agents_spec.rs·spec_plan.rs(v1/v2 도구면)/home/seunghyeong/harness-work/codex/codex-rs/core/src/agent/agent_names.txt(과학자 닉네임 101)/home/seunghyeong/.claude/plugins/marketplaces/omc/bridge/team-bridge.cjs·team-mcp.cjs(spawnCliProcess codex/gemini, 파일락 폴 루프) +mcp-team-bridge.ts(provider validation·hard timeout)/home/seunghyeong/harness-work/oh-my-claudecode/src/team/governance.ts·audit-log.ts·delegation-evidence.ts(거버넌스·감사 enum·broad-task 판별) +merge-orchestrator.ts(merge drain·conflict audit)/home/seunghyeong/harness-work/oh-my-claudecode/agents/executor.md·architect.md+src/agents/definitions.ts(19에이전트 레지스트리) +utils.ts(frontmatter loader) +worker-bootstrap.ts(NEVER spawn)/home/seunghyeong/harness-work/gajae-code/packages/coding-agent/src/task/{spawn-gate.ts(SpawnPlanReceipt),receipt.ts(BANNED_RAW_TASK_KEYS),worktree.ts,parallel.ts} +src/prompts/agents/*.md+AGENTS.md(L14 team skill·L44 관찰창 규약)/home/seunghyeong/harness-work/ouroboros/src/ouroboros/orchestrator/{parallel_executor.py(stall/heartbeat/AC병렬),dependency_analyzer.py(레벨그래프+LLM pass),coordinator.py(충돌중재)} +mcp/tools/subagent.py(_subagent 봉투) +job_handlers.py(job_id/status/wait/result)/home/seunghyeong/harness-work/fable-ish/scripts/classify_task.py(멀티에이전트 부재, 분류 게이트)/home/seunghyeong/.claude/plugins/marketplaces/omc/agents/(내패턴 실사용 19종) +/mnt/d/human-token-workflow/AGENTS.md(L21 저자≠리뷰어 한국어 재강제)
관련 축:
[!tip] 차용안 — 내 스택(CC+OMC+Codex)에 이식 가능한 것
- gajae
SpawnPlanReceipt모호성 게이팅(최우선) — 4명 초과 병렬 시 5필드 강제. 단delegation_rules프롬프트만으론 약하고omc team start/team API 전 단계 하드 게이트여야 한다.- gajae
agent://<id>+sha256영수증 — OMC team bridge엔 현실적(파일상태·outbox·audit 이미 있음, artifact store+read tool+hash+retention만 붙이면). 단 네이티브 ClaudeTask반환 완전 대체는 코어 한계로 어렵다.- ouroboros
LevelCoordinator충돌 게이트 — team/worktree executor엔 좋다. shared-checkout 네이티브 subagent엔 hook/transcript/git-diff로 Write/Edit 경로 계측이 먼저 필요.- Codex
fork_context상속 제어 — 그대로 노출은 가장 비현실적(Claude엔 fork는 있으나 임의 “last N turns” 노출 아님). “최근 N턴 요약을 prompt에 삽입”하는 시뮬레이션이 현실적.- ouroboros stall reset + 30s heartbeat — OMC bridge에 이식 가치. 현재 CLI child에 hard timeout만 있으니(
mcp-team-bridge.ts:492), stdout/stderr/status/turn_count 활동 기준으로 deadline을 리셋하는 쪽이 자연스럽다.- 이미 잘 하는 것 — 내 패턴의 저자≠리뷰어(self-approve 금지) 거버넌스는 7개 중 가장 강하게 명문화(작업 리포까지 한국어 재강제). OMC 감사로그(0o600 JSONL)+거버넌스 객체도 베스트.
Codex 교차검증 결론 — 큰 비교축은 유용하나, 소스 기반 횡단분석으로 쓰려면 Codex v1/v2, Claude named/forked, OMC native/team, gajae public-role/bundled-agent, ouroboros in-process/job/plugin-envelope를 각각 분리해야 한다. 본 재작성판은 이 지적을 반영해 “전부 재귀 금지”→
hard block/bounded/explicit/prompt-governed로, “요약만 반환=보편법칙”→예외(Claude 경고 수준·gajae raw 보존) 명시로 교정했다. (static source review만, 테스트 미실행.)