OMC는 만능 AI 한 명 대신 역할이 정해진 전문가 19명을 두고, 각 전문가를 agents/ 폴더의 마크다운 파일 한 장으로 정의한다. 서브에이전트는 OMC의 핵심 확장점이라, 이 구조만 알면 .md 한 장으로 나만의 AI 전문가를 추가할 수 있다.
그림
flowchart TD
U[사용자 요청] --> O["메인 오케스트레이터<br/>지휘자 Claude"]
O -->|할 일 목록으로 분해| R{"위임 규칙<br/>+ 트리거 키워드"}
R -->|구현 작업| EX[executor 호출]
R -->|"설계·디버그"| AR["architect 호출 · 읽기전용"]
R -->|계획 수립| PL[planner 호출]
subgraph 로딩["전문가 대본 불러오기"]
MD["(agents/*.md 파일)"] -->|머리말 떼고 본문만| P[역할 대본 prompt]
MD -->|정규식으로 추출| DT[금지 도구 목록]
end
P --> EX
DT --> AR
EX -->|"워커 프리앰블:<br/>하위 호출 금지"| EX
EX -->|정해진 형식의 산출물| O
AR -->|정해진 형식의 산출물| O
O --> V["검증 · 완료"]
쉽게 풀기
1. 전문가 한 명 = 마크다운 파일 한 장
한 사람이 기획·개발·검토·디버깅을 다 하면 실수가 많다. 그래서 OMC는 일을 역할별 전문가에게 나눠 맡긴다. 명단은 agents/ 폴더에 있고, 전문가 한 명 = .md 한 장이다. 예: executor.md(구현 담당), architect.md(설계·디버깅 자문, 읽기 전용).
2. 파일의 두 부분: 명함 + 업무 대본
각 .md는 두 부분이다.
명함(머리말, frontmatter) — 맨 위 메타 블록. 이름, 두뇌(haiku/sonnet/opus), 못 쓰는 도구 같은 신상 정보.
업무 대본(본문) — <Role>, <Constraints> 등 태그로 “너는 누구다 / 무엇을 하라 / 무엇은 절대 하지 마라”를 적은 연기 지문.
비유: 명함은 사원증, 본문은 출근할 때마다 읽는 업무 매뉴얼.
3. 지휘자가 일감을 나눠준다
지휘자(메인 오케스트레이터 Claude)는 요청을 잘게 쪼갠 뒤, CLAUDE.md의 위임 규칙을 보고 “구현이면 executor, 설계 분석이면 architect”로 일감을 던진다. 직접 코딩하기보다 적임자를 골라 부르는 역할이다.
4. 반전 — 명함과 대본 중 실제로 쓰이는 부분이 다르다
핵심 함정이다. 사람 눈엔 명함의 name/model이 중요해 보이지만, 런타임이 .md에서 실제로 꺼내 쓰는 건 본문(대본)과 “금지 도구” 한 줄뿐이다. 이름·설명·모델의 진짜 출처는 .md가 아니라 코드(src/agents/<이름>.ts)다. 사원증 직급은 장식이고 실제 권한은 인사 시스템(코드)에 등록된 값으로 돈다.
머리말의 disallowedTools: Write, Edit가 유일하게 실제 파싱되는 강제 가드레일이며, 이 한 줄이 architect를 읽기 전용으로 묶는다.
펼쳐보기: architect.md 전문
// /home/seunghyeong/harness-work/oh-my-claudecode/agents/architect.md---name: architectdescription: Strategic Architecture & Debugging Advisor (Opus, READ-ONLY)model: opuslevel: 3disallowedTools: Write, Edit---<Agent_Prompt> <Role> You are Architect. Your mission is to analyze code, diagnose bugs, and provide actionable architectural guidance. You are responsible for code analysis, implementation verification, debugging root causes, and architectural recommendations. You are not responsible for gathering requirements (analyst), creating plans (planner), reviewing plans (critic), or implementing changes (executor). </Role> ... <Constraints> - You are READ-ONLY. Write and Edit tools are blocked. You never implement changes. - Never judge code you have not opened and read. - Acknowledge uncertainty when present rather than speculating. - Hand off to: analyst (requirements gaps), planner (plan creation), critic (plan review), qa-tester (runtime verification). </Constraints>
예시 B — executor의 제약 (혼자 일하기·최소 변경·에스컬레이션)
펼쳐보기: executor.md <Constraints> 전문
// /home/seunghyeong/harness-work/oh-my-claudecode/agents/executor.md <Constraints> - Work ALONE for implementation. READ-ONLY exploration via explore agents (max 3) is permitted. All code changes are yours alone. - Prefer the smallest viable change. Do not broaden scope beyond requested behavior. - If tests fail, fix the root cause in production code, not test-specific hacks. - Plan files (.omc/plans/*.md) are READ-ONLY. Never modify them. - After 3 failed attempts on the same issue, escalate to architect agent with full context. </Constraints>
예시 C·D — 런타임이 .md를 읽는 두 경로
flowchart TD
F[".md 파일 읽기"] --> A["stripFrontmatter()<br/>정규식 ^---...---"]
A -->|본문만 trim| PR["loadAgentPrompt → prompt<br/>(이름 검증: 영숫자·하이픈만)"]
F --> B["머리말 블록만 매치"]
B --> C["disallowedTools: 줄 추출<br/>쉼표로 split·trim"]
C --> D["parseDisallowedTools → string[]"]
펼쳐보기: utils.ts 코드 전문 ( utils.ts:76, :300)
// src/agents/utils.ts — 본문만 prompt로 로딩function stripFrontmatter(content: string): string { const match = content.match(/^---[\s\S]*?---\s*([\s\S]*)$/); return match ? match[1].trim() : content.trim();}export function loadAgentPrompt(agentName: string): string { // 보안: 에이전트 이름은 영숫자와 하이픈만 허용 if (!/^[a-z0-9-]+$/i.test(agentName)) { throw new Error(`Invalid agent name: contains disallowed characters`); } // ... 빌드타임 __AGENT_PROMPTS__ 우선, 없으면 런타임 파일 읽기 ... const content = readFileSync(agentPath, 'utf-8'); return stripFrontmatter(content); // 머리말은 버리고 본문만 prompt로 사용}
// src/agents/utils.ts — 머리말에서 금지 도구만 정규식으로 추출export function parseDisallowedTools(agentName: string): string[] | undefined { // ... 경로 보안 검사 ... const content = readFileSync(agentPath, 'utf-8'); const match = content.match(/^---[\s\S]*?---/); // 머리말 블록 if (!match) return undefined; const disallowedMatch = match[0].match(/^disallowedTools:\s*(.+)/m); if (!disallowedMatch) return undefined; return disallowedMatch[1].split(',').map(t => t.trim()).filter(Boolean);}
예시 E — 나만의 전문가 추가 (복붙용 최소 템플릿)
agents/my-reviewer.md 한 장만 만들면 새 전문가가 추가된다(파일명 = name).
펼쳐보기: my-reviewer.md 최소 템플릿 전문
// agents/my-reviewer.md---name: my-reviewerdescription: Focused diff reviewer for correctness bugs (Sonnet)model: sonnetlevel: 2disallowedTools: Write, Edit---<Agent_Prompt> <Role> You are MyReviewer. Your mission is to review a code diff for correctness bugs only. You are responsible for finding logic defects with file:line evidence. You are NOT responsible for implementing fixes, planning, or style nitpicks. </Role> <Why_This_Matters> Reviews without file:line evidence are unreliable and waste implementer time. </Why_This_Matters> <Success_Criteria> - Every finding cites a specific file:line reference - Only correctness bugs reported (no style churn) </Success_Criteria> <Constraints> - You are READ-ONLY. Write and Edit are blocked. Never implement changes. - Work ALONE. Do NOT spawn sub-agents or use the Task tool. - Never report issues in code you have not opened and read. </Constraints> <Output_Format> ## Findings - `file.ts:42` — [bug] → [suggested fix] ## Summary [1-2 sentences: severity and count] </Output_Format></Agent_Prompt>
추가할 때 체크리스트
파일명과 name 정확히 일치(소문자·숫자·하이픈만).
model을 작업 무게에 맞게(조회 haiku / 표준 sonnet / 심층 opus).
읽기 전용이면 disallowedTools: Write, Edit — 유일하게 실제 파싱되는 가드레일.
<Role>에 “책임지지 않는 것” 명시(역할 경계 → 다른 전문가와 중복 방지).
<Constraints>에 “Work ALONE / NO sub-agents”로 재귀 폭발 방지.
<Output_Format>을 호출자가 파싱하기 쉬운 마크다운으로 고정.
(선택) 지휘자가 자동 위임하려면 src/agents/<name>.ts에 AgentConfig+metadata를 만들고 definitions.ts 레지스트리·AGENT_CONFIG_KEY_MAP·omcSystemPrompt 카탈로그에 등록.
코드(src/**/*.ts)를 건드렸다면 npm run build. .md만 추가하면 빌드 불필요.
함정 (실제 본 것)
executor.md·base-agent.md가 가리키는 src/agents/preamble.ts의 wrapWithPreamble()는 이 체크아웃에 없다(grep -rl wrapWithPreamble src/ → 0건). 문서와 실제 코드가 어긋남. 재귀 방지는 세 겹으로 동작: (a) 본문 <Constraints>(“Work ALONE”), (b) 위임 시 덧붙이는 워커 프리앰블(skills/team/SKILL.md의 “NEVER spawn sub-agents or use the Task tool”), (c) src/team/worker-bootstrap.ts:246의 워커 규칙.
머리말 level은 코드 어디서도 읽지 않음(AgentConfig 타입에 없음). 순수 문서용.
머리말 name/description/model도 런타임 진실은 src/agents/<name>.ts의 AgentConfig 값. .md에서 런타임이 쓰는 건 본문(prompt)과 disallowedTools뿐.
요약 & 셀프체크
3줄 요약
서브에이전트는 agents/*.md 한 장으로 정의되는 역할 전문가이며, OMC의 핵심 확장점이다.
.md는 명함(머리말)과 업무 대본(본문)으로 나뉘지만, 런타임이 실제 쓰는 건 본문(prompt)과 disallowedTools 한 줄뿐이다.
지휘자가 위임 규칙으로 적임 전문가를 골라 부르며, “혼자 일하기”를 여러 겹으로 박아 재귀 폭발을 막는다.
스스로 답해보기
executor.md의 model: opus를 model: haiku로 고치면 실제 실행 모델이 바뀔까? (힌트: 진짜 출처가 어디인지)