์‹œ๋ฆฌ์ฆˆ: oh-my-codex ์•„ํ‚คํ…์ฒ˜ ํ•ด๋ถ€

์ด ์‹œ๋ฆฌ์ฆˆ๋Š” OpenAI Codex CLI ํ™•์žฅ ๋Ÿฐํƒ€์ž„์ธ oh-my-codex(OMX)์˜ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๋‹จ๊ณ„๋ณ„๋กœ ํ•ด๋ถ€ํ•˜๋Š” ๊ณผ์ •์ด๋‹ค.

ํŽธ๋‚ด์šฉํ•ต์‹ฌ
0ํŽธOverview3-Plane ์•„ํ‚คํ…์ฒ˜, OMC์™€์˜ ์ฐจ์ด, ์ „์ฒด ํ๋ฆ„
1ํŽธCodex CLI FoundationCodex CLI ์ž์ฒด์˜ ๊ตฌ์กฐ์™€ ํ™•์žฅ ํฌ์ธํŠธ
2ํŽธOMX IntegrationOMX๊ฐ€ Codex์— ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐ๋˜๋‚˜
3ํŽธ (๋ณธ๋ฌธ)Skill System์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ์–ด๋–ป๊ฒŒ ์ •์˜ํ•˜๋‚˜
4ํŽธPrompt & Agent System์—์ด์ „ํŠธ๋Š” ๋ญ๊ณ  ์–ด๋–ป๊ฒŒ ์„ ํƒ๋˜๋‚˜
5ํŽธMCP Servers์–ด๋–ค MCP ๋„๊ตฌ๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋‚˜
6ํŽธState & Lifecycle์ƒํƒœ๋ฅผ ์–ด๋–ป๊ฒŒ ์œ ์ง€ํ•˜๋‚˜
7ํŽธTeam OrchestrationTeam ๋ชจ๋“œ๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋‚˜
8ํŽธNative & SparkRust ๋„ค์ดํ‹ฐ๋ธŒ ๋„๊ตฌ๋Š” ๋ญ”๊ฐ€

  • Skill์€ Codex CLI์— ์ฃผ์ž…๋˜๋Š” ๋งˆํฌ๋‹ค์šด ๊ธฐ๋ฐ˜ ํ–‰๋™ ์ง€์นจ์„œ (์ฝ”๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ ํ”„๋กฌํ”„ํŠธ)
  • SKILL.md ํŒŒ์ผ๋กœ ์ •์˜๋˜๋ฉฐ, XML ํƒœ๊ทธ ์„น์…˜(Purpose, Steps, Execution_Policy ๋“ฑ)์œผ๋กœ ๊ตฌ์กฐํ™”๋œ ์›Œํฌํ”Œ๋กœ์šฐ ์ •์˜ ๋‹จ์œ„
  • $name ํ‚ค์›Œ๋“œ ๋˜๋Š” AGENTS.md์˜ ํ‚ค์›Œ๋“œ ๋งค์นญ์œผ๋กœ ํŠธ๋ฆฌ๊ฑฐ๋˜๋Š” Codex์˜ ํ–‰๋™ ๋ชจ๋“œ
  • ์„ค์น˜ ๊ฒฝ๋กœ: ./.agents/skills/name/SKILL.md(ํ”„๋กœ์ ํŠธ) ๋˜๋Š” ~/.agents/skills/name/SKILL.md(์ „์—ญ)

ํ•ด๋‹น ๊ฐœ๋…์ด ํ•„์š”ํ•œ ์ด์œ 

  • 2ํŽธ์—์„œ AGENTS.md๊ฐ€ ํ‚ค์›Œ๋“œ๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ $ultrawork Skill์„ ์‹คํ–‰ํ•˜๋ผ๊ณ  Codex์—๊ฒŒ ์ง€์‹œํ•˜๋Š” ํ๋ฆ„์„ ์ดํ•ดํ–ˆ์Œ
  • ํ•˜์ง€๋งŒ โ€œultrawork ๋ชจ๋“œ์—์„œ Codex๊ฐ€ ๊ตฌ์ฒด์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ํ–‰๋™ํ•ด์•ผ ํ•˜๋Š”์ง€โ€์˜ ์ •์˜๊ฐ€ ๋น ์ ธ ์žˆ์Œ
  • Skill์ด ์ด ์—ญํ• ์„ ํ•œ๋‹ค โ€” AGENTS.md๊ฐ€ โ€œ๋ฌด์—‡์„ ์‹คํ–‰ํ• ์ง€โ€ ๊ฒฐ์ •ํ•˜๋ฉด, SKILL.md๊ฐ€ โ€œ์–ด๋–ป๊ฒŒ ์‹คํ–‰ํ• ์ง€โ€ ์ •์˜

AS-IS (OMC Skill โ€” Claude Code ๋ฐฉ์‹)

sequenceDiagram
    autonumber
    participant CC as Claude Code
    participant ST as Skill Tool
    participant SM as SKILL.md

    CC->>ST: Skill("omc:ultrawork") ํ˜ธ์ถœ
    ST->>SM: plugins/omc/skills/ultrawork/SKILL.md ๋กœ๋“œ
    SM-->>ST: ๋งˆํฌ๋‹ค์šด ๋‚ด์šฉ ๋ฐ˜ํ™˜
    ST-->>CC: ํ”„๋กฌํ”„ํŠธ๋กœ ์ฃผ์ž…
    Note over CC: Skill Tool์ด ์ค‘๊ฐœ์ž ์—ญํ•  (ํ”„๋กœ๊ทธ๋ž˜๋ฐ์  ๋กœ๋“œ)

TO-BE (OMX Skill โ€” Codex CLI ๋ฐฉ์‹)

sequenceDiagram
    autonumber
    participant CX as Codex CLI (LLM)
    participant AM as AGENTS.md
    participant SM as skills/ultrawork/SKILL.md

    CX->>AM: ์„ธ์…˜ ์‹œ์ž‘ ์‹œ ์ง€์นจ ๋กœ๋“œ
    AM-->>CX: "$ultrawork โ†’ SKILL.md๋ฅผ ์ฝ์–ด๋ผ" ์ง€์‹œ
    CX->>SM: LLM์ด ์ง์ ‘ SKILL.md ํŒŒ์ผ ์ฝ๊ธฐ
    SM-->>CX: ๋งˆํฌ๋‹ค์šด ๋‚ด์šฉ์„ context์— ๋กœ๋“œ
    CX->>CX: SKILL.md ์ง€์นจ์— ๋”ฐ๋ผ ํ–‰๋™ ์ˆ˜ํ–‰
    Note over CX: ์ค‘๊ฐœ์ž ์—†์Œ โ€” LLM์ด ์ง์ ‘ ํŒŒ์ผ ์ฝ๊ธฐ (ํ™•๋ฅ ๋ก ์ )

