지식위키

스킬·커맨드 횡단 — 재사용 가능한 작업 절차를 패키징하는 법

스킬·커맨드 횡단 — 재사용 가능한 작업 절차를 패키징하는 법

한 줄 요약

스킬(skill)·커맨드(command) = “이런 상황에 이렇게 일하라”는 작업 절차를 파일 한 묶음으로 포장해, 필요할 때만 AI 머릿속에 펼쳐 넣는 장치다. 하네스 엔지니어링에서 이건 컨텍스트 예산을 아끼면서 전문 역량을 무한히 확장하는 핵심 메커니즘이라, 7개 프레임워크가 같은 문제를 어떻게 푸는지 보면 “스킬이라는 개념의 존재 이유” 자체가 손에 잡힌다.

그림 — 스킬의 생명주기

40_skills-commands-diagram.svg

스킬은 항상 메뉴판 → 펼침 → 실행의 3박자로 움직인다. 평소엔 이름과 한 줄 설명만 컨텍스트에 올려두고(메뉴판), 매칭되면 본문을 펼치고(disclosure), 그제야 절차를 수행한다.

flowchart TB
    A([세션 시작]) --> B"메뉴판 상주<br/>name + description 만"
    B --> C{"언제 켜지나?"}
    C -->|발화가 설명과 매칭| D[자동 호출]
    C -->|"사용자가 /name 입력"| E[수동 호출]
    C -->|훅이 키워드 강제 주입| F[키워드 트리거]
    D --> G{"본문은 누가 읽나?"}
    E --> G
    F --> G
    G -->|엔진이 메시지로 주입| H["(본문 펼침)"]
    G -->|모델이 Read 도구로 끌어옴| H
    H --> I(["절차 실행 · 인자 치환"])

    classDef menu fill:#e8f0fe,stroke:#1a73e8,color:#0b3d91;
    classDef body fill:#fde2e4,stroke:#c9184a,color:#3a0ca3;
    class B menu
    class H body

[!tip] 세 박자만 기억하면 된다 ① 메뉴판(평소 상주하는 이름+설명) · ② 펼침(매칭되면 본문 로드) · ③ 실행(절차 수행+인자 치환). 7개 프레임워크의 차이는 거의 전부 “②를 누가/어떻게 하느냐”에서 갈린다.

쉽게 풀기

식당 메뉴판을 떠올려 보자.

  • 손님(=AI)이 자리에 앉으면 받는 건 두꺼운 요리책이 아니라 한 장짜리 메뉴판이다. 메뉴판엔 “마라탕 — 얼얼하게 매운 사천식 탕”처럼 이름과 한 줄 설명만 있다. 이게 description이고, 세션 내내 컨텍스트에 떠 있는 부분이다.
  • 손님이 “매운 게 당긴다”고 말하면(=발화가 설명과 매칭), 주방은 그제야 마라탕 레시피 전문을 꺼낸다. 이게 본문(SKILL.md)이 펼쳐지는 순간이다.
  • 레시피 안에 “고급 육수 비법은 부록 3쪽 참고”가 있으면, 필요할 때만 그 부록까지 펼친다. 이게 번들 자료(references/, 스크립트, 에셋)다.

이 “필요할 때만 한 단계씩 펼친다”가 바로 **점진 공개(progressive disclosure)**이고, 스킬이라는 개념이 존재하는 이유다. 수십 개 스킬의 레시피 전문을 항상 손님 테이블에 깔아두면 테이블(=컨텍스트)이 꽉 차버리니까.

여기서 두 갈래의 설계 선택이 생긴다.

  • 메뉴판을 누가 펼치나? 어떤 프레임워크는 *주방장(엔진)*이 알아서 레시피를 손님 앞에 가져다 놓고, 어떤 곳은 *손님(모델)*이 직접 “그 레시피 좀 가져다줘(Read 도구)“라고 해서 가져온다.
  • 메뉴판과 레시피를 한 장에 합칠까, 쪼갤까? 합치면 관리가 단순하고, 쪼개면(얇은 메뉴 한 줄 + 두꺼운 레시피 파일) 메뉴판 자체를 가볍게 유지할 수 있다.

핵심 정리

스킬을 이해하는 네 가지 질문 축으로 정리한다.

질문 축무엇을 보나대표 갈래
형식/스키마무엇으로 정의하나SKILL.md(YAML+본문) 폴더가 7개 공통
생명주기/트리거언제 켜지나자동 매칭 · 수동 /name · 훅 키워드 강제
주입방식어떻게 모델에 들어가나엔진 주입 vs 모델 Read
특이점무엇이 다른가예산 강등 · TS 코드 · MCP 결합 등

