์ด ๋ฌธ์„œ๋Š” 2ํŽธ Hook System์˜ ํ•˜์œ„ ๊ฐœ๋…์œผ๋กœ, 18๊ฐœ Hook ์Šคํฌ๋ฆฝํŠธ ์ค‘ keyword-detector.mjs๋ฅผ ๋‹ค๋ฃฌ๋‹ค.


  • keyword-detector.mjs๋Š” UserPromptSubmit Hook์—์„œ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๋ฐ›์•„ ๋งค์ง ํ‚ค์›Œ๋“œ๋ฅผ ๊ฐ์ง€ํ•˜๊ณ , ํ•ด๋‹น Skill ํ˜ธ์ถœ ์ง€์‹œ๋ฅผ Claude context์— ์ฃผ์ž…ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ
  • 5๋‹จ๊ณ„ ํŒŒ์ดํ”„๋ผ์ธ: Guard โ†’ Extract โ†’ Sanitize โ†’ Match โ†’ Output
  • 14๊ฐœ ํ‚ค์›Œ๋“œ๋ฅผ ๊ฐ์ง€ํ•˜๋ฉฐ, ๋ณต์ˆ˜ ํ‚ค์›Œ๋“œ ์ถฉ๋Œ ์‹œ ์šฐ์„ ์ˆœ์œ„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ด๊ฒฐ

์ž‘์„ฑ์ผ: 2026-03-14 ์†Œ์Šค: keyword-detector.mjs

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

  • ์‚ฌ์šฉ์ž๊ฐ€ โ€œultraworkโ€, โ€œralphโ€ ๊ฐ™์€ ๋งค์ง ํ‚ค์›Œ๋“œ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด OMC๊ฐ€ ์ด๋ฅผ ๊ฐ์ง€ํ•ด์„œ ์ ์ ˆํ•œ Skill์„ ๋กœ๋“œํ•ด์•ผ ํ•œ๋‹ค
  • Claude Code ์ž์ฒด์—๋Š” ํ‚ค์›Œ๋“œ ๊ฐ์ง€ ๊ธฐ๋Šฅ์ด ์—†์œผ๋ฏ€๋กœ, UserPromptSubmit Hook์— ์ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋“ฑ๋กํ•˜์—ฌ ์ฒ˜๋ฆฌํ•œ๋‹ค
  • ์ด ์Šคํฌ๋ฆฝํŠธ๋Š” hooks.json์—์„œ UserPromptSubmit ์ด๋ฒคํŠธ์˜ ์ฒซ ๋ฒˆ์งธ ์Šคํฌ๋ฆฝํŠธ๋กœ ๋“ฑ๋ก๋˜์–ด ์žˆ์–ด, ๋ชจ๋“  ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ๋Œ€ํ•ด ๊ฐ€์žฅ ๋จผ์ € ์‹คํ–‰๋œ๋‹ค

AS-IS

sequenceDiagram
    autonumber
    participant U as User
    participant CC as Claude Code

    U->>CC: "ultrawork refactor the API"
    CC->>CC: "ultrawork"๋ฅผ ์ผ๋ฐ˜ ํ…์ŠคํŠธ๋กœ ์ฒ˜๋ฆฌ
    CC-->>U: ํ‚ค์›Œ๋“œ ๋ฌด์‹œ, ์ผ๋ฐ˜ ์‘๋‹ต

TO-BE

sequenceDiagram
    autonumber
    participant U as User
    participant CC as Claude Code
    box OMC
    participant KD as keyword-detector.mjs
    end

    U->>CC: "ultrawork refactor the API"
    CC->>KD: stdin: { prompt, cwd, session_id }
    KD->>KD: sanitize โ†’ "ultrawork" ๋งค์นญ
    KD->>KD: activateState(.omc/state/ultrawork-state.json)
    KD-->>CC: { additionalContext: "[MAGIC KEYWORD: ULTRAWORK] Skill ํ˜ธ์ถœ ์ง€์‹œ" }
    CC->>CC: Skill tool ํ˜ธ์ถœ โ†’ ultrawork SKILL.md ๋กœ๋“œ

