์ด ๋ฌธ์๋ 2ํธ Hook System์ ํ์ ๊ฐ๋ ์ผ๋ก, 18๊ฐ Hook ์คํฌ๋ฆฝํธ ์ค
skill-injector.mjs๋ฅผ ๋ค๋ฃฌ๋ค.
- skill-injector.mjs๋
UserPromptSubmitHook์์ ์ฌ์ฉ์ ํ๋กฌํํธ๋ฅผ ํ์ต๋ Skill ํ์ผ์ trigger์ ๋งค์นญํ์ฌ, ๊ด๋ จ Skill ๋ด์ฉ์ Claude context์ ์ฃผ์ ํ๋ ์คํฌ๋ฆฝํธ - keyword-detector.mjs๊ฐ 14๊ฐ ๋งค์ง ํค์๋๋ฅผ ํ๋์ฝ๋ฉ์ผ๋ก ๊ฐ์งํ๋ ๋ฐ๋ฉด, skill-injector.mjs๋ ์ฌ์ฉ์๊ฐ ํ์ต์ํจ Skill ํ์ผ์ trigger๋ฅผ ๋์ ์ผ๋ก ๋งค์นญ
- 3-tier ๋๋ ํ ๋ฆฌ์์ Skill์ ํ์ํ๊ณ , ์ธ์ ์บ์ฑ์ผ๋ก ์ค๋ณต ์ฃผ์ ์ ๋ฐฉ์งํ๋ฉฐ, ์ต๋ 5๊ฐ๊น์ง ๋งค์นญ
์์ฑ์ผ: 2026-03-15 ์์ค: skill-injector.mjs
ํด๋น ๊ฐ๋ ์ด ํ์ํ ์ด์
- keyword-detector.mjs๋ 14๊ฐ ํค์๋๋ง ๊ฐ์ง ๊ฐ๋ฅํ๋ค. ์ฌ์ฉ์๊ฐ ์์ฒด Skill์ ๋ง๋ค์ด๋ ํค์๋ ๊ฐ์ง์๋ ๋ฐ์๋์ง ์๋๋ค
- skill-injector.mjs๋
.mdํ์ผ์ YAML frontmatter์triggers๋ฅผ ์ ์ํ๋ฉด, ํด๋น trigger๊ฐ ํ๋กฌํํธ์ ํฌํจ๋ ๋ ์๋์ผ๋ก Skill ๋ด์ฉ์ ์ฃผ์ ํ๋ค - ์ด ์คํฌ๋ฆฝํธ๋ hooks.json์์
UserPromptSubmit์ด๋ฒคํธ์ ๋ ๋ฒ์งธ ์คํฌ๋ฆฝํธ๋ก ๋ฑ๋ก๋์ด ์์ด, keyword-detector.mjs ์ดํ์ ์คํ๋๋ค
AS-IS
sequenceDiagram autonumber participant U as User participant CC as Claude Code U->>CC: "PR ์ค๋นํด์ค" CC->>CC: ํ์ต๋ Skill ์กด์ฌํ์ง๋ง ๋งค์นญ ์๋จ ์์ CC-->>U: ์ผ๋ฐ ์๋ต (Skill ๋ฌด์)
TO-BE
sequenceDiagram autonumber participant U as User participant CC as Claude Code box OMC participant SI as skill-injector.mjs end U->>CC: "PR ์ค๋นํด์ค" CC->>SI: stdin: { prompt, cwd, session_id } SI->>SI: 3-tier ๋๋ ํ ๋ฆฌ์์ .md Skill ํ์ SI->>SI: trigger "PR ์ค๋น" ๋งค์นญ (score: 10) SI-->>CC: { additionalContext: "<mnemosyne>Skill ๋ด์ฉ</mnemosyne>" } CC->>CC: ์ฃผ์ ๋ Skill ์ง์์ผ๋ก PR ์ค๋น ์ํ
keyword-detector.mjs์์ ์ญํ ๋ถ๋ด
sequenceDiagram autonumber participant U as User participant CC as Claude Code box OMC participant KD as keyword-detector.mjs participant SI as skill-injector.mjs end U->>CC: ํ๋กฌํํธ ์ ๋ ฅ CC->>KD: UserPromptSubmit (1st, timeout 5s) KD->>KD: 14๊ฐ ๋งค์ง ํค์๋ ๋งค์นญ KD-->>CC: Skill ํธ์ถ ์ง์ or ๋ฉ์์ง ์ฃผ์ CC->>SI: UserPromptSubmit (2nd, timeout 3s) SI->>SI: ํ์ต๋ Skill trigger ๋งค์นญ SI-->>CC: ๋งค์นญ๋ Skill ๋ด์ฉ context ์ฃผ์
| ๊ตฌ๋ถ | keyword-detector.mjs | skill-injector.mjs |
|---|---|---|
| ๋งค์นญ ๋์ | 14๊ฐ ํ๋์ฝ๋ฉ ํค์๋ | ํ์ต๋ Skill ํ์ผ์ trigger |
| ๋งค์นญ ๋ฐฉ์ | ์ ๊ท์ ํจํด | trigger ํค์๋ ํฌํจ ์ฌ๋ถ (์ ์์ ) |
| ์ถ๋ ฅ ๋ฐฉ์ | Skill tool ํธ์ถ ์ง์ or ๋ฉ์์ง ์ง์ ์ฃผ์ | <mnemosyne> ํ๊ทธ๋ก Skill ๋ด์ฉ ์ฃผ์
|
| ์คํ ์์ | 1st (5s) | 2nd (3s) |
3-tier Skill ๋๋ ํ ๋ฆฌ
graph TB subgraph Tier1["Tier 1: ํ๋ก์ ํธ ๋ ๋ฒจ"] P[".omc/skills/*.md"] end subgraph Tier2["Tier 2: ๊ธ๋ก๋ฒ ๋ ๋ฒจ"] G["~/.omc/skills/*.md"] end subgraph Tier3["Tier 3: ๋ ๊ฑฐ์"] L["~/.claude/skills/omc-learned/*.md"] end SI["skill-injector.mjs"] --> P SI --> G SI --> L P -->|"์ฐ์ "| Result["๋งค์นญ ํ๋ณด"] G --> Result L --> Result
- ํ๋ก์ ํธ ๋ ๋ฒจ์ด ์ฐ์ โ ๊ฐ์ Skill์ด ํ๋ก์ ํธ์ ๊ธ๋ก๋ฒ์ ๋ชจ๋ ์์ผ๋ฉด ํ๋ก์ ํธ ๋ฒ์ ์ ์ฌ์ฉ
realpathSync()๋ก ์ฌ๋ณผ๋ฆญ ๋งํฌ๋ฅผ ํด๊ฒฐํ์ฌ ์ค๋ณต ์ ๊ฑฐ
Skill ํ์ผ ๊ตฌ์กฐ์ ๋งค์นญ ๋ก์ง
YAML frontmatter์ triggers
---
name: pr-creator
triggers:
- PR ์ค๋น
- PR ready
- ์ปค๋ฐํ๊ณ ํธ์
---
Skill ๋ณธ๋ฌธ ๋ด์ฉ...parseSkillFrontmatterFallback()๊ฐ --- ๊ตฌ๋ถ์ ์ฌ์ด์์ name๊ณผ triggers ๋ฐฐ์ด์ ์ถ์ถํ๋ค.
์ค์ฝ์ด๋ง ๊ธฐ๋ฐ ๋งค์นญ
graph LR Prompt["์ฌ์ฉ์ ํ๋กฌํํธ"] --> Lower["์๋ฌธ์ ๋ณํ"] Lower --> Check{"๊ฐ Skill์ trigger ์ํ"} Check -->|"trigger ํฌํจ"| Score["+10์ "] Check -->|"๋ฏธํฌํจ"| Skip["์คํต"] Score --> Sort["์ ์ ๋ด๋ฆผ์ฐจ์ ์ ๋ ฌ"] Sort --> Limit["์์ 5๊ฐ ๋ฐํ"]
- ํ๋กฌํํธ๋ฅผ ์๋ฌธ์๋ก ๋ณํ ํ, ๊ฐ Skill ํ์ผ์ trigger๋ฅผ ์ํํ๋ฉฐ ํฌํจ ์ฌ๋ถ๋ฅผ ๊ฒ์ฌ
- trigger 1๊ฐ ๋งค์นญ๋น 10์ ๊ฐ์ฐ
- ์ ์ ๋ด๋ฆผ์ฐจ์์ผ๋ก ์ ๋ ฌํ์ฌ ์ต๋ 5๊ฐ(
MAX_SKILLS_PER_SESSION) ๋ฐํ
์ธ์ ์บ์ฑ โ ์ค๋ณต ์ฃผ์ ๋ฐฉ์ง
const injectedCacheFallback = new Map(); // sessionId โ Set<skillPath>- ํ ์ธ์ ์์ ์ด๋ฏธ ์ฃผ์ ๋ Skill์ ๋ค์ ์ฃผ์ ํ์ง ์๋๋ค
session_id๋ณ๋ก ์ฃผ์ ๋ Skill ๊ฒฝ๋ก์Set์ ์ ์ง- ๊ฐ์ ์ธ์ ์์ ๊ฐ์ trigger๋ฅผ ๋ฐ๋ณต ์ ๋ ฅํด๋ context๊ฐ ๋ถํ์ํ๊ฒ ์ปค์ง์ง ์์
Bridge vs Fallback ์ํคํ ์ฒ
graph TB SI["skill-injector.mjs"] --> Try{"dist/hooks/skill-bridge.cjs ๋ก๋ ์๋"} Try -->|"์ฑ๊ณต"| Bridge["Bridge ๋ชจ๋"] Try -->|"์คํจ"| Fallback["Fallback ๋ชจ๋"] Bridge --> R1["RECURSIVE ๋๋ ํ ๋ฆฌ ํ์"] Bridge --> R2["์์ ์บ์ฑ"] Fallback --> F1["NON-RECURSIVE ํ์"] Fallback --> F2["์ธ๋ฉ๋ชจ๋ฆฌ ์บ์ฑ (์ธ์ ํ์ )"]
- Bridge ๋ชจ๋: ์ปดํ์ผ๋
skill-bridge.cjs๋ฒ๋ค์ ์ฌ์ฉ. ์ฌ๊ท์ ๋๋ ํ ๋ฆฌ ํ์, ์์ ์บ์ฑ ์ง์ - Fallback ๋ชจ๋: Bridge ๋ก๋ ์คํจ ์ ์ธ๋ผ์ธ ๊ตฌํ ์ฌ์ฉ. ๋น์ฌ๊ท ํ์, ์ธ๋ฉ๋ชจ๋ฆฌ ์บ์ฑ๋ง ์ง์
- Fallback์ ํ์ ํธํ์ฑ์ ์ํ ๊ฒ์ผ๋ก, ๊ธฐ๋ฅ์ ์ผ๋ก๋ ๋์ผํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํ
์ถ๋ ฅ ํ์ โ <mnemosyne> ํ๊ทธ
formatSkillsMessage()๊ฐ ๋งค์นญ๋ Skill๋ค์ ์๋ ํ์์ผ๋ก ๋ํํ๋ค:
<mnemosyne>
<skill-metadata>
{
"name": "pr-creator",
"path": ".omc/skills/pr-creator.md",
"triggers": ["PR ์ค๋น", "PR ready"],
"score": 20,
"scope": "project"
}
</skill-metadata>
Skill ๋ณธ๋ฌธ ๋ด์ฉ...
---
</mnemosyne><mnemosyne>๋ ๊ทธ๋ฆฌ์ค ์ ํ์ ๊ธฐ์ต์ ์ฌ์ ๋ฏ๋ค๋ชจ์๋ค์์ ๋ฐ์จ ์ด๋ฆ์ด๋ค. OMC์์๋ โClaude๊ฐ ๊ธฐ์ตํด์ผ ํ ํ์ต๋ ์ง์โ์ ๊ฐ์ธ๋ OMC ์์ฒด ์ปจ๋ฒค์
์ผ๋ก ์ฌ์ฉํ๋ค. Claude Code๊ฐ ๊ณต์์ผ๋ก ์ ๊ณตํ๋ ๊ฒ์ additionalContext ๋ฌธ์์ด ํ๋๋ฟ์ด๋ฉฐ, ๊ทธ ์์ ์ด๋ค ํ์์ ์ฌ์ฉํ ์ง๋ ํ๋ฌ๊ทธ์ธ์ด ์์ ๋กญ๊ฒ ๊ฒฐ์ ํ๋ค. OMC๋ XML ํ๊ทธ ํ์์ ์ ํํ์ฌ Claude๊ฐ ๊ฒฝ๊ณ๋ฅผ ์ธ์ํ๊ธฐ ์ฝ๊ฒ ํ๋ค.
<skill-metadata>์ ๋งค์นญ ์ ๋ณด๋ฅผ JSON์ผ๋ก ํฌํจํ์ฌ ๋๋ฒ๊น ๊ฐ๋ฅ- ๋ณต์ Skill ๋งค์นญ ์
---๊ตฌ๋ถ์๋ก ๋ถ๋ฆฌ
keyword-detector.mjs์์ ์ถ๋ ฅ ํ์ ์ฐจ์ด:
| keyword-detector.mjs | skill-injector.mjs | |
|---|---|---|
| ๋ํ | ์์ (ํ๋ฌธ ์ง์) | <mnemosyne> ํ๊ทธ |
| ๋ชฉ์ | โ์ด Skill์ ์คํํ๋ผโ ๋ช ๋ น | โ์ด ์ง์์ ์ฐธ๊ณ ํ๋ผโ ์ปจํ ์คํธ |
| ์์ | [MAGIC KEYWORD: ULTRAWORK] | <mnemosyne><skill-metadata>...</mnemosyne> |
์๋ฌ ์ฒ๋ฆฌ
๋ชจ๋ ์๋ฌ๋ gracefulํ๊ฒ ์ฒ๋ฆฌ๋๋ค:
// ์ด๋ค ์๋ฌ๊ฐ ๋ฐ์ํด๋ Claude Code ์งํ์ ์ฐจ๋จํ์ง ์์
console.log(JSON.stringify({ continue: true, suppressOutput: true }));- Skill ํ์ผ ์ฝ๊ธฐ ์คํจ, JSON ํ์ฑ ์๋ฌ ๋ฑ ๋ชจ๋ ์์ธ์์
{ continue: true }๋ฐํ suppressOutput: true๋ก verbose ๋ชจ๋์์๋ ์๋ฌ ๋ ธ์ด์ฆ๋ฅผ ์จ๊น- Hook ์คํฌ๋ฆฝํธ๋ ๋ณด์กฐ ๊ธฐ๋ฅ์ด๋ฏ๋ก, ์คํจํด๋ ๋ณธ ์์ ์ด ์ค๋จ๋๋ฉด ์ ๋๋ค
์ฐธ๊ณ ๋ฌธ์
- skill-injector.mjs ์์ค
- OMC - Hook System โ Hook ์์คํ ์ ์ฒด ๊ตฌ์กฐ
- OMC - Keyword Detector โ ๊ฐ์ ์ด๋ฒคํธ์ ์ฒซ ๋ฒ์งธ ์คํฌ๋ฆฝํธ