OMC (oh-my-claudecode) · 서브에이전트 (agents/*.md 역할 프롬프트와 위임)
OMC (oh-my-claudecode) · 서브에이전트 (agents/*.md 역할 프롬프트와 위임)
한 줄 요약
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)다. 사원증 직급은 장식이고 실제 권한은 인사 시스템(코드)에 등록된 값으로 돈다.
flowchart LR
MD["('agents/X.md')"]
MD -->|"loadAgentPrompt<br/>머리말 제거"| BODY["본문 prompt 사용됨"]
MD -->|"parseDisallowedTools<br/>정규식"| TOOL["disallowedTools 사용됨"]
MD -.->|런타임 무시| META["name·description·model·level "]
TS["('src/agents/X.ts<br/>AgentConfig')"] -->|진짜 출처| META2["name·description·model "]
5. 무한 복제 막기
전문가가 또 전문가를 끝없이 부르면 작업이 폭발한다(재귀 폭발). OMC는 “혼자 일해라 / 하위 에이전트를 부르지 마라”를 여러 겹으로 박아 막는다.
핵심 정리
명함(frontmatter) 핵심 필드
| 필드 | 필수 | 한 줄 설명 |
|---|---|---|
name | 식별자. 파일명과 일치(executor.md→name: executor) | |
model | (관례) | 두뇌 티어 — haiku=조회, sonnet=표준, opus=설계·심층 |
disallowedTools | 못 쓰는 도구(예: Write, Edit) — 머리말에서 유일하게 실제 파싱됨 |
[!note]- 펼쳐보기: 런타임이
.md에서 실제 쓰는 것 + 전체 필드
- 본문(prompt) —
loadAgentPrompt()가 머리말을 떼고 본문만 가져온다.disallowedTools—parseDisallowedTools()가 정규식으로 머리말에서 이 한 줄만 추출(src/agents/utils.ts:325).name/description/model은 코드(src/agents/<이름>.ts)의AgentConfig값이 진짜 출처.level필드는 어디서도 읽히지 않는 순수 문서용 라벨.description(머리말) — 선택용 한 줄 요약, 끝에 보통(Sonnet)같은 모델 표기.
본문(역할 대본) 주요 태그
핵심 4종: <Role>(책임 + 책임지지 않는 것=역할 경계) · <Success_Criteria>(완료 판정) · <Constraints>(금지·제약) · <Output_Format>(호출자가 파싱할 산출물 형식).
[!note]- 펼쳐보기: 전체 태그 목록
<Role>— 너는 누구다 / 무엇을 책임지고 / 무엇은 책임지지 않는다(역할 경계)<Why_This_Matters>— 규칙이 존재하는 이유(실패 모드)<Success_Criteria>— 완료 판정 기준(체크 가능 항목)<Constraints>— 금지·제약(읽기전용, 최소 diff, 3회 실패 시 에스컬레이션)<Investigation_Protocol>/<Tool_Usage>— 단계별 절차·도구 사용법<Output_Format>— 호출자가 파싱할 산출물 형식(마크다운 템플릿)<Examples>(<Good>/<Bad>) ·<Final_Checklist>— 예시·자체 점검
[!note]- 펼쳐보기: 코드 측 스키마
AgentConfig(src/agents/types.ts:65)
필드 필수 한 줄 설명 name/description식별자 / 선택용 요약 promptloadAgentPrompt(name)로.md본문을 로드tools/disallowedTools허용 도구(생략 시 전부) / 금지 도구 model/metadata모델(기본 sonnet) / 위임 표 자동생성용(cost·triggers·useWhen·avoidWhen)
실제 예시
예시 A — architect 명함 + 역할 대본 (읽기 전용 전문가)
머리말의 disallowedTools: Write, Edit가 유일하게 실제 파싱되는 강제 가드레일이며, 이 한 줄이 architect를 읽기 전용으로 묶는다.
[!note]- 펼쳐보기: architect.md 전문
// /home/seunghyeong/harness-work/oh-my-claudecode/agents/architect.md --- name: architect description: Strategic Architecture & Debugging Advisor (Opus, READ-ONLY) model: opus level: 3 disallowedTools: 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의 제약 (혼자 일하기·최소 변경·에스컬레이션)
[!note]- 펼쳐보기: 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[]"]
[!note]- 펼쳐보기: 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).
[!note]- 펼쳐보기: my-reviewer.md 최소 템플릿 전문
// agents/my-reviewer.md --- name: my-reviewer description: Focused diff reviewer for correctness bugs (Sonnet) model: sonnet level: 2 disallowedTools: 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만 추가하면 빌드 불필요.
[!warning]- 함정 (실제 본 것)
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로 고치면 실제 실행 모델이 바뀔까? (힌트: 진짜 출처가 어디인지)- 새 전문가가 읽기 전용이어야 한다면,
.md에서 어떤 한 줄을 꼭 넣어야 강제될까? - “재귀 폭발”을 OMC는 어떤 세 겹으로 막는가?
연결
[!tip] Codex 교차검증 원본 노트에 별도 Codex 교차검증 섹션은 없었다(보존할 외부 검증 내용 없음). 본문의 모든 사실·파일경로·함정은 기존 분석 노트의 근거를 그대로 유지했다.