SKILL.md Anatomy โ€” XML ํƒœ๊ทธ ๊ตฌ์กฐ

๋ชจ๋“  SKILL.md๋Š” YAML ํ”„๋ŸฐํŠธ๋งคํ„ฐ + XML ํƒœ๊ทธ ์„น์…˜์œผ๋กœ ๊ตฌ์„ฑ๋œ๋‹ค. XML ํƒœ๊ทธ๋Š” LLM์ด ๊ตฌ์กฐ๋ฅผ ๋ช…ํ™•ํžˆ ํŒŒ์‹ฑํ•˜๋„๋ก ๋•๋Š” ํ”„๋กฌํ”„ํŠธ ์—”์ง€๋‹ˆ์–ด๋ง ํŒจํ„ด์ด๋‹ค.

ํ‘œ์ค€ ๊ตฌ์กฐ

---
name: skill-name
description: Short description
---
 
<Purpose>           # ์ด ์Šคํ‚ฌ์ด ๋ฌด์—‡์„ ํ•˜๊ณ  ์™œ ์กด์žฌํ•˜๋Š”๊ฐ€
<Use_When>          # ์ด ์Šคํ‚ฌ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ (ํ‚ค์›Œ๋“œ ํฌํ•จ)
<Do_Not_Use_When>   # ๋‹ค๋ฅธ ์Šคํ‚ฌ์„ ์จ์•ผ ํ•˜๋Š” ์ƒํ™ฉ (๋Œ€์•ˆ ๋ช…์‹œ)
<Why_This_Exists>   # ์ด ๋ชจ๋“œ๊ฐ€ ํ•„์š”ํ•œ ๋™๊ธฐ
<Execution_Policy>  # ์‹คํ–‰ ์ œ์•ฝ๊ณผ ๋„๊ตฌ ์‚ฌ์šฉ ์ •์ฑ…
<Steps>             # ๋‹จ๊ณ„๋ณ„ ์‹คํ–‰ ์ ˆ์ฐจ
<Tool_Usage>        # MCP/๋„๊ตฌ ํ˜ธ์ถœ ๊ณ„์•ฝ
<Escalation_And_Stop_Conditions>  # ์—์Šค์ปฌ๋ ˆ์ด์…˜ยท์ค‘๋‹จ ์กฐ๊ฑด
<Final_Checklist>   # ์™„๋ฃŒ ์ „ ์ฒดํฌ๋ฆฌ์ŠคํŠธ
<Advanced>          # (์„ ํƒ) ์‹ฌํ™” ๋‚ด์šฉ

OMC SKILL.md์™€์˜ ๊ตฌ์กฐ ๋น„๊ต

ํ•ญ๋ชฉOMCOMX
ํ˜ธ์ถœ ๋ฐฉ์‹Skill("omc:name") tool$name ํ‚ค์›Œ๋“œ / ์ง์ ‘ ํŒŒ์ผ ์ฝ๊ธฐ
๋กœ๋“œ ๋ฉ”์ปค๋‹ˆ์ฆ˜Skill tool โ†’ SKILL.md ๋กœ๋“œ (ํ”„๋กœ๊ทธ๋ž˜๋ฐ์ )Codex LLM์ด ํŒŒ์ผ ์ง์ ‘ ์ฝ๊ธฐ (ํ™•๋ฅ ๋ก ์ )
์„ค์น˜ ์œ„์น˜ํ”Œ๋Ÿฌ๊ทธ์ธ ๋‚ด skills/.agents/skills/
Skill ์ˆ˜29๊ฐœ36๊ฐœ
XML ํƒœ๊ทธ ํŒจํ„ด๊ฑฐ์˜ ๋™์ผ๊ฑฐ์˜ ๋™์ผ
์ƒˆ Skill ์ข…๋ฅ˜โ€”deep-interview, ralplan, visual-verdict, web-clone, ecomode, ai-slop-cleaner

๊ตฌ์กฐ๋Š” ๊ฑฐ์˜ ๋™์ผํ•˜๋‹ค. OMC์˜ ์„ค๊ณ„๋ฅผ OMX๊ฐ€ ๊ณ„์Šนํ•˜๋ฉด์„œ, Codex CLI ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ๋กœ๋“œ ๋ฉ”์ปค๋‹ˆ์ฆ˜๋งŒ ๋ณ€๊ฒฝ(Skill tool โ†’ LLM ์ง์ ‘ ์ฝ๊ธฐ)ํ•œ ๊ฒƒ์ด๋‹ค.

36๊ฐœ Skill ๋ถ„๋ฅ˜

์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ Skill (ํ•ต์‹ฌ)

Skill์—ญํ• ํ‚ค์›Œ๋“œ ํŠธ๋ฆฌ๊ฑฐ
teamN worker ๋ณ‘๋ ฌ ์กฐ์œจ (tmux ๊ธฐ๋ฐ˜)team, swarm, coordinated team
autopilot์ „์ฒด ์ž๋™ํ™” ํŒŒ์ดํ”„๋ผ์ธ (Layer 3)autopilot, build me, I want a
ralph๊ฒ€์ฆ ๋ฃจํ”„ โ€” ์™„๋ฃŒ๊นŒ์ง€ ๋ฐ˜๋ณต (Layer 2)ralph, don't stop, must complete, keep going
ultrawork๋‹จ์ˆœ ๋ณ‘๋ ฌ ์‹คํ–‰ (Layer 1)ultrawork, ulw, parallel
ultraqaQA ์‚ฌ์ดํดultraqa
ralplanํ•ฉ์˜ ๊ธฐ๋ฐ˜ ๊ณ„ํš (planner + architect + critic)ralplan, consensus plan
cancelํ™œ์„ฑ ๋ชจ๋“œ ์ทจ์†Œcancel, stop, abort

๋ถ„์„/๋ฆฌ๋ทฐ Skill

Skill์—ญํ• ํ‚ค์›Œ๋“œ ํŠธ๋ฆฌ๊ฑฐ
plan๊ตฌ์กฐํ™”๋œ ์ž‘์—… ๊ณ„ํšplan this, plan the, let's plan
deep-interview์†Œํฌ๋ผํ…Œ์Šค์‹ ์š”๊ตฌ์‚ฌํ•ญ ์ธํ„ฐ๋ทฐ (Ouroboros)interview, deep interview, ouroboros, don't assume
analyze์‹ฌ์ธต ๋ถ„์„analyze, investigate
deepsearch๊นŠ์€ ์ €์žฅ์†Œ ๋ถ„์„(๋ช…์‹œ์  ํ˜ธ์ถœ)
code-review์ฝ”๋“œ ๋ฆฌ๋ทฐ ์›Œํฌํ”Œ๋กœ์šฐcode review, review code
security-review๋ณด์•ˆ ๊ฐ์‚ฌsecurity review
frontend-ui-uxUI/UX ํ‰๊ฐ€(๋ช…์‹œ์  ํ˜ธ์ถœ)

