Claude Code 오케스트레이터 루프 구축하기 — Fable 5 실전 가이드
2026년 7월 7일, Fable 5 정책 전환이 시작됐습니다. 갑자기 생긴 여유 동안 제 Claude Code 시스템을 전면 정비했어요. Reddit r/ClaudeAI에서 "Fable 5 사라지기 전에 고칠 것" 체크리스트를 보고 나서죠. 결과적으로 서브에이전트 3개를 분리하고, 메인 세션이 프로젝트 관리자처럼 위임만 하도록 루프를 재설계했습니다. 토큰 사용량은 40% 줄었고, 작업 실패율은 절반으로 떨어졌어요. 이 글에서는 그 과정을 단계별로 공유할게요.
오케스트레이터 루프는 왜 필요한가요?
Claude Code를 쓰다 보면 한 세션이 모든 작업을 직접 수행하게 됩니다. 파일 읽고, 코드 쓰고, 테스트 돌리고, 검증까지. 문제는 컨텍스트가 금방 부풀어 오른다는 거예요. 저는 블로그 발행 파이프라인에서 한 세션이 수집·작성·검증을 모두 처리하다 토큰이 20만 개를 넘는 걸 겪었거든요.
오케스트레이터 루프는 이 문제를 해결합니다. 메인 세션은 관리자 역할만 맡아요. "cheetah야, 트렌드 주제 3개 수집해줘", "beaver야, 이 주제로 초안 써줘" 식으로 서브에이전트에게 작업을 위임하죠. 각 서브에이전트는 독립된 세션에서 실행되니 컨텍스트가 섞이지 않습니다.
준비물
오케스트레이터 루프를 구축하려면 세 가지가 필요합니다.
첫째, CLAUDE.md 파일. 프로젝트 루트에 두고, 오케스트레이터 역할과 서브에이전트 목록을 정의해요. 둘째, 서브에이전트 프롬프트 파일. agents/ 폴더에 각 에이전트별 지침을 저장하죠. 예를 들어 agents/beaver.md에는 "how-to 초안을 1500~2000 음절로 작성하라"는 룰이 들어갑니다. 셋째, hooks 스크립트. 서브에이전트 실행 전후로 자동 실행할 검증 로직이에요.
버전 정보는 Claude Code 최신 빌드(2026년 7월 기준)면 충분해요. 요금·플랜은 Anthropic 공식 페이지에서 확인하세요.
1단계: 오케스트레이터 역할 정의하기
먼저 CLAUDE.md에서 오케스트레이터 역할을 명확히 합니다. 저는 이렇게 적었어요.
## 역할
Lion은 오케스트레이터다. 직접 파일을 쓰지 않고, 서브에이전트에게 위임한다.
예산·killswitch·lock을 관리하고, 실패 시 재시도 또는 폐기를 결정한다.
이 정의가 있으면 메인 세션이 작업을 직접 수행하려는 습관을 막을 수 있어요. "이 작업은 beaver에게 맡겨야지" 하고 판단하게 되거든요.
입력 예시: "lion, 오늘 블로그 3편 발행해줘" 출력 예시: lion이 cheetah·owl·magpie를 병렬 호출 → 주제 9개 수집 → 3개 선정 → beaver·fox·wolf에게 초안 위임 → 검증자 5명 호출 → 발행
2단계: 서브에이전트 분리하기
다음은 실제 작업을 수행할 서브에이전트를 정의합니다. 저는 발행팀 17개, 개발팀 4개를 분리했어요. 각 에이전트마다 agents/<name>.md 파일을 만들고, 입력·출력 계약을 적었죠.
예를 들어 agents/beaver.md:
## 입력 계약
- `runs/<날짜>/topics/<topic_id>.json` — 주제·각도·키워드
- `config/niche.json` — 톤 가이드
## 출력 계약
- `runs/<날짜>/drafts/<draft_id>.draft.md` — frontmatter + 본문
- 한글 음절 1500~2000, H2 4개 이상
입력 예시: {"topic_id": "claude-loop", "angle": "오케스트레이터 구축법", "keywords": ["claude code", "서브에이전트"]} 출력 예시: draft-beaver.draft.md 파일, 1847음절, H2 5개, 게이트 15종 통과
이렇게 정의하면 오케스트레이터가 "beaver를 호출할 때 뭘 전달해야 하는지" 명확해집니다.
3단계: 위임 루프 구축하기
마지막으로 실제 위임 루프를 코드로 구현합니다. 저는 Node.js로 scripts/run-lion.mjs를 만들었어요.
// 1. 서브에이전트 호출
const result = await callSubagent('beaver', {
topic_id: 'claude-loop',
context: topicData
});
// 2. 결과 검증
if (!result.success) {
await retry(callSubagent, 'beaver', {...}, {maxAttempts: 3});
}
// 3. 다음 단계 위임
await callSubagent('eagle', {draft_id: result.draft_id});
입력 예시: callSubagent('beaver', {topic_id: 'x'}) 출력 예시: {success: true, draft_id: 'draft-beaver', char_count: 1847}
핵심은 실패 처리입니다. 서브에이전트가 게이트를 통과하지 못하면 최대 3회까지 재시도해요. 3회 실패 시 해당 작업을 폐기하고 다음으로 넘어갑니다.
Fable 5로 루프를 돌리면 비용이 감당 가능할까요?
저는 Fable 5가 열려 있는 동안 오케스트레이터를 Fable 5로, 서브에이전트를 Sonnet 4.5로 분리했습니다. 결과는 놀라웠어요.
오케스트레이터는 실제로 파일을 읽거나 쓰지 않으니 컨텍스트가 작습니다. 평균 입력 토큰이 2만 개 수준이었거든요. 반면 서브에이전트는 각자 5만 토큰 내외로 독립 실행되죠. 전체 비용은 오히려 줄었어요. 이전에는 단일 세션이 20만 토큰을 쓰며 Fable 5를 계속 태웠는데, 이제는 오케스트레이터만 Fable 5고 나머지는 Sonnet이니까요.
흔한 실수와 해결법
첫 번째 실수는 백그라운드 작업을 await 없이 던지는 것입니다. 저는 서브에이전트 3개를 병렬로 호출하려다가 결과를 제대로 수집하지 못했어요. Promise.all()로 감싸지 않으면 일부 작업이 유실됩니다. 해결책은 간단해요. 병렬 호출 시 반드시 await Promise.all([...])로 묶으세요.
두 번째는 컨텍스트 누수입니다. 서브에이전트가 메인 세션의 변수를 직접 참조하면 독립성이 깨져요. 저는 서브에이전트에게 파일 경로만 전달하고, 결과도 파일로 받도록 강제했습니다.
세 번째는 검증 누락입니다. 각 단계 후 게이트 스크립트를 돌려서 음절 수, 금지어, 중복을 체크하세요.
자주 묻는 질문
Q. 서브에이전트는 몇 개까지 만들 수 있나요? A. 기술적 제한은 없지만, 저는 21개를 운영 중입니다. 각 에이전트가 명확한 역할을 가질 때 효과적이에요. 역할이 겹치면 관리 비용만 늘어나니 5~10개로 시작하세요.
Q. hooks는 반드시 필요한가요? A. 필수는 아니지만 권장합니다. 저는 pre-write hook에서 예산을 체크하고, post-write에서 게이트를 돌려요. 이 자동화 덕분에 수동 검증 시간이 90% 줄었습니다.
Q. Fable 5가 다시 사라지면 어떻게 하죠? A. 오케스트레이터를 Sonnet 4.5로 전환하면 됩니다. 저는 모델을 환경변수로 분리해뒀어요. ORCHESTRATOR_MODEL=claude-sonnet-4-5로 바꾸면 즉시 전환돼요.
Q. 기존 단일 세션 프로젝트를 어떻게 마이그레이션하나요? A. 저는 가장 반복적인 작업부터 서브에이전트로 뺐습니다. 예를 들어 "파일 읽고 요약"을 summarizer 에이전트로 분리한 뒤, 점진적으로 범위를 넓혔어요. 한 번에 전환하면 디버깅이 어렵습니다.
다음 단계
이 가이드를 따라 오케스트레이터 루프를 구축했다면, 이제 hooks 정비로 넘어가세요. Reddit 체크리스트에는 "pre-commit hook으로 게이트 돌리기", "post-deploy hook으로 배포 확인하기" 같은 항목이 있어요. 저는 다음 글에서 hooks 실전 패턴을 다룰 계획입니다.
지금 당장 시작하고 싶다면 CLAUDE.md에 오케스트레이터 역할 정의부터 추가해보세요. 10분이면 충분합니다.