์ „์ฒด ํŒŒ์ดํ”„๋ผ์ธ (ํฐ ๊ทธ๋ฆผ)

graph TD
    A["stdin: JSON"] --> B["1. Guard"]
    B -->|"DISABLE_OMC=1 ๋˜๋Š”<br/>OMC_TEAM_WORKER"| X1["{ continue: true } ์ฆ‰์‹œ ๋ฐ˜ํ™˜"]
    B -->|"ํ†ต๊ณผ"| C["2. Extract"]
    C["extractPrompt()"] --> D["3. Sanitize"]
    D["sanitizeForKeywordDetection()"] --> E["4. Match"]
    E --> F{"๋งค์นญ ๊ฒฐ๊ณผ"}
    F -->|"0๊ฐœ"| X2["{ continue: true } ํŒจ์Šค"]
    F -->|"1๊ฐœ ์ด์ƒ"| G["deduplicate โ†’ resolveConflicts()"]
    G --> H["5. Output"]
    H --> H1["cancel โ†’ clearStateFiles + Skill ํ˜ธ์ถœ"]
    H --> H2["ralph/ultrawork ๋“ฑ โ†’ activateState + Skill ํ˜ธ์ถœ"]
    H --> H3["ultrathink/tdd ๋“ฑ โ†’ ๋ฉ”์‹œ์ง€ ์ง์ ‘ ์ฃผ์ž… (Skill ํ˜ธ์ถœ ์—†์Œ)"]

1. Guard โ€” ์‹คํ–‰ ์กฐ๊ฑด ๊ฒ€์‚ฌ

์Šคํฌ๋ฆฝํŠธ ์ตœ์ƒ๋‹จ์—์„œ ์‹คํ–‰ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜๋Š” 3๊ฐ€์ง€ ๊ฐ€๋“œ:

// Guard 1: ํ™˜๊ฒฝ๋ณ€์ˆ˜๋กœ ์™„์ „ ๋น„ํ™œ์„ฑํ™”
if (process.env.DISABLE_OMC === '1' || _skipHooks.includes('keyword-detector')) {
  return { continue: true };
}
 
// Guard 2: Team Worker ๋‚ด๋ถ€์—์„œ๋Š” ํ‚ค์›Œ๋“œ ๊ฐ์ง€ ๊ธˆ์ง€
// โ†’ "team" ํ‚ค์›Œ๋“œ๊ฐ€ ๋‹ค์‹œ ๊ฐ์ง€๋˜๋ฉด ๋ฌดํ•œ ์Šคํฐ ๋ฃจํ”„ ๋ฐœ์ƒ
if (process.env.OMC_TEAM_WORKER) {
  return { continue: true, suppressOutput: true };
}
 
// Guard 3: ๋นˆ ์ž…๋ ฅ
if (!input.trim()) {
  return { continue: true, suppressOutput: true };
}

Team Worker Guard๋Š” ์‹ค์ œ ๋ฒ„๊ทธ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ๊ฒƒ์ด๋‹ค. Team ๋ชจ๋“œ์—์„œ ์ƒ์„ฑ๋œ worker๊ฐ€ ์‚ฌ์šฉ์ž ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋‹ค์‹œ ๋ฐ›์œผ๋ฉด, โ€œteamโ€์ด๋ผ๋Š” ํ‚ค์›Œ๋“œ๋ฅผ ์žฌ๊ฐ์ง€ํ•˜์—ฌ ๋˜ ๋‹ค๋ฅธ worker๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฌดํ•œ ๋ฃจํ”„์— ๋น ์งˆ ์ˆ˜ ์žˆ๋‹ค.

2. Extract โ€” ํ”„๋กฌํ”„ํŠธ ์ถ”์ถœ

