์๋ฆฌ์ฆ: oh-my-codex ์ํคํ ์ฒ ํด๋ถ
์ด ์๋ฆฌ์ฆ๋ OpenAI Codex CLI ํ์ฅ ๋ฐํ์์ธ oh-my-codex(OMX)์ ๋ด๋ถ ๊ตฌ์กฐ๋ฅผ ๋จ๊ณ๋ณ๋ก ํด๋ถํ๋ ๊ณผ์ ์ด๋ค.
| ํธ | ๋ด์ฉ | ํต์ฌ |
|---|---|---|
| 0ํธ | Overview | 3-Plane ์ํคํ ์ฒ, OMC์์ ์ฐจ์ด, ์ ์ฒด ํ๋ฆ |
| 1ํธ | Codex CLI Foundation | Codex CLI ์์ฒด์ ๊ตฌ์กฐ์ ํ์ฅ ํฌ์ธํธ |
| 2ํธ | OMX Integration | OMX๊ฐ Codex์ ์ด๋ป๊ฒ ์ฐ๊ฒฐ๋๋ |
| 3ํธ (๋ณธ๋ฌธ) | Skill System | ์ํฌํ๋ก์ฐ๋ฅผ ์ด๋ป๊ฒ ์ ์ํ๋ |
| 4ํธ | Prompt & Agent System | ์์ด์ ํธ๋ ๋ญ๊ณ ์ด๋ป๊ฒ ์ ํ๋๋ |
| 5ํธ | MCP Servers | ์ด๋ค MCP ๋๊ตฌ๋ฅผ ์ธ ์ ์๋ |
| 6ํธ | State & Lifecycle | ์ํ๋ฅผ ์ด๋ป๊ฒ ์ ์งํ๋ |
| 7ํธ | Team Orchestration | Team ๋ชจ๋๋ ์ด๋ป๊ฒ ๋์ํ๋ |
| 8ํธ | Native & Spark | Rust ๋ค์ดํฐ๋ธ ๋๊ตฌ๋ ๋ญ๊ฐ |
- 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์์ ๊ตฌ์กฐ ๋น๊ต
| ํญ๋ชฉ | OMC | OMX |
|---|---|---|
| ํธ์ถ ๋ฐฉ์ | 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 | ์ญํ | ํค์๋ ํธ๋ฆฌ๊ฑฐ |
|---|---|---|
team | N 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 |
ultraqa | QA ์ฌ์ดํด | 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-ux | UI/UX ํ๊ฐ | (๋ช ์์ ํธ์ถ) |
์ ํธ๋ฆฌํฐ Skill
| Skill | ์ญํ |
|---|---|
doctor | ์ค์น ์ํ ์ง๋จ |
omx-setup | ์ด๊ธฐ ์ค์ |
hud | ์ํ ๋์๋ณด๋ |
note | ๋ฉ๋ชจ |
trace | ์คํ ์ถ์ |
build-fix | ๋น๋ ์คํจ ๋ณต๊ตฌ (fix build, type errors) |
tdd | TDD ์ํฌํ๋ก์ฐ (tdd, test first) |
git-master | Git ์์ |
pipeline | ๋น๋ ํ์ดํ๋ผ์ธ |
ai-slop-cleaner | ์ฝ๋ ์ ๋ฆฌ/๋ฆฌํฉํฐ (cleanup, refactor, deslop) |
ecomode | ํ ํฐ ์ ์ฝ ๋ชจ๋ (ecomode, eco, budget) |
help | ๋์๋ง |
skill | ์คํฌ ๋ชฉ๋ก ์กฐํ |
ํน์ Skill
| Skill | ์ญํ |
|---|---|
visual-verdict | ๋น์ฃผ์ผ QA โ ์คํฌ๋ฆฐ์ท ๋น๊ต, ๊ตฌ์กฐํ JSON ์ถ๋ ฅ |
ask-claude | Claude์๊ฒ ์ง๋ฌธ |
ask-gemini | Gemini์๊ฒ ์ง๋ฌธ |
web-clone | ์น์ฌ์ดํธ ๋ณต์ ํ์ดํ๋ผ์ธ โ Playwright ๊ธฐ๋ฐ ๋ธ๋ผ์ฐ์ ์๋ํ (web-clone, clone site) |
configure-notifications | ์๋ฆผ ๊ฒ์ดํธ์จ์ด ์ค์ |
worker | Team Worker ์ ์ฉ (team ๋ชจ๋์์๋ง ์ฌ์ฉ) |
swarm | team์ ํธํ ๋ณ์นญ |
ralph-init | Ralph ์ด๊ธฐํ ์ ์ฉ |
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 | ํค์๋ ์์ |
|---|---|---|
| 11 | ralplan | ralplan, consensus plan |
| 10 | autopilot, ultrawork | autopilot, build me, ultrawork, parallel |
| 9 | ralph | ralph, don't stop, must complete |
| 8 | deep-interview, plan, team, ultraqa | interview, team, swarm |
| 7 | analyze | analyze, investigate |
| 6 | tdd, build-fix, code-review, security-review | tdd, fix build, code review |
| 5 | cancel | cancel, 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 1 | ultrawork | ๋ณ๋ ฌ ์คํ + ๋ชจ๋ธ ๋ผ์ฐํ | X | ๊ฒฝ๋ (๋น๋/ํ ์คํธ ํต๊ณผ) |
| Layer 2 | ralph | ์ธ์ ์ํ + architect ๊ฒ์ฆ + ์ฌ์๋ | O | ํ์ (STANDARD tier ์ด์) |
| Layer 3 | autopilot | ์ ์ฒด ์์จ ํ์ดํ๋ผ์ธ | 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.30 | 0.25 |
| Outcome (๊ฒฐ๊ณผ) | 0.25 | 0.20 |
| Scope (๋ฒ์) | 0.20 | 0.20 |
| Constraints (์ ์ฝ) | 0.15 | 0.15 |
| Success Criteria (์ฑ๊ณต ๊ธฐ์ค) | 0.10 | 0.10 |
| Context Clarity (๋งฅ๋ฝ) | โ | 0.10 |
ambiguity = 1 - (๊ฐ ์ฐจ์์ clarity ร ๊ฐ์ค์น)์ ํฉ
Challenge Mode โ ๊ฐ์ ์คํธ๋ ์ค ํ ์คํธ
| ๋ชจ๋ | ํ์ฑ ์์ | ์ญํ |
|---|---|---|
| Contrarian | round 4+ | ํต์ฌ ๊ฐ์ ์ ๋ฐ๋ก ์ ๊ธฐ |
| Simplifier | round 6+ | ์ต์ ์คํ ๊ฐ๋ฅ ๋ฒ์ ํ์ |
| Ontologist | round 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."
}| ํ๋ | ํ์ | ์ค๋ช |
|---|---|---|
score | integer 0-100 | ์๊ฐ์ ์ผ์น๋ ์ ์ |
verdict | pass / revise / fail | ํ์ ๊ฒฐ๊ณผ |
category_match | boolean | ์๋๋ UI ์นดํ ๊ณ ๋ฆฌ์์ ์ผ์น ์ฌ๋ถ |
differences[] | string[] | ๊ตฌ์ฒด์ ์๊ฐ ์ฐจ์ด (๋ ์ด์์, ๊ฐ๊ฒฉ, ํ์ดํฌ๊ทธ๋ํผ, ์์) |
suggestions[] | string[] | differences์ ๋์ํ๋ ์คํ ๊ฐ๋ฅํ ์์ ์ ์ |
reasoning | string | 1-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