지식위키

OMC (oh-my-claudecode) · 컨텍스트/프롬프트 조립 (CLAUDE.md 주입 + 키워드 감지 + 스킬 인젝션)

OMC (oh-my-claudecode) · 컨텍스트/프롬프트 조립 (CLAUDE.md 주입 + 키워드 감지 + 스킬 인젝션)

한 줄 요약

OMC는 Claude가 보는 텍스트를 파일(CLAUDE.md)·입력 가로채기(키워드 훅)·세션 복원 세 군데에서 조립해, 백지 상태로 시작하는 모델에게 “무엇을 알고 시작할지”를 심는다. 왜 배우나: 키워드 한 단어로 모드가 켜지는 마법의 정체가 이 “프롬프트 조립”이며, 직접 하네스를 만들 때 가장 먼저 베껴야 할 핵심이다.


그림

flowchart TD
  A["설치 1회: omc-setup"] --> B["CLAUDE.md에<br/>OMC:START~END 마커 블록 끼우기"]
  B -. "세션마다 CC가 자동 로드" .-> M["모델 시스템 프롬프트<br/>(항상 켜진 운영 매뉴얼)"]

  S["세션 시작 SessionStart"] --> S1["상태 복원<br/>(ralph·ultrawork·메모리·notepad)"]
  S1 --> AC["additionalContext<br/>(추가 주입 텍스트)"]

  U["사용자 입력 UserPromptSubmit"] --> K["키워드 탐지기"]
  K --> K1["청소: 코드·인용·옛 로그 제거"]
  K1 --> K2{"매직 키워드?"}
  K2 -- "예" --> K3["모드 상태파일 쓰기<br/>+ MAGIC KEYWORD 안내문"]
  K2 -- "아니오" --> K4["그냥 통과"]
  U --> J["스킬 주입기"]
  J --> J1["트리거 매칭 + 점수"]
  J1 --> J2["학습된 스킬 요약 블록"]
  K3 --> AC
  J2 --> AC
  AC --> M
  M --> R["모델 응답:<br/>모드/스킬 실행"]

쉽게 풀기

Claude 본체는 기억이 없는 천재 가정교사다. 매번 새로 출근해 책상 위 종이만 읽고 일을 시작하며, 어제 한 일도 집에 있는 도구도 스스로는 모른다. OMC는 그 가정교사가 출근하기 전에 책상에 종이를 미리 깔아두는 비서다. 종이를 까는 자리가 세 군데다.

flowchart LR
  subgraph 정적["1. 벽 안내문 (설치 1회)"]
    P1["CLAUDE.md 마커 블록"]
  end
  subgraph 동적["2. 현관 쪽지 (매 입력)"]
    P2["키워드 탐지 훅"]
    P3["스킬 주입기"]
  end
  subgraph 복원["3. 어제 일지 (세션 시작)"]
    P4["SessionStart 복원"]
  end
  정적 --> 모델["기억 없는 천재 모델"]
  동적 --> 모델
  복원 --> 모델
  1. 벽에 붙인 상시 안내문 (CLAUDE.md 마커 블록) — 설치 때 딱 한 번, CLAUDE.md<!-- OMC:START --> … <!-- OMC:END --> 주석 테두리 블록을 끼운다. 안에는 직원(에이전트)·연장(도구)·위임 규칙·모델 라우팅이 적혀 있다. Claude Code가 세션마다 CLAUDE.md를 자동 로드하므로 이 안내문은 항상 걸려 있는 운영 매뉴얼이 된다. 따로 주입 코드를 돌릴 필요 없이 파일에 박아두면 끝.

  2. 현관에서 쪽지 끼우기 (키워드 훅, 매 입력) — 사용자가 문장을 칠 때마다 UserPromptSubmit 훅이 먼저 가로챈다. ralph·autopilot·ultrawork·ccg 같은 매직 키워드가 보이면 “이 모드를 시작하라”는 쪽지를 끼워준다(keyword-detector.mjs). 동시에 입력과 관련 있는 “학습된 스킬” 요약도 함께 끼운다(skill-injector.mjs).

  3. 출근 직후 어제 일지 복원 (SessionStart) — 새 세션이 시작되면 프로젝트 메모리·위키·notepad 우선순위 메모·중단됐던 모드 상태(ralph 루프 등)를 다시 책상에 올린다(session-start.mjs / wiki-session-start.mjs).

핵심 비유: 모델은 추론기, OMC는 그 앞에 종이를 까는 담당자. 마법 같은 자동화는 전부 “어떤 종이를 깔았느냐”의 결과다.