extractPrompt()๋Š” Claude Code๊ฐ€ ๋ณด๋‚ด๋Š” ๋‹ค์–‘ํ•œ JSON ๊ตฌ์กฐ์—์„œ ์‚ฌ์šฉ์ž ํ…์ŠคํŠธ๋ฅผ ์ถ”์ถœํ•œ๋‹ค:

function extractPrompt(input) {
  const data = JSON.parse(input);
  if (data.prompt) return data.prompt;                     // ์ผ๋ฐ˜ ํ˜•ํƒœ
  if (data.message?.content) return data.message.content;  // ๋ฉ”์‹œ์ง€ ํ˜•ํƒœ
  if (Array.isArray(data.parts)) {                         // ๋ฉ€ํ‹ฐํŒŒํŠธ ํ˜•ํƒœ
    return data.parts.filter(p => p.type === 'text').map(p => p.text).join(' ');
  }
  return '';
}

ํŒŒ์‹ฑ ์‹คํŒจ ์‹œ ๋นˆ ๋ฌธ์ž์—ด์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค (fail closed โ€” ์ž˜๋ชป๋œ ์ž…๋ ฅ์—์„œ false positive ๋ฐฉ์ง€).

3. Sanitize โ€” ์˜คํƒ ๋ฐฉ์ง€

sanitizeForKeywordDetection()์€ ํ‚ค์›Œ๋“œ๊ฐ€ ์•„๋‹Œ ๊ณณ์—์„œ์˜ ์˜คํƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด 6๋‹จ๊ณ„๋กœ ํ…์ŠคํŠธ๋ฅผ ์ •๋ฆฌํ•œ๋‹ค:

์ˆœ์„œ์ œ๊ฑฐ ๋Œ€์ƒ์ด์œ 
1XML ํƒœ๊ทธ ๋ธ”๋ก <tag>...</tag>ํ”„๋กฌํ”„ํŠธ ๋‚ด XML ๊ตฌ์กฐ์—์„œ ํ‚ค์›Œ๋“œ ์˜คํƒ
2Self-closing XML <tag />๋™์ผ
3URL https://...URL ๊ฒฝ๋กœ์— ํ‚ค์›Œ๋“œ ํฌํ•จ ๊ฐ€๋Šฅ
4ํŒŒ์ผ ๊ฒฝ๋กœ /foo/bar/baz๊ฒฝ๋กœ์— ํ‚ค์›Œ๋“œ ํฌํ•จ ๊ฐ€๋Šฅ
5์ฝ”๋“œ ๋ธ”๋ก ```...```์ฝ”๋“œ ์•ˆ ํ‚ค์›Œ๋“œ๋Š” ์˜๋„ํ•œ ๋ช…๋ น์ด ์•„๋‹˜
6์ธ๋ผ์ธ ์ฝ”๋“œ `...`๋™์ผ

์˜ˆ: ์‚ฌ์šฉ์ž๊ฐ€ "https://example.com/ultrawork/docs๋ฅผ ๋ด" ๋ผ๊ณ  ์ž…๋ ฅํ•˜๋ฉด, URL์„ ๋จผ์ € ์ œ๊ฑฐํ•˜๋ฏ€๋กœ โ€œultraworkโ€๊ฐ€ ํ‚ค์›Œ๋“œ๋กœ ์˜คํƒ๋˜์ง€ ์•Š๋Š”๋‹ค.

4. Match โ€” ํ‚ค์›Œ๋“œ ๋งค์นญ

14๊ฐœ ํ‚ค์›Œ๋“œ (์šฐ์„ ์ˆœ์œ„ ์ˆœ)