์œ ํ‹ธ๋ฆฌํ‹ฐ Skill

Skill์—ญํ• 
doctor์„ค์น˜ ์ƒํƒœ ์ง„๋‹จ
omx-setup์ดˆ๊ธฐ ์„ค์ •
hud์ƒํƒœ ๋Œ€์‹œ๋ณด๋“œ
note๋ฉ”๋ชจ
trace์‹คํ–‰ ์ถ”์ 
build-fix๋นŒ๋“œ ์‹คํŒจ ๋ณต๊ตฌ (fix build, type errors)
tddTDD ์›Œํฌํ”Œ๋กœ์šฐ (tdd, test first)
git-masterGit ์ž‘์—…
pipeline๋นŒ๋“œ ํŒŒ์ดํ”„๋ผ์ธ
ai-slop-cleaner์ฝ”๋“œ ์ •๋ฆฌ/๋ฆฌํŒฉํ„ฐ (cleanup, refactor, deslop)
ecomodeํ† ํฐ ์ ˆ์•ฝ ๋ชจ๋“œ (ecomode, eco, budget)
help๋„์›€๋ง
skill์Šคํ‚ฌ ๋ชฉ๋ก ์กฐํšŒ

ํŠน์ˆ˜ Skill

Skill์—ญํ• 
visual-verdict๋น„์ฃผ์–ผ QA โ€” ์Šคํฌ๋ฆฐ์ƒท ๋น„๊ต, ๊ตฌ์กฐํ™” JSON ์ถœ๋ ฅ
ask-claudeClaude์—๊ฒŒ ์งˆ๋ฌธ
ask-geminiGemini์—๊ฒŒ ์งˆ๋ฌธ
web-clone์›น์‚ฌ์ดํŠธ ๋ณต์ œ ํŒŒ์ดํ”„๋ผ์ธ โ€” Playwright ๊ธฐ๋ฐ˜ ๋ธŒ๋ผ์šฐ์ € ์ž๋™ํ™” (web-clone, clone site)
configure-notifications์•Œ๋ฆผ ๊ฒŒ์ดํŠธ์›จ์ด ์„ค์ •
workerTeam Worker ์ „์šฉ (team ๋ชจ๋“œ์—์„œ๋งŒ ์‚ฌ์šฉ)
swarmteam์˜ ํ˜ธํ™˜ ๋ณ„์นญ
ralph-initRalph ์ดˆ๊ธฐํ™” ์ „์šฉ
review๋ฒ”์šฉ ๋ฆฌ๋ทฐ

Keyword โ†’ Skill Mapping โ€” ํ‚ค์›Œ๋“œ ๊ฐ์ง€ ๋ฉ”์ปค๋‹ˆ์ฆ˜

2ํŽธ์—์„œ โ€œAGENTS.md ๋‚ด ํ‚ค์›Œ๋“œ ํ…Œ์ด๋ธ”์ด 1์ฐจ ๊ฐ์ง€๋ฅผ ๋‹ด๋‹นํ•˜๊ณ , keyword-detector.ts๊ฐ€ ์ƒํƒœ ์ถ”์ ์šฉ 2์ฐจ ๋ณด์กฐโ€๋ผ๋Š” ๊ตฌ์กฐ๋ฅผ ๋ฐฐ์› ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” keyword-registry.ts์˜ ์šฐ์„ ์ˆœ์œ„ ์ฒด๊ณ„์™€ ์ถฉ๋Œ ํ•ด๊ฒฐ ๋กœ์ง์„ ๊นŠ์ด ๋‹ค๋ฃฌ๋‹ค.

์šฐ์„ ์ˆœ์œ„ ์ฒด๊ณ„ (์†Œ์Šค: src/hooks/keyword-registry.ts)

keyword-registry.ts๋Š” 39๊ฐœ ํ‚ค์›Œ๋“œ ํŠธ๋ฆฌ๊ฑฐ๋ฅผ { keyword, skill, priority, guidance } ํ˜•ํƒœ๋กœ ์ •์˜ํ•œ๋‹ค. ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’์„์ˆ˜๋ก ๋จผ์ € ๋งค์นญ๋œ๋‹ค.

์šฐ์„ ์ˆœ์œ„Skillํ‚ค์›Œ๋“œ ์˜ˆ์‹œ
11ralplanralplan, consensus plan
10autopilot, ultraworkautopilot, build me, ultrawork, parallel
9ralphralph, don't stop, must complete
8deep-interview, plan, team, ultraqainterview, team, swarm
7analyzeanalyze, investigate
6tdd, build-fix, code-review, security-reviewtdd, fix build, code review
5cancelcancel, stop, abort

์ถฉ๋Œ ํ•ด๊ฒฐ (์†Œ์Šค: compareKeywordMatches)

์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ์—ฌ๋Ÿฌ ํ‚ค์›Œ๋“œ๊ฐ€ ๋™์‹œ์— ๋งค์นญ๋˜๋ฉด, ์ •๋ ฌ ๋น„๊ต ํ•จ์ˆ˜ ํ•˜๋‚˜๋กœ ํ•ด๊ฒฐํ•œ๋‹ค:

// src/hooks/keyword-registry.ts
export function compareKeywordMatches(
  a: { priority: number; keyword: string },
  b: { priority: number; keyword: string },
): number {
  if (b.priority !== a.priority) return b.priority - a.priority;     // 1. ๋†’์€ priority ์Šน๋ฆฌ
  if (b.keyword.length !== a.keyword.length) return b.keyword.length - a.keyword.length; // 2. ๊ธด ํ‚ค์›Œ๋“œ ์Šน๋ฆฌ
  return a.keyword.localeCompare(b.keyword);                          // 3. ์•ŒํŒŒ๋ฒณ ์ˆœ
}

Array.sort(compareKeywordMatches) ํ•œ ๋ฒˆ์ด๋ฉด ์ตœ์šฐ์„  ๋งค์นญ์ด [0]์— ์˜จ๋‹ค. ๊ตฌํ˜„์ด ๋‹จ์ˆœํ•œ ์ด์œ ๋Š” ๋ณต์žกํ•œ ๋กœ์ง์„ priority ์ˆซ์ž์— ๋ฏธ๋ฆฌ ์ธ์ฝ”๋”ฉํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๊ฐ์ง€ ๊ณ„์ธต โ€” Explicit vs Implicit