[!note] 가로챈 쪽지를 모델이 왜 따를까? 훅이 끼운 텍스트는 모델에게 “시스템이 준 추가 지시문”으로 보인다. 사용자 글인지 비서 쪽지인지 구분 못 하고 한 덩어리로 읽기 때문에, 키워드 한 단어가 모드를 켠다.


핵심 정리

조립이 일어나는 세 자리

자리시점누가
CLAUDE.md 마커 블록설치 1회 (정적)installer
키워드·스킬 쪽지매 입력 (동적)keyword-detector / skill-injector
세션 복원세션 시작마다session-start / wiki-session-start

마커 블록 안의 주요 섹션

섹션 태그한 줄 역할
OMC:VERSION설치 버전(드리프트 감지)
<operating_principles>위임·증거우선·최소경로 원칙
<delegation_rules>위임 vs 직접 판단
<model_routing>haiku·sonnet·opus 배분
<agent_catalog>에이전트 + 기본 모델
<tools> / <skills>도구 목록 / 키워드→스킬 매핑

[!note]- 펼쳐보기: 선택 섹션(필수 아님)

  • <hooks_and_context> — system-reminder 패턴 + 킬스위치 DISABLE_OMC/OMC_SKIP_HOOKS 설명
  • <commit_protocol> — 커밋 트레일러 규약
  • <worktree_paths>.omc/ 상태 경로 해석 있으면 좋지만 없어도 동작한다.

키워드 → 모드 매핑 (요지)

상태파일까지 만드는 스킬형과 텍스트만 끼우는 모드형으로 갈린다.

flowchart TD
  IN["입력 키워드"] --> Q{"sanitize 후<br/>매칭 + 정보성 질문?"}
  Q -- "정보성('ralph가 뭐야?')" --> SKIP["모드 안 켬"]
  Q -- "스킬형" --> SF["상태파일 + 안내문<br/>ralph·autopilot·ultrawork·ultragoal·ralplan"]
  Q -- "모드형" --> MF["텍스트만<br/>ccg·deep-interview·tdd·review·wiki…"]
  SF -. "ralph는 동반" .-> UW["ultrawork 상태파일도 생성"]
  • ralph / don't stop / until done / 랄프(로렌 제외) → ralph (상태파일 , ultrawork 동반)
  • autopilot / full auto / 오토파일럿autopilot (상태파일 )
  • ultrawork / ulw / uwultrawork (상태파일 )
  • ultragoal / ralplan → 각각 상태파일 (명시 호출 의도 요구)
  • ccg / deep interview / tdd / code review / ultrathink / wiki 등 → 텍스트 모드만 (상태파일 )

[!note]- 펼쳐보기: 추측 아닌 실코드 안전장치

  • team은 자동감지에서 제거 — 워커가 “team”을 보고 또 team을 스폰하는 무한 루프 방지. /team으로만 명시 호출.
  • 정보성 질문(“ralph가 뭐야?“)은 isInformationalKeywordContext로 걸러 모드를 안 켠다.
  • 과거 훅 출력([RALPH LOOP - ITERATION N])을 붙여넣어도 stripSystemEchoes로 제거 → 자기강화 루프 차단.
  • Ralph Lauren(랄프)(?!로렌) 부정전방탐색으로 제외.

스킬 인젝션 예산 (토큰 폭발 방지)

제한의미
디스크립터 1개최대 1000자본문은 디스크, 요약만
전체 컨텍스트최대 3000자한 입력 총량
세션당 개수최대 5개초과분은 미주입
재주입 방지세션 1시간 TTLdedup

실제 예시

A. 설치 시 박히는 CLAUDE.md 마커 블록

<!-- OMC:START -->
<!-- OMC:VERSION:4.9.1 -->
# oh-my-claudecode - Intelligent Multi-Agent Orchestration
...
<skills>
Keyword triggers: "autopilot"→autopilot, "ralph"→ralph, "ulw"→ultrawork, ...
</skills>
<!-- OMC:END -->

[!note]- 펼쳐보기: 마커 블록 전문 발췌 + 설치 래퍼 코드

<!-- /home/seunghyeong/harness-work/oh-my-claudecode/CLAUDE.md -->
<!-- OMC:START -->
<!-- OMC:VERSION:4.9.1 -->

# oh-my-claudecode - Intelligent Multi-Agent Orchestration
...
<agent_catalog>
Prefix: `oh-my-claudecode:`. See `agents/*.md` for full prompts.

explore (haiku), analyst (opus), planner (opus), architect (opus), debugger (sonnet),
executor (sonnet), verifier (sonnet), tracer (sonnet), security-reviewer (sonnet),
code-reviewer (opus), test-engineer (sonnet), designer (sonnet), writer (haiku), ...
</agent_catalog>