[!note] 프레임워크별 한 줄 성격

  • Claude Code — 커맨드를 “단일 파일 스킬”로 통합. 엔진이 3단계 점진 공개(메타/본문/번들)를 직접 수행. 우선순위 enterprise>personal>project, 동명이면 스킬>커맨드.
  • Codex — 카탈로그/본문 2단. 렌더 단계에서 토큰 예산을 알고 3단 강등(풀→글자 단위 공평 축약→설명 제거+우선순위 omit)하는 유일한 결정론 시스템. 경로 길면 alias 테이블 자동 전환.
  • OMC — 얇은 디스패처(commands/, description:"") + 두꺼운 절차(skills/)를 물리 분리해 카탈로그 토큰을 0으로. level(1~7)로 작업 권한 등급화.
  • gajae-code — 독립 런타임(Bun). 마크다운 외에 execute() TS 함수 커맨드 보유. 번들 디폴트 본문을 코드에 임베드해 .gjc 삭제 후에도 생존. skill:// 내부 프로토콜.
  • ouroboros — 한 이름이 command→SKILL→MCP 도구로 3중 선언. ## Required Skill Capabilities 능력 계약으로 Claude/Codex 백엔드 중립.
  • fable-ish — 스킬을 단 1개만 두고 references/로 깊이를 줌. 훅(기계어판)과 스킬(사람어판)이 같은 어휘로 짝맞춤.
  • 내 패턴 — OMC 규약 상속. keyword-detector.mjs가 키워드→[MAGIC KEYWORD] 강제 주입(본문 인라인 X, 경로만). team은 무한 스폰 방지로 자동 트리거 제외.

모두가 수렴한 공통 패턴 (체크리스트로 확인):

  • SKILL.md = 폴더 + YAML frontmatter + 본문. 7개 전부 동일한 물리 형태로 수렴
  • name+description 두 필드가 핵심 (사람·모델이 함께 읽는 단일 진실 소스)
  • 점진 공개가 보편 원리 (평소 설명만, 매칭 시 본문, 상세는 더 깊이)
  • description은 “라우팅 키” — 자동 호출의 매칭 텍스트라 “무엇을+언제”를 사용자 어휘로
  • 본문은 사람 안내문이 아니라 모델에게 주는 명령문(imperative)
  • 인자 치환 문법($ARGUMENTS/$1/$name)이 거의 동일

[!warning] “수렴”이 곧 “동일”은 아니다 — 분기점이 진짜 학습 포인트

  • 카탈로그 예산을 누가 관리하나 — Codex만 렌더 단계 결정론 강등. 나머지는 “설명 짧게 써라” 사람 규율 + OMC식 description:"" 수동 트릭. (Codex가 Rust 코어라 가능, CC/OMC는 호스트 일괄 로드라 “비우기”로 우회)
  • 커맨드+스킬, 합칠까 쪼갤까 — CC는 통합(엔진 레벨 점진 공개), OMC는 분리(파일 레벨 빈 설명). 같은 목표(토큰 절약)를 엔진을 고칠 수 있느냐로 다르게 풂.
  • 본문을 누가 읽나 — 엔진 주입(확실·1회·세션 상주, 단 엔진 제어 필요) vs 모델 Read(플러그인에서 가능, 단 경로 못 찾을 위험 → OMC는 폴백 경로를 디스패처에 박음).
  • TS 코드 커맨드 — gajae만(독립 런타임이라 가능). 나머지는 마크다운(+!shell 전처리).
  • 스킬 개수 철학 — fable 1개(응집·일관) vs OMC 40개(모듈성, 단 카탈로그 관리 비용).

실제 예시

같은 “스킬” 개념이 세 가지 다른 형태로 나타나는 걸 비교하면 설계 철학이 한눈에 보인다.