graph TD
    UI["์‚ฌ์šฉ์ž ์ž…๋ ฅ: '$ralph refactor the API, use parallel'"]

    UI --> E["1์ฐจ: Explicit ๊ฐ์ง€ โ€” '$ralph'"]
    UI --> I["2์ฐจ: Implicit ๊ฐ์ง€ โ€” 'parallel' (ultrawork)"]

    E --> D["์ค‘๋ณต ์ œ๊ฑฐ: ์Šคํ‚ฌ๋‹น ์ฒซ ๋งค์นญ๋งŒ ์œ ์ง€"]
    I --> D

    D --> R["๊ฒฐ๊ณผ: ralph (explicit, ์šฐ์„ ), ultrawork (implicit)"]

    style E fill:#e8f0fe
    style I fill:#fef7e0
  • Explicit ($skill): ์ขŒโ†’์šฐ ์ˆœ์„œ๋Œ€๋กœ ๊ฐ์ง€, implicit๋ณด๋‹ค ํ•ญ์ƒ ์šฐ์„ 
  • Implicit (ํ‚ค์›Œ๋“œ ๋งค์นญ): priority/length/alphabetical๋กœ ์ •๋ ฌ
  • ์Šคํ‚ฌ๋‹น ์ฒซ ๋งค์นญ๋งŒ ์œ ์ง€ (์ค‘๋ณต ์ œ๊ฑฐ)

Execution Gate โ€” ralplan-first ๊ฐ•์ œ

์‹คํ–‰ํ˜• ํ‚ค์›Œ๋“œ(ralph, autopilot, team, ultrawork)๊ฐ€ ๊ฐ์ง€๋˜์—ˆ๋”๋ผ๋„, ํ”„๋กฌํ”„ํŠธ๊ฐ€ underspecified(๋ชจํ˜ธ)ํ•˜๋ฉด ralplan์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋œ๋‹ค.

// src/hooks/keyword-registry.ts โ€” ๊ฒŒ์ดํŠธ ๋Œ€์ƒ ํ‚ค์›Œ๋“œ
export const EXECUTION_GATE_KEYWORDS = new Set<string>([
  'ralph', 'autopilot', 'team', 'ultrawork',
]);
 
export const GATE_BYPASS_PREFIXES = ['force:', '!'];
 
// ํ•ต์‹ฌ ํŒ๋‹จ ํ•จ์ˆ˜: ํ”„๋กฌํ”„ํŠธ๊ฐ€ ๋ชจํ˜ธํ•œ์ง€ ๊ฒฐ์ •
export function isUnderspecifiedForExecution(text: string): boolean {
  const trimmed = text.trim();
  if (!trimmed) return true;
 
  // escape hatch: force: ๋˜๋Š” ! ์ ‘๋‘์‚ฌ โ†’ ๋ฌด์กฐ๊ฑด ํ†ต๊ณผ
  for (const prefix of GATE_BYPASS_PREFIXES) {
    if (trimmed.startsWith(prefix)) return false;
  }
 
  // well-specified ์‹œ๊ทธ๋„ 14๊ฐœ ํŒจํ„ด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ์žˆ์œผ๋ฉด ํ†ต๊ณผ
  if (WELL_SPECIFIED_SIGNALS.some(p => p.test(trimmed))) return false;
 
  // ๋ชจ๋“œ ํ‚ค์›Œ๋“œ ์ œ๊ฑฐ ํ›„ ์‹ค์งˆ ๋‹จ์–ด ์ˆ˜ ๊ณ„์‚ฐ
  const stripped = trimmed
    .replace(/\b(?:ralph|autopilot|team|ultrawork|ulw|swarm)\b/gi, '')
    .trim();
  const effectiveWords = stripped.split(/\s+/).filter(w => w.length > 0).length;
 
  // 15๋‹จ์–ด ์ดํ•˜๋ฉด ๋ชจํ˜ธ โ†’ ralplan์œผ๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ
  if (effectiveWords <= 15) return true;
  return false;
}

well-specified ์‹œ๊ทธ๋„ โ€” ์ด ํŒจํ„ด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋งค์นญ๋˜๋ฉด โ€œ๊ตฌ์ฒด์ โ€์œผ๋กœ ํŒ๋‹จํ•˜์—ฌ ๊ฒŒ์ดํŠธ๋ฅผ ํ†ต๊ณผ์‹œํ‚จ๋‹ค:

// 14๊ฐœ ํŒจํ„ด ์ค‘ ํ•ต์‹ฌ ๋ฐœ์ทŒ
const WELL_SPECIFIED_SIGNALS: RegExp[] = [
  /\.\w{1,10}\b/,                    // ํŒŒ์ผ ํ™•์žฅ์ž (.ts, .md ๋“ฑ)
  /(?:^|\s)(?:src|lib|test)\//,      // ๋””๋ ‰ํ† ๋ฆฌ ๊ฒฝ๋กœ
  /\b(?:function|class|interface)\s/, // ์ฝ”๋“œ ์„ ์–ธ
  /[A-Z][a-z]+[A-Z]/,               // CamelCase ์‹๋ณ„์ž
  /\b\d+\.\s/,                       // ๋ฒˆํ˜ธ ๋งค๊ธด ๋‹จ๊ณ„ (1. 2. 3.)
  /\b(?:must|should|accept)\b/i,     // ์ˆ˜์šฉ ๊ธฐ์ค€ ํ‚ค์›Œ๋“œ
  /```/,                             // ์ฝ”๋“œ ๋ธ”๋ก
  /\b(?:PR|commit|issue)\s*#?\d+/i,  // PR/์ปค๋ฐ‹/์ด์Šˆ ์ฐธ์กฐ
  // ... ์ด 14๊ฐœ
];

"ralph make it better" โ†’ ๋ชจ๋“œ ํ‚ค์›Œ๋“œ ์ œ๊ฑฐ ํ›„ โ€œmake it betterโ€ = 3๋‹จ์–ด โ†’ ๋ชจํ˜ธ โ†’ ralplan ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ "ralph refactor src/api/auth.ts to use JWT" โ†’ .ts ํŒŒ์ผ ํ™•์žฅ์ž + src/ ๊ฒฝ๋กœ โ†’ ๊ตฌ์ฒด์  โ†’ ๋ฐ”๋กœ ์‹คํ–‰

๊ฒŒ์ดํŠธ ์ ์šฉ ํ•จ์ˆ˜:

// src/hooks/keyword-detector.ts
export function applyRalplanGate(
  keywords: string[], text: string,
): { keywords: string[]; gateApplied: boolean } {
  // cancel ํฌํ•จ ์‹œ ๊ฒŒ์ดํŠธ ์•ˆ ํ•จ
  // ralplan ์ด๋ฏธ ์žˆ์œผ๋ฉด ๊ฒŒ์ดํŠธ ์•ˆ ํ•จ
  // planning ์™„๋ฃŒ(PRD + test-spec ์กด์žฌ) ์‹œ ๊ฒŒ์ดํŠธ ์•ˆ ํ•จ
 
  if (!isUnderspecifiedForExecution(text)) return { keywords, gateApplied: false };
 
  // ์‹คํ–‰ํ˜• ํ‚ค์›Œ๋“œ๋ฅผ ralplan์œผ๋กœ ๊ต์ฒด
  const filtered = keywords.filter(k => !EXECUTION_GATE_KEYWORDS.has(k));
  if (!filtered.includes('ralplan')) filtered.push('ralplan');
  return { keywords: filtered, gateApplied: true };
}

Skill Composition โ€” 3๊ณ„์ธต ํ•ฉ์„ฑ ์•„ํ‚คํ…์ฒ˜

OMX ์Šคํ‚ฌ์˜ ํ•ต์‹ฌ ์„ค๊ณ„ ์›๋ฆฌ๋Š” **๊ณ„์ธต์  ํ•ฉ์„ฑ(Layered Composition)**์ด๋‹ค. ๊ฐ ๊ณ„์ธต์ด ์•„๋ž˜ ๊ณ„์ธต์„ ๊ฐ์‹ธ๋ฉฐ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

3๊ณ„์ธต ๊ตฌ์กฐ

graph TB
    subgraph L3["Layer 3: autopilot โ€” ์ „์ฒด ์ž์œจ ํŒŒ์ดํ”„๋ผ์ธ"]
        A3["planning โ†’ execution โ†’ QA โ†’ validation"]
    end

    subgraph L2["Layer 2: ralph โ€” ์˜์†์„ฑ + ๊ฒ€์ฆ"]
        A2["์„ธ์…˜ ์ƒํƒœ ์œ ์ง€ + architect ๊ฒ€์ฆ + ์žฌ์‹œ๋„ ๋ฃจํ”„"]
    end

    subgraph L1["Layer 1: ultrawork โ€” ๋ณ‘๋ ฌ์„ฑ"]
        A1["๋…๋ฆฝ ํƒœ์Šคํฌ ๋™์‹œ ์‹คํ–‰ + ๋ชจ๋ธ ๋ผ์šฐํŒ…"]
    end

    L3 -->|wraps| L2
    L2 -->|wraps| L1

    style L3 fill:#d4edda
    style L2 fill:#cce5ff
    style L1 fill:#fff3cd
๊ณ„์ธตSkill์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ์ƒํƒœ ์˜์†์„ฑ๊ฒ€์ฆ
Layer 1ultrawork๋ณ‘๋ ฌ ์‹คํ–‰ + ๋ชจ๋ธ ๋ผ์šฐํŒ…X๊ฒฝ๋Ÿ‰ (๋นŒ๋“œ/ํ…Œ์ŠคํŠธ ํ†ต๊ณผ)
Layer 2ralph์„ธ์…˜ ์ƒํƒœ + architect ๊ฒ€์ฆ + ์žฌ์‹œ๋„Oํ•„์ˆ˜ (STANDARD tier ์ด์ƒ)
Layer 3autopilot์ „์ฒด ์ž์œจ ํŒŒ์ดํ”„๋ผ์ธO์ „์ฒด lifecycle

Ralph + Ultrawork ํ•ฉ์„ฑ ์ƒ์„ธ

Ralph๋Š” Ultrawork์˜ ๋ณ‘๋ ฌ ์‹คํ–‰์„ ๋‚ด๋ถ€์ ์œผ๋กœ ํ™œ์šฉํ•˜๋ฉด์„œ, ์˜์†์„ฑยท๊ฒ€์ฆยท์žฌ์‹œ๋„๋ฅผ ๊ฐ์‹ธ๋Š” ๊ตฌ์กฐ๋‹ค.

sequenceDiagram
    autonumber
    participant U as ์‚ฌ์šฉ์ž
    participant R as Ralph (Layer 2)
    participant UW as Ultrawork (Layer 1)
    participant V as Architect ๊ฒ€์ฆ
    participant S as .omx/state/

    U->>R: "$ralph refactor API"
    R->>S: state_write(mode: "ralph", iteration: 1, phase: "executing")
    R->>R: Pre-context intake gate ํ™•์ธ
    Note over R: .omx/context/{slug}-{timestamp}.md ํ•„์ˆ˜

    loop ์ตœ๋Œ€ 10ํšŒ ๋ฐ˜๋ณต
        R->>UW: ๋ณ‘๋ ฌ ํƒœ์Šคํฌ ์œ„์ž„ (delegate)
        UW->>UW: ๋…๋ฆฝ ํƒœ์Šคํฌ ๋™์‹œ ์‹คํ–‰
        UW-->>R: ์‹คํ–‰ ๊ฒฐ๊ณผ ๋ฐ˜ํ™˜
        R->>S: state_write(phase: "verifying")
        R->>V: architect ๊ฒ€์ฆ ์š”์ฒญ (STANDARD tier ์ด์ƒ)
        V-->>R: ๊ฒ€์ฆ ๊ฒฐ๊ณผ
        alt ๊ฒ€์ฆ ํ†ต๊ณผ
            R->>S: state_write(phase: "complete", completed_at: timestamp)
            R-->>U: ์™„๋ฃŒ ๋ณด๊ณ 
        else ๊ฒ€์ฆ ์‹คํŒจ
            R->>S: state_write(phase: "fixing", iteration: N+1)
            Note over R: ๋‹ค์Œ ๋ฐ˜๋ณต์œผ๋กœ ๊ณ„์†
        end
    end

Ralph Planning Gate โ€” ralplan-first ๊ฐ•์ œ

Ralph๊ฐ€ ํ™œ์„ฑํ™”๋˜๋ฉด PRD + test-spec ์•„ํ‹ฐํŒฉํŠธ๊ฐ€ ์กด์žฌํ•ด์•ผ ๊ตฌํ˜„์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค.

Ralph ํ™œ์„ฑ ์ƒํƒœ์—์„œ์˜ ๊ฒŒ์ดํŠธ ์กฐ๊ฑด:
โ”œโ”€โ”€ .omx/plans/prd-*.md ์กด์žฌ?      โ†’ YES โ†’ ๋‹ค์Œ ํ™•์ธ
โ”‚                                   โ†’ NO  โ†’ ๊ตฌํ˜„ ์ฐจ๋‹จ (BLOCKED)
โ””โ”€โ”€ .omx/plans/test-spec-*.md ์กด์žฌ? โ†’ YES โ†’ ๊ฒŒ์ดํŠธ ํ•ด์ œ (UNLOCKED)
                                    โ†’ NO  โ†’ ๊ตฌํ˜„ ์ฐจ๋‹จ (BLOCKED)

๊ฒŒ์ดํŠธ ์ƒํƒœ๋Š” AGENTS.md ์˜ค๋ฒ„๋ ˆ์ด์— UNLOCKED / BLOCKED๋กœ ์ฃผ์ž…๋œ๋‹ค. ๋‘ ํŒŒ์ผ์ด ๋ชจ๋‘ ์กด์žฌํ•ด์•ผ ๋น„๋กœ์†Œ current_phase: "executing"์ด ํ—ˆ์šฉ๋œ๋‹ค.

deep-interview (Ouroboros) โ€” ์†Œํฌ๋ผํ…Œ์Šค์‹ ์š”๊ตฌ์‚ฌํ•ญ ์ธํ„ฐ๋ทฐ

deep-interview๋Š” ๊ตฌํ˜„ ์ „์— ๋ชจํ˜ธ์„ฑ์„ ์ œ๊ฑฐํ•˜๋Š” ์ธํ„ฐ๋ทฐ ์›Œํฌํ”Œ๋กœ์šฐ๋‹ค. โ€œOuroborosโ€๋ผ๋Š” ๋ณ„๋ช…์€ ์ž๊ธฐ ์ฐธ์กฐ์  ๋ฐ˜๋ณต ์งˆ๋ฌธ ๋ฃจํ”„์—์„œ ์œ ๋ž˜ํ•œ๋‹ค.

5๋‹จ๊ณ„ ํ๋ฆ„

sequenceDiagram
    autonumber
    participant U as ์‚ฌ์šฉ์ž
    participant DI as deep-interview
    participant S as .omx/ (์ƒํƒœยท์•„ํ‹ฐํŒฉํŠธ)
    participant EX as ์‹คํ–‰ ๋ธŒ๋ฆฟ์ง€

    DI->>S: Phase 0: Preflight โ€” context ์Šค๋ƒ…์ƒท ์ƒ์„ฑ
    Note over S: .omx/context/{slug}-{timestamp}.md

    DI->>DI: Phase 1: Initialize โ€” depth ํ”„๋กœํŒŒ์ผ ์„ค์ •
    Note over DI: quick(0.30) / standard(0.20) / deep(0.15)

    loop Phase 2: Interview Loop (ambiguity โ‰ค threshold๊นŒ์ง€)
        DI->>U: 1ํšŒ 1์งˆ๋ฌธ โ€” ๊ฐ€์žฅ ์•ฝํ•œ clarity ์ฐจ์› ํƒ€๊ฒŸ
        U-->>DI: ๋‹ต๋ณ€
        DI->>DI: ambiguity ์ ์ˆ˜ ์žฌ๊ณ„์‚ฐ
        DI->>S: state_write(rounds[], current_ambiguity)
    end

    Note over DI: Phase 3: Challenge Mode (round 4+)
    DI->>U: Contrarian(4+), Simplifier(6+), Ontologist(8+)

    DI->>S: Phase 4: Crystallize โ€” transcript + spec ์ƒ์„ฑ
    Note over S: .omx/interviews/ + .omx/specs/

    DI->>EX: Phase 5: Execution Bridge
    Note over EX: $ralplan / $autopilot / $ralph / $team / ์ถ”๊ฐ€ ์ •์ œ

Ambiguity ์ ์ˆ˜ โ€” ๊ฐ€์ค‘์น˜ ๊ธฐ๋ฐ˜ ๋‹ค์ฐจ์› ํ‰๊ฐ€

์ฐจ์›Greenfield ๊ฐ€์ค‘์น˜Brownfield ๊ฐ€์ค‘์น˜
Intent (์˜๋„)0.300.25
Outcome (๊ฒฐ๊ณผ)0.250.20
Scope (๋ฒ”์œ„)0.200.20
Constraints (์ œ์•ฝ)0.150.15
Success Criteria (์„ฑ๊ณต ๊ธฐ์ค€)0.100.10
Context Clarity (๋งฅ๋ฝ)โ€”0.10

ambiguity = 1 - (๊ฐ ์ฐจ์›์˜ clarity ร— ๊ฐ€์ค‘์น˜)์˜ ํ•ฉ

Challenge Mode โ€” ๊ฐ€์ • ์ŠคํŠธ๋ ˆ์Šค ํ…Œ์ŠคํŠธ

๋ชจ๋“œํ™œ์„ฑ ์‹œ์ ์—ญํ• 
Contrarianround 4+ํ•ต์‹ฌ ๊ฐ€์ •์— ๋ฐ˜๋ก  ์ œ๊ธฐ
Simplifierround 6+์ตœ์†Œ ์‹คํ–‰ ๊ฐ€๋Šฅ ๋ฒ”์œ„ ํƒ์ƒ‰
Ontologistround 8+ (ambiguity > 0.30)๋ณธ์งˆ์  ์žฌ์ •์˜ ์š”์ฒญ

Input Lock โ€” ์ž๋™ ์Šน์ธ ์ฐจ๋‹จ

deep-interview๊ฐ€ ํ™œ์„ฑํ™”๋˜๋ฉด ์ž๋™ ์Šน์ธ ๋‹จ์ถ•์–ด๊ฐ€ ์ฐจ๋‹จ๋œ๋‹ค.

์ฐจ๋‹จ ๋Œ€์ƒ: yes, y, proceed, continue, ok, sure, go ahead, next i should

์ด๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ธํ„ฐ๋ทฐ ์งˆ๋ฌธ์— ๋Œ€ํ•ด ์„ฑ์˜ ์—†์ด yes๋งŒ ๋ฐ˜๋ณตํ•˜์—ฌ ๋ชจํ˜ธ์„ฑ ์ œ๊ฑฐ๋ฅผ ์šฐํšŒํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•œ๋‹ค. Lock์€ ์ธํ„ฐ๋ทฐ ์™„๋ฃŒ(success), ์—๋Ÿฌ(error), ์ค‘๋‹จ(abort), ํ•ธ๋“œ์˜คํ”„(handoff) ์‹œ ํ•ด์ œ๋œ๋‹ค.

visual-verdict โ€” ๋น„์ฃผ์–ผ QA ์›Œํฌํ”Œ๋กœ์šฐ

visual-verdict๋Š” ์Šคํฌ๋ฆฐ์ƒท๊ณผ ๋ ˆํผ๋Ÿฐ์Šค ์ด๋ฏธ์ง€๋ฅผ ๋น„๊ตํ•˜์—ฌ ๊ตฌ์กฐํ™”๋œ JSON ํŒ์ •์„ ๋‚ด๋ฆฌ๋Š” ๋น„์ฃผ์–ผ QA ์Šคํ‚ฌ์ด๋‹ค.

์ž…์ถœ๋ ฅ ๊ณ„์•ฝ

์ž…๋ ฅ:

  • reference_images[] โ€” 1๊ฐœ ์ด์ƒ์˜ ๋ ˆํผ๋Ÿฐ์Šค ์ด๋ฏธ์ง€ ๊ฒฝ๋กœ
  • generated_screenshot โ€” ํ˜„์žฌ ์ถœ๋ ฅ ์ด๋ฏธ์ง€
  • category_hint (์„ ํƒ) โ€” UI ์นดํ…Œ๊ณ ๋ฆฌ ํžŒํŠธ (์˜ˆ: hackernews, dashboard)

์ถœ๋ ฅ โ€” ํ•„์ˆ˜ JSON ์Šคํ‚ค๋งˆ:

{
  "score": 87,
  "verdict": "revise",
  "category_match": true,
  "differences": [
    "Top nav spacing is tighter than reference",
    "Primary button uses smaller font weight"
  ],
  "suggestions": [
    "Increase nav item horizontal padding by 4px",
    "Set primary button font-weight to 600"
  ],
  "reasoning": "Core layout matches, but style details still diverge."
}
ํ•„๋“œํƒ€์ž…์„ค๋ช…
scoreinteger 0-100์‹œ๊ฐ์  ์ผ์น˜๋„ ์ ์ˆ˜
verdictpass / revise / failํŒ์ • ๊ฒฐ๊ณผ
category_matchboolean์˜๋„๋œ UI ์นดํ…Œ๊ณ ๋ฆฌ์™€์˜ ์ผ์น˜ ์—ฌ๋ถ€
differences[]string[]๊ตฌ์ฒด์  ์‹œ๊ฐ ์ฐจ์ด (๋ ˆ์ด์•„์›ƒ, ๊ฐ„๊ฒฉ, ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ, ์ƒ‰์ƒ)
suggestions[]string[]differences์— ๋Œ€์‘ํ•˜๋Š” ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์ˆ˜์ • ์ œ์•ˆ
reasoningstring1-2๋ฌธ์žฅ ํŒ์ • ๊ทผ๊ฑฐ ์š”์•ฝ

Ralph ํ†ตํ•ฉ โ€” ๋ฐ˜๋ณต ๊ฒŒ์ดํŠธ

sequenceDiagram
    autonumber
    participant R as Ralph
    participant VV as visual-verdict
    participant S as .omx/state/

    loop Ralph ๋ฐ˜๋ณต ๋ฃจํ”„
        R->>R: ์ฝ”๋“œ ์ˆ˜์ • ์ž‘์—… ์ˆ˜ํ–‰
        R->>VV: $visual-verdict ์‹คํ–‰ (๋งค ์ˆ˜์ • ์ „)
        VV-->>R: JSON ํŒ์ • ๋ฐ˜ํ™˜
        R->>S: ralph-progress.json์— verdict ์ €์žฅ
        alt score โ‰ฅ 90
            Note over R: ํ†ต๊ณผ โ€” ๋‹ค์Œ ๋‹จ๊ณ„๋กœ
        else score < 90
            Note over R: ๋ฏธํ†ต๊ณผ โ€” suggestions ๊ธฐ๋ฐ˜์œผ๋กœ ์ˆ˜์ • ๊ณ„์†
        end
    end
  • Ralph ํ†ตํ•ฉ ์‹œ ํ†ต๊ณผ ๊ธฐ์ค€: score >= 90
  • web-clone ํ†ตํ•ฉ ์‹œ ํ†ต๊ณผ ๊ธฐ์ค€: score >= 85 (visual + functional + structure ๋ณตํ•ฉ ํŒ์ •)
  • ๋งค ์ˆ˜์ • ์ „ $visual-verdict๋ฅผ ๋จผ์ € ์‹คํ–‰ํ•˜์—ฌ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ํ‰๊ฐ€ โ†’ ๋ถˆํ•„์š”ํ•œ ์ˆ˜์ • ๋ฐฉ์ง€

Skill ๋กœ๋”ฉ ๋ฉ”์ปค๋‹ˆ์ฆ˜ โ€” ๋””์Šค์ปค๋ฒ„๋ฆฌ์—์„œ ์‹คํ–‰๊นŒ์ง€

๋””์Šค์ปค๋ฒ„๋ฆฌ ๊ฒฝ๋กœ (์†Œ์Šค: src/utils/paths.ts)

// src/utils/paths.ts โ€” 3๊ฐœ ํƒ์ƒ‰ ๊ฒฝ๋กœ ์ •์˜
export function projectSkillsDir(projectRoot?: string): string {
  return join(projectRoot || process.cwd(), '.agents', 'skills');  // 1์ˆœ์œ„
}
export function userSkillsDir(): string {
  return join(codexHome(), 'skills');  // ~/.codex/skills/ โ€” 2์ˆœ์œ„
}
export function legacyUserSkillsDir(): string {
  return join(homedir(), '.agents', 'skills');  // 3์ˆœ์œ„ (๋ ˆ๊ฑฐ์‹œ)
}
 
// ๋””์Šค์ปค๋ฒ„๋ฆฌ: ํ”„๋กœ์ ํŠธ โ†’ ์‚ฌ์šฉ์ž ์ˆœ์„œ, ๊ฐ™์€ ์ด๋ฆ„์ด๋ฉด ํ”„๋กœ์ ํŠธ๊ฐ€ shadow
export async function listInstalledSkillDirectories(
  projectRoot?: string,
): Promise<InstalledSkillDirectory[]> {
  const orderedDirs = [
    { dir: projectSkillsDir(projectRoot), scope: 'project' },
    { dir: userSkillsDir(), scope: 'user' },
  ];
  // project skills shadow user skills with same name
}

๊ฐ™์€ ์ด๋ฆ„์˜ Skill์ด ํ”„๋กœ์ ํŠธ์™€ ์‚ฌ์šฉ์ž ์Šค์ฝ”ํ”„ ๋ชจ๋‘์— ์กด์žฌํ•˜๋ฉด, ํ”„๋กœ์ ํŠธ ์Šค์ฝ”ํ”„๊ฐ€ ์Šน๋ฆฌ(shadow). ์‰๋„์ž‰๋œ ์Šคํ‚ฌ์˜ ์ฐธ์กฐ ๋ผ์ธ์€ ์„ธ์…˜ ํ•ฉ๋ณธ AGENTS.md์—์„œ ์ œ๊ฑฐ๋œ๋‹ค.

Catalog Manifest (์†Œ์Šค: src/catalog/manifest.json)

{
  "schemaVersion": 1,
  "catalogVersion": "2026.02.28.1",
  "skills": [
    {"name": "ralph", "category": "execution", "status": "active", "core": true},
    {"name": "swarm", "category": "execution", "status": "alias", "canonical": "team"}
  ]
}
  • core skill (ํ•„์ˆ˜): ralplan, team, ralph, ultrawork, autopilot
  • alias: swarm โ†’ team, ecomode โ†’ ultrawork (merged)
  • ๋กœ๋“œ ์‹œ์ ์— ์Šคํ‚ค๋งˆ ์œ ํšจ์„ฑ ๊ฒ€์ฆ

๋กœ๋“œ ํ๋ฆ„ ์š”์•ฝ โ€” AGENTS.md ๊ฒฝ๋กœ ์ฐธ์กฐ + LLM ์ง์ ‘ ์ฝ๊ธฐ

SKILL.md๋Š” AGENTS.md์— ์ž„๋ฒ ๋”ฉ๋˜์ง€ ์•Š๋Š”๋‹ค. AGENTS.md์—๋Š” ์Šคํ‚ฌ ํŒŒ์ผ์˜ ๊ฒฝ๋กœ ์ฐธ์กฐ๋งŒ ํฌํ•จ๋œ๋‹ค.

AGENTS.md ๋‚ด ์‹ค์ œ ์ฐธ์กฐ ํ˜•์‹:

<!-- AGENTS.md keyword_detection ์„น์…˜ -->
| Keyword(s) | Skill | Action |
|-------------|-------|--------|
| "ralph", "don't stop", "must complete" | `$ralph` | Read `./.agents/skills/ralph/SKILL.md`, execute persistence loop |
| "autopilot", "build me", "I want a" | `$autopilot` | Read `./.agents/skills/autopilot/SKILL.md`, execute autonomous pipeline |

LLM์€ ์ด ํ…Œ์ด๋ธ”์„ ์ฝ๊ณ , ํ‚ค์›Œ๋“œ๊ฐ€ ๋งค์นญ๋˜๋ฉด Action ์—ด์˜ ๊ฒฝ๋กœ๋ฅผ ๋”ฐ๋ผ SKILL.md๋ฅผ ์ง์ ‘ ์ฝ๋Š”๋‹ค. ํ”„๋กœ๊ทธ๋ž˜๋ฐ์  ๋กœ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ LLM์˜ ํŒŒ์ผ ์ฝ๊ธฐ ๋Šฅ๋ ฅ์— ์˜์กดํ•˜๋Š” ํ™•๋ฅ ๋ก ์  ์„ค๊ณ„๋‹ค.

ํ”„๋กœ์ ํŠธ ์Šคํ‚ฌ์ด ์‚ฌ์šฉ์ž ์Šคํ‚ฌ์„ shadowํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜:

// src/hooks/agents-overlay.ts โ€” ์‰๋„์ž‰ ์ฒ˜๋ฆฌ์˜ ํ•ต์‹ฌ
const SKILL_REFERENCE_PATTERN = /\/skills\/([^/\s`]+)\/SKILL\.md/;
 