<skills>
Keyword triggers: "autopilot"→autopilot, "ralph"→ralph, "ulw"→ultrawork, "ccg"→ccg,
"ralplan"→ralplan, "deep interview"→deep-interview, ...
</skills>
<!-- OMC:END -->

설치 코드 — 기존 블록만 교체하고 마커 밖 사용자 본문은 보존:

// src/installer/index.ts
const START_MARKER = '<!-- OMC:START -->';
const END_MARKER = '<!-- OMC:END -->';
const versionMarker = version ? `<!-- OMC:VERSION:${version} -->\n` : '';
// 기존 사용자 본문이 없을 때:
return `${START_MARKER}\n${versionMarker}${cleanOmcContent}\n${END_MARKER}\n`;
// 사용자 본문이 있을 때는 마커 블록 + 빈 줄 + USER_CUSTOMIZATIONS + 사용자 본문 보존

B. 키워드 매칭 후 끼워지는 안내문 (본문이 아니라 “경로 + 안내”만)

핵심은 스킬 본문을 인라인하지 않고 경로만 가리킨다는 점이다. 흐름은 아래와 같다.

sequenceDiagram
  participant U as 사용자
  participant H as keyword-detector
  participant CC as Claude Code
  participant M as 모델
  U->>H: 입력 ("ralph 시작")
  H->>H: sanitize → 키워드 매칭
  H->>H: 모드 상태파일 atomic write
  H-->>CC: additionalContext (경로+안내, 본문 X)
  CC->>M: 원문 + 주입텍스트 병합
  M->>M: SKILL.md 읽어 워크플로 시작

[!note]- 펼쳐보기: 실제 MAGIC KEYWORD 안내문 출력

// scripts/keyword-detector.mjs — createSkillInvocation()
`[MAGIC KEYWORD: ${skillName.toUpperCase()}]

Skill routing detected: ${skillName}
Preferred invocation: /oh-my-claudecode:${skillName}
Read fallback: open ${skillPath} and follow its SKILL.md instructions.

User request (compact echo; original prompt remains authoritative):
${compactHookText(originalPrompt)}

IMPORTANT: Start the ${skillName} workflow immediately. ...`

C. 학습된 스킬 frontmatter + 주입 형식

# skills/wiki/SKILL.md
name: wiki
triggers: ["wiki", "wiki this", "wiki add", "wiki lint", "wiki query"]

[!note]- 펼쳐보기: formatSkillsMessage 주입 형식 (본문은 디스크, 요약만)

<mnemosyne>
## Relevant Learned Skills
Compact descriptors only; full learned skill bodies stay on disk to avoid prompt bloat.

### <name> (<scope>)
<skill-metadata>{"path":"...","triggers":[...],"score":10,"scope":"project"}</skill-metadata>
Summary: ...
Load instructions: if this skill is needed, read <path> and follow the full instructions there.
</mnemosyne>

D. 훅이 stdout으로 돌려주는 JSON (모델이 소비하는 핵심)

{ "continue": true,
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "<주입할 텍스트>"
  } }

[!warning] message가 아니라 반드시 hookSpecificOutput.additionalContext 여야 모델이 받는다(코드 주석에 명시). Claude Code가 이 값을 모델 컨텍스트에 추가한다.

E. 직접 만들 때 최소 키워드 훅

// myharness/scripts/keyword-hook.mjs
#!/usr/bin/env node
import { readFileSync } from 'fs';
const input = readFileSync(0, 'utf-8');           // stdin
let data = {}; try { data = JSON.parse(input); } catch {}
const prompt = (data.prompt || '').toLowerCase();