# Claude Code — 커맨드=스킬 통합, 엔진이 점진 공개
# 공식 표 기준 frontmatter 16필드
# 출처: harness-work/.../skills/skill-development/SKILL.md
# _원문아카이브/claude-code/skills.md:237
---
name: commit-push-pr
description: 변경을 커밋·푸시하고 PR을 연다 (주요 사례를 앞에)
disable-model-invocation: true   # 부작용 작업 → 자동 호출 차단(라우팅 억제)
allowed-tools: [Bash, Read]      # 사전 승인이지 도구 풀 제한이 아님(skills.md:383)
context: fork                    # 본문이 격리 서브에이전트 프롬프트가 됨
---
# 본문은 "지금 수행할 작업 정의"(2인칭 You should 금지, 명령형)
# OMC — 얇은 디스패처 + 두꺼운 절차 (물리 분리로 카탈로그 토큰 0)
# 출처: harness-work/oh-my-claudecode/commands/trace.md
# harness-work/oh-my-claudecode/skills/trace/SKILL.md
commands/trace.md   →  description:""  (카탈로그 부피 0)
                       본문이 모델에 도착 → 모델이 Read 도구로
skills/trace/SKILL.md   ← 두꺼운 절차 전문을 지연 로딩
                          frontmatter: level(1~7), 본문에 pipeline 단계
# ouroboros — 한 이름 3중 선언 + 능력 계약
# 출처: harness-work/ouroboros/{commands/seed.md, skills/seed/SKILL.md,
# .claude-plugin/SKILL_CAPABILITY_GUIDE.md}
# commands/seed.md   → SKILL.md를 Read 하라 지시
# skills/seed/SKILL.md → mcp_tool / mcp_args:$1 로 MCP 도구 직결
# ## Required Skill Capabilities  (능력 토큰 추상화)
# - ask_user      ┐ 런타임별로 capability guide가
# - call_mcp      ┤ Claude / Codex 백엔드에 매핑
# - maintain_ledger ┘ → SKILL.md 한 벌로 양쪽 커버

내 스택(Claude+Codex+OMC)에 차용할 구체안 — 위 분기점에서 뽑은 실전 적용:

  1. Codex의 예산 강등 사고를 OMC 카탈로그 린트로. 스킬 level/사용빈도로 디스패처를 정렬·정리(빌드 타임 린트). description:""는 유지하되 정렬·omit 발상만 차용. (render.rsprompt_scope_rank)
  2. CC의 context:fork+agent를 무거운 OMC 스킬에. trace/research류는 격리 서브에이전트에서 돌리고 요약만 메인 반환. (단 team류 오케스트레이션엔 위험 — forked는 히스토리 못 봄, 계약 명시 필수)
  3. fable-ish의 어휘 짝맞춤을 내 게이트에. Stop 게이트 훅 문구와 SKILL.md ## Workflow같은 단어로 통일 → 라우팅보다 행동 품질에 직접 작용.
  4. ouroboros 능력 토큰을 양쪽 배포 스킬에. ask_user/call_mcp 5~7개 최소 어휘부터 + 런타임별 guide 테스트 동반.
  5. gajae식 RECEIPT-ONLY를 파이프라인 스킬에. 다단계 스킬은 산출물 본문 대신 {path, sha256, stage, schema_version} 영수증만 반환(컨텍스트 중복 제거). 단 최종 사용자 보고까지 영수증만 두면 설명력 부족.
  6. CC의 paths glob 자동로드를 프로젝트 스킬에. *.pptx 작업 시에만 ppt-forge 규약 스킬이 켜지게. (CC 엔진 전용, OMC 디스패처와 병행)
  7. dd의 “첫 액션 캡처” 패턴을 부작용 스킬 표준으로. 디스패처 첫 줄에 결정론 스크립트를 박아 모델 추론 전에 상태 고정. 단 allowed-tools 최소화는 제한이 아니라 승인 최적화 → disallowed-tools/permissions/훅 preflight 병행.

요약 & 셀프체크

  • 스킬은 메뉴판 → 펼침 → 실행 3박자로 움직이며, 그 존재 이유는 점진 공개로 컨텍스트 예산을 아끼는 것이다.
  • 7개가 SKILL.md 폴더 형태·name+description·점진 공개로 수렴했지만, “본문을 누가 읽나(엔진 주입 vs 모델 Read)”·“커맨드를 합칠까 쪼갤까”·“예산을 누가 관리하나”에서 분기한다.
  • 가장 중요한 경계: 스킬은 prompt packaging이고, 실제 권한 차단은 permissions·sandbox·hook gate가 한다 — 라우팅 억제와 권한 경계를 혼동하지 말 것.

[!question] 스스로 답해보기

  1. 같은 “토큰 절약”이라는 목표를 Claude Code와 OMC가 정반대 방식(통합 vs 분리)으로 푼 근본 이유는 무엇인가? (힌트: 엔진을 고칠 수 있는가)
  2. “자동 호출 차단(disable-model-invocation)“은 부작용을 막는가, 아니면 라우팅만 억제하는가? 실제 부작용은 무엇이 막나?
  3. 내가 한 스킬을 Claude와 Codex 양쪽에 배포해야 한다면, 어떤 패턴을 차용하겠는가?