// ํ”„๋กœ์ ํŠธ ์Šค์ฝ”ํ”„์— ๊ฐ™์€ ์ด๋ฆ„์˜ ์Šคํ‚ฌ์ด ์žˆ์œผ๋ฉด
// ์‚ฌ์šฉ์ž ์Šค์ฝ”ํ”„ ์Šคํ‚ฌ์˜ ์ฐธ์กฐ ๋ผ์ธ์„ AGENTS.md์—์„œ ์ œ๊ฑฐ
export function dropShadowedSkillReferenceLines(
  agentsMd: string,
  projectSkillNames: Set<string>,
): string {
  return agentsMd
    .split('\n')
    .filter(line => {
      const match = line.match(SKILL_REFERENCE_PATTERN);
      if (!match) return true;  // ์Šคํ‚ฌ ์ฐธ์กฐ๊ฐ€ ์•„๋‹Œ ๋ผ์ธ์€ ์œ ์ง€
      const skillName = match[1];
      // ํ”„๋กœ์ ํŠธ์— ๊ฐ™์€ ์ด๋ฆ„์ด ์žˆ์œผ๋ฉด ์ด (์‚ฌ์šฉ์ž ์Šค์ฝ”ํ”„) ๋ผ์ธ ์ œ๊ฑฐ
      return !projectSkillNames.has(skillName);
    })
    .join('\n');
}