์šฐ์„ ์ˆœ์œ„ํ‚ค์›Œ๋“œํŠธ๋ฆฌ๊ฑฐ ํŒจํ„ด์ถœ๋ ฅ ๋ฐฉ์‹
1cancelcancelomc, stopomcstate ์‚ญ์ œ + Skill ํ˜ธ์ถœ
2ralphralph, don't stop, must complete, until donestate ์ƒ์„ฑ + Skill ํ˜ธ์ถœ
3autopilotautopilot, build me an app, i want a, e2e this ๋“ฑstate ์ƒ์„ฑ + Skill ํ˜ธ์ถœ
4ultraworkultrawork, ulw, uwstate ์ƒ์„ฑ + Skill ํ˜ธ์ถœ
5ccgccg, claude-codex-geminiSkill ํ˜ธ์ถœ
6ralplanralplanSkill ํ˜ธ์ถœ
7deep-interviewdeep interview, ouroborosSkill ํ˜ธ์ถœ
8ai-slop-cleanerai slop, anti slop + action+smell ์กฐํ•ฉSkill ํ˜ธ์ถœ
9tddtdd, test first, red green๋ฉ”์‹œ์ง€ ์ง์ ‘ ์ฃผ์ž…
10code-reviewcode review, review code๋ฉ”์‹œ์ง€ ์ง์ ‘ ์ฃผ์ž…
11security-reviewsecurity review, review security๋ฉ”์‹œ์ง€ ์ง์ ‘ ์ฃผ์ž…
12ultrathinkultrathink, think hard, think deeply๋ฉ”์‹œ์ง€ ์ง์ ‘ ์ฃผ์ž…
13deepsearchdeepsearch, search the codebase, find in codeSkill ํ˜ธ์ถœ
14analyzedeep analyze, deepanalyze๋ฉ”์‹œ์ง€ ์ง์ ‘ ์ฃผ์ž…

๋‘ ๊ฐ€์ง€ ์ถœ๋ ฅ ๋ฐฉ์‹

ํ‚ค์›Œ๋“œ๋Š” ๊ฐ์ง€ ํ›„ ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ์ฒ˜๋ฆฌ๋œ๋‹ค:

Skill ํ˜ธ์ถœ ๋ฐฉ์‹ (cancel~deepsearch): createSkillInvocation()์œผ๋กœ Claude์—๊ฒŒ โ€œ์ด Skill์„ ์‹คํ–‰ํ•˜๋ผโ€๋Š” ์ง€์‹œ๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค.

[MAGIC KEYWORD: ULTRAWORK]
You MUST invoke the skill using the Skill tool:
Skill: oh-my-claudecode:ultrawork

๋ฉ”์‹œ์ง€ ์ง์ ‘ ์ฃผ์ž… ๋ฐฉ์‹ (tdd, code-review, security-review, ultrathink, analyze): Skill ํ˜ธ์ถœ ์—†์ด XML ํƒœ๊ทธ๋กœ ๊ฐ์‹ผ ์ง€์‹œ ๋ฉ”์‹œ์ง€๋ฅผ additionalContext์— ์ง์ ‘ ์ฃผ์ž…ํ•œ๋‹ค.

<tdd-mode>
[TDD MODE ACTIVATED]
Write or update tests first when practical...
</tdd-mode>

ai-slop-cleaner์˜ ํŠน์ˆ˜ํ•œ ๋งค์นญ ๋กœ์ง

๋‹ค๋ฅธ ํ‚ค์›Œ๋“œ๋Š” ๋‹จ์ˆœ ์ •๊ทœ์‹์ด์ง€๋งŒ, ai-slop-cleaner๋Š” 2๊ฐ€์ง€ ์กฐ๊ฑด์˜ ์กฐํ•ฉ์œผ๋กœ ๋งค์นญํ•œ๋‹ค:

// ๋ฐฉ๋ฒ• 1: ๋ช…์‹œ์  ํ‚ค์›Œ๋“œ
/\b(ai[\s-]?slop|anti[\s-]?slop|deslop)\b/
 
// ๋ฐฉ๋ฒ• 2: action + smell ์กฐํ•ฉ
action: clean, refactor, simplify, dedupe, prune ...
smell:  slop, duplicate, dead code, over-abstraction, tech debt ...
// "duplicated code๋ฅผ clean upํ•ด์ค˜" โ†’ action(cleanup) + smell(duplicated) โ†’ ๋งค์นญ