근거

기능노트: CC_40_skills · CC_50_slash-commands · CX_50_skills · OMC_40_skills-and-commands · GJ_30_extension-points-hooks-skills-commands · OB_70_extension-points-hooks-skills-commands · FB_80_skill-workflow-layer · MINE_40_skills-and-slash-commands

소스/문서 경로:

  • 공식문서 아카이브: /mnt/d/6study/10_프레임워크분석/_원문아카이브/claude-code/skills.md, .../slash-commands.md, /mnt/d/6study/10_프레임워크분석/_원문아카이브/codex/83_agent-skills.md
  • Claude Code: /home/seunghyeong/harness-work/claude-code/plugins/plugin-dev/skills/skill-development/SKILL.md, .../command-development/references/frontmatter-reference.md, .claude/commands/commit-push-pr.md, plugins/ralph-wiggum/commands/ralph-loop.md
  • Codex: /home/seunghyeong/harness-work/codex/codex-rs/core-skills/src/{loader,render,skill_instructions,injection}.rs, skills/src/lib.rs, .../samples/skill-creator/SKILL.md
  • OMC: /home/seunghyeong/harness-work/oh-my-claudecode/skills/{team,trace}/SKILL.md, commands/{trace,psm}.md, skills/AGENTS.md, COMPATIBILITY.md
  • gajae-code: packages/coding-agent/src/extensibility/{skills.ts,slash-commands.ts,custom-commands/loader.ts}, internal-urls/skill-protocol.ts, defaults/gjc/skills/ralplan/SKILL.md
  • ouroboros: /home/seunghyeong/harness-work/ouroboros/{commands/seed.md,skills/seed/SKILL.md,.claude-plugin/SKILL_CAPABILITY_GUIDE.md,scripts/keyword-detector.py}
  • fable-ish: /home/seunghyeong/harness-work/fable-ish/skills/fable-ish/{SKILL.md,references/*.md}, scripts/classify_task.py, README.md
  • 내 패턴: /home/seunghyeong/.claude/plugins/marketplaces/omc/skills/{team,wiki}/SKILL.md, templates/hooks/keyword-detector.mjs, .../gptaku-plugins/plugins/dd/{skills/dd/SKILL.md,commands/dd.md}

[!tip] Codex 교차검증 — gpt-5.5(xhigh)가 소스와 대조해 잡아낸 핵심 교정 큰 프레임(“점진 공개, description 라우팅, 얇은 표면/두꺼운 본문”)은 타당. 다만 “호스트 공식 기능 / 플러그인 관례 / 개별 스킬 구현”을 한 층으로 섞은 과잉 일반화가 약점. 본 교재는 아래 교정을 반영했다.

  • 사실 교정: Claude frontmatter는 18필드가 아니라 16필드(skills.md:237). /name은 frontmatter name이 아니라 파일/디렉터리 경로에서 나옴(plugin 루트 SKILL.md만 예외). allowed-tools는 도구 풀 제한이 아니라 사전 승인(skills.md:383). Codex는 description 비어도 MissingField로 실패하지 않고 빈 문자열로 길이만 검증(loader.rs:657). gajae hide는 권한 경계가 아니라 노출/resolver 스킵일 뿐(skill:// 직접 접근은 여전히 됨, skills.ts:13). OMC pipeline/handoff/triggers는 일반 스키마가 아니라 일부 스킬의 관례.
  • 이분법 교정: “엔진 주입 vs 모델 Read”는 깔끔한 이분법이 아님 — Codex는 카탈로그=model-read 지시지만 명시적 $skill 선택은 엔진이 <skill> user fragment로 주입(injection.rs:58). “gajae만 TS 코드”도 표면만 본 것 — 모두 hooks/scripts/MCP라는 코드 실행층 보유, 차이는 “코드가 어느 층이냐”.
  • 최우선 경계: 스킬=prompt packaging / 권한=runtime·permission·hook gate. disable-model-invocation·allow_implicit_invocation:false·hide·team auto 제외는 전부 라우팅 억제이지 부작용 차단이 아님. 실제 차단은 permissions·sandbox·hook gate·runtime policy가 담당.

연결

_분석축_루브릭 · 30_hooks · 50_tools-mcp · HOME