์ด ํ•จ์ˆ˜๊ฐ€ omx launch ์‹œ์ ์— ์‹คํ–‰๋˜์–ด, ํ•ฉ๋ณธ AGENTS.md์—์„œ ์‰๋„์ž‰๋œ ์‚ฌ์šฉ์ž ์Šคํ‚ฌ ์ฐธ์กฐ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค. LLM์ด ๋ณด๋Š” AGENTS.md์—๋Š” ํ•ญ์ƒ ๊ฐ€์žฅ ๋†’์€ ์šฐ์„ ์ˆœ์œ„์˜ ์Šคํ‚ฌ ๊ฒฝ๋กœ๋งŒ ๋‚จ๋Š”๋‹ค.

MCP ๋„๊ตฌ(state_write, memory_store ๋“ฑ)๋Š” Skill ์‹คํ–‰ ์ค‘ ์ƒํƒœ ๊ธฐ๋ก์— ์‚ฌ์šฉ๋˜๋ฉฐ, SKILL.md ๋‚ด <Tool_Usage> ์„น์…˜์— ์‚ฌ์šฉ ๊ณ„์•ฝ์ด ๋ช…์‹œ๋œ๋‹ค.

graph LR
    OL["agents-overlay.ts<br>launch ์‹œ ํ•ฉ๋ณธ"] -->|"๊ฒฝ๋กœ ์ฐธ์กฐ ์ฃผ์ž…<br>+ shadow ์ฒ˜๋ฆฌ"| AM["AGENTS.md"]
    AM -->|"LLM์ด ํ‚ค์›Œ๋“œ ํ…Œ์ด๋ธ” ์ฝ๊ธฐ"| CX["Codex CLI (LLM)"]
    CX -->|"Action ์—ด์˜ ๊ฒฝ๋กœ ๋”ฐ๋ผ<br>์ง์ ‘ ํŒŒ์ผ ์ฝ๊ธฐ"| SM[".agents/skills/ralph/SKILL.md"]
    SM -->|"context์— ๋กœ๋“œ"| CX
    CX -->|"์ƒํƒœ ๊ธฐ๋ก"| MCP["MCP Server<br>(state_write ๋“ฑ)"]

    PT["paths.ts<br>๋””์Šค์ปค๋ฒ„๋ฆฌ"] -.->|"์Šคํ‚ฌ ๊ฒฝ๋กœ ํ•ด์„"| OL
    MF["manifest.json"] -.->|"์นดํƒˆ๋กœ๊ทธ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ"| OL

    style OL fill:#f0e6ff
    style AM fill:#fef7e0
    style CX fill:#e8f0fe

์ฐธ๊ณ  ๋ฌธ์„œ