// echo/코드블록 제거(false positive 방지)
const clean = prompt.replace(/```[\s\S]*?```/g, '').replace(/`[^`]+`/g, '');

const MAP = [
  [/\b(loop|don't stop|until done)\b/, 'ralph'],
  [/\b(auto|autopilot)\b/, 'autopilot'],
];
let hit = null;
for (const [re, name] of MAP) if (re.test(clean)) { hit = name; break; }

if (!hit) { console.log(JSON.stringify({ continue: true, suppressOutput: true })); process.exit(0); }

console.log(JSON.stringify({
  continue: true,
  hookSpecificOutput: {
    hookEventName: 'UserPromptSubmit',
    additionalContext:
`[MAGIC KEYWORD: ${hit.toUpperCase()}]
Preferred invocation: /myharness:${hit}
Read fallback: skills/${hit}/SKILL.md
IMPORTANT: start the ${hit} workflow immediately.`
  }
}));

[!tip] 모드 상태파일이라는 부수효과 키워드가 매칭되면 텍스트만 넣는 게 아니라 <omcRoot>/state/sessions/<sid>/<mode>-state.json을 atomic write 한다. 예: ralph는 {active, iteration, max_iterations:100, prompt, session_id, linked_ultrawork:true, awaiting_confirmation:true}. 이 파일을 Stop 훅(persistent-mode.mjs)이 읽어 루프 강제에, SessionStart가 읽어 모드 복원에 쓴다. 그래서 ralph 키워드는 ultrawork 상태파일도 같이 만든다.

직접 만들 때 체크리스트

  • 마커 래퍼는 START/END + VERSION 3줄, 교체 시 사용자 본문 보존(^START\r?\n[\s\S]*?^END).
  • 키워드 훅은 stdin JSON 읽고 hookSpecificOutput.additionalContext로만 반환(message 아님).
  • 정보성 질문/코드블록/과거 echo는 sanitize 후 매칭(자기강화 루프 방지).
  • 자동 스폰 위험 키워드(team류)는 자동감지에서 빼고 슬래시 전용으로.
  • 스킬 본문 인라인 금지, “경로 + 요약”만(세션당 개수/문자 예산 둘 것).
  • 모드 상태는 session-scoped JSON atomic write, SessionStart에서 복원.
  • 훅 실패는 항상 {continue:true} fail-open.
  • 킬스위치 env(DISABLE_OMC, OMC_SKIP_HOOKS=keyword-detector) 존중.

요약 & 셀프체크

3줄 요약

  1. 모델은 백지 천재, OMC는 그 앞에 종이를 까는 비서 — CLAUDE.md(상시)·키워드 훅(매 입력)·세션 복원(시작) 세 자리에서 텍스트를 조립한다.
  2. CLAUDE.md 마커 블록은 자동 로드되고, 키워드·스킬은 훅이 additionalContext로 끼우되 본문이 아니라 “경로 + 요약”만 넣어 토큰을 아낀다.
  3. 무한 루프·자기강화·오탐을 막는 안전장치(team 제외, 정보성 질문 필터, echo 제거, 예산 제한)가 핵심 노하우다.

스스로 답해보기

  • Q1. 키워드 한 단어가 모드를 켤 수 있는 이유는? (힌트: 모델이 사용자 글과 훅 쪽지를 어떻게 구분하나)
  • Q2. 스킬 본문을 통째로 안 넣고 “경로 + 요약”만 넣는 이유 두 가지는?
  • Q3. “ralph”는 상태파일을 만드는데 “tdd”는 안 만든다. 왜 차이가 날까?

연결

OMC_개요 · OMC_10_entrypoint-hooks-loop · _분석축_루브릭


근거 파일

[!note]- 펼쳐보기: 근거 파일 전체 목록

  • CLAUDE.md — 마커 블록 실물(VERSION 4.9.1, 모든 섹션 태그)
  • scripts/keyword-detector.mjs — 키워드→모드 매핑, sanitize, 상태파일 생성, MAGIC KEYWORD 출력
  • scripts/skill-injector.mjs — frontmatter triggers 매칭, mnemosyne 디스크립터, 예산/dedup
  • scripts/session-start.mjs — SessionStart 컨텍스트 조립(상태복원/project-memory/notepad/예산)
  • scripts/wiki-session-start.mjs — 위키 컨텍스트 주입
  • scripts/pre-compact.mjs — 압축 처리(dist/hooks/pre-compact 위임)
  • src/agents/prompt-helpers.ts — 외부모델 위임 시 system_prompt/파일컨텍스트 조립·sanitize
  • src/installer/index.ts — START/END/VERSION 마커 래퍼 생성(L1804~1860)
  • hooks/hooks.json — 훅 이벤트 배선(UserPromptSubmit/SessionStart/PreCompact 순서)
  • skills/wiki/SKILL.md — 스킬 frontmatter(triggers) 실측
  • .mcp.json — MCP 서버 t 등록(bridge/mcp-server.cjs) (경로 prefix: /home/seunghyeong/harness-work/oh-my-claudecode/)

[!tip] Codex 교차검증 별도 Codex 교차검증 기록은 없다. 핵심 사실(마커 블록 자동 로드, additionalContext 필드 필수, team 자동감지 제외, 스킬 예산 제한, ralph→ultrawork 동반 상태파일)은 모두 위 근거 파일의 실코드/실측에 근거하며 추측으로 변경하지 않았다. 추후 교차검증 결과는 이 콜아웃에 누적한다.