5. Output โ€” ์ถฉ๋Œ ํ•ด๊ฒฐ๊ณผ ์ตœ์ข… ์ถœ๋ ฅ

resolveConflicts() โ€” ์šฐ์„ ์ˆœ์œ„ ํ•ด๊ฒฐ

๋ณต์ˆ˜ ํ‚ค์›Œ๋“œ๊ฐ€ ๋™์‹œ์— ๋งค์นญ๋˜๋ฉด resolveConflicts()๊ฐ€ ์šฐ์„ ์ˆœ์œ„๋กœ ์ •๋ ฌํ•œ๋‹ค:

cancel > ralph > autopilot > ultrawork > ccg > ralplan > ... > analyze
  • cancel์€ ๋ฐฐํƒ€์  โ€” ๋‹ค๋ฅธ ๋ชจ๋“  ํ‚ค์›Œ๋“œ๋ฅผ ๋ฌด์‹œํ•˜๊ณ  cancel๋งŒ ์‹คํ–‰
  • ๋‚˜๋จธ์ง€๋Š” ๊ณต์กด ๊ฐ€๋Šฅ โ€” ์šฐ์„ ์ˆœ์œ„ ์ˆœ์œผ๋กœ ์ •๋ ฌํ•˜์—ฌ ๋ชจ๋‘ ์‹คํ–‰

ralph ํ™œ์„ฑํ™” ์‹œ ultrawork ์ž๋™ ์—ฐ๋™

ralph๊ฐ€ ๊ฐ์ง€๋˜๊ณ  ultrawork๊ฐ€ ์—†์œผ๋ฉด, ultrawork state๋„ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•œ๋‹ค:

if (hasRalph && !hasUltrawork) {
  activateState(directory, prompt, 'ultrawork', sessionId);
}

ralph๋Š” โ€œ์ž‘์—… ์™„๋ฃŒ๊นŒ์ง€ ๋ฉˆ์ถ”์ง€ ๋งˆโ€์ด๊ณ , ultrawork๋Š” โ€œ๋ณ‘๋ ฌ๋กœ ์‹คํ–‰ํ•˜๋ผโ€์ด๋ฏ€๋กœ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ž์—ฐ์Šค๋Ÿฝ๋‹ค.

activateState() โ€” ์ƒํƒœ ํŒŒ์ผ ์ƒ์„ฑ

ralph, autopilot, ultrawork 3๊ฐœ ํ‚ค์›Œ๋“œ๋งŒ ์ƒํƒœ ํŒŒ์ผ์„ ์ƒ์„ฑํ•œ๋‹ค:

.omc/state/sessions/{sessionId}/ultrawork-state.json
{
  "active": true,
  "started_at": "2026-03-14T...",
  "original_prompt": "ultrawork refactor the API",
  "session_id": "abc123",
  "reinforcement_count": 0
}

์ด state ํŒŒ์ผ์€ ๋‚˜์ค‘์— persistent-mode.cjs (Stop Hook)๊ฐ€ ์ฝ์–ด์„œ ์ข…๋ฃŒ๋ฅผ ์ฐจ๋‹จํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

createHookOutput() โ€” Claude Code์— ์ „๋‹ฌ

์ตœ์ข… ๊ฒฐ๊ณผ๋Š” ํ•ญ์ƒ ๊ฐ™์€ ํฌ๋งท์œผ๋กœ stdout์— ์ถœ๋ ฅ๋œ๋‹ค:

{
  "continue": true,
  "hookSpecificOutput": {
    "hookEventName": "UserPromptSubmit",
    "additionalContext": "[MAGIC KEYWORD: ULTRAWORK]\nYou MUST invoke the skill..."
  }
}

์ฐธ๊ณ  ๋ฌธ์„œ