์‹œ๋ฆฌ์ฆˆ: oh-my-claudecode ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ถ€ํ„ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ฐœ๋ฐœ๊นŒ์ง€

์ด ์‹œ๋ฆฌ์ฆˆ๋Š” Claude Code ํ”Œ๋Ÿฌ๊ทธ์ธ ์‹œ์Šคํ…œ์˜ ๋‚ด๋ถ€ ๋™์ž‘์„ ๋‹จ๊ณ„๋ณ„๋กœ ํ•ด๋ถ€ํ•˜๊ณ , ์ตœ์ข…์ ์œผ๋กœ ๋‚˜๋งŒ์˜ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ง์ ‘ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒƒ๊นŒ์ง€ ๋„๋‹ฌํ•˜๋Š” ๊ณผ์ •์ด๋‹ค.

ํŽธ๋‚ด์šฉํ•ต์‹ฌ
1ํŽธPlugin Anatomyplugin.json ํ•˜๋‚˜๋กœ ์‹œ์ž‘ํ•˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ ๋ผˆ๋Œ€
2ํŽธ (๋ณธ๋ฌธ)Hook System์ด๋ฒคํŠธ โ†’ stdin JSON โ†’ ์Šคํฌ๋ฆฝํŠธ โ†’ stdout JSON
3ํŽธSkill SystemSKILL.md๋กœ ์›Œํฌํ”Œ๋กœ์šฐ๋ฅผ ์ •์˜ํ•˜๋Š” ๋ฐฉ๋ฒ•
4ํŽธAgent SystemTask tool๋กœ ์œ„์ž„๋˜๋Š” ์‹ค์ œ ์ž‘์—… ์ˆ˜ํ–‰์ž
5ํŽธMCP Tools BridgeLSP, AST ๋“ฑ ์ปค์Šคํ…€ ๋„๊ตฌ ์„œ๋ฒ„
6ํŽธState & Lifecycle.omc/ ์ƒํƒœ ๊ด€๋ฆฌ์™€ ๋ชจ๋“œ ์ง€์†
7ํŽธParallel OrchestrationUltrawork, Team, Autopilot, Ralph ํŒจํ„ด

  • Claude Code Hook System์€ Claude Code๊ฐ€ ๋‚ด๋ถ€ ์ด๋ฒคํŠธ ๋ฐœ์ƒ ์‹œ ์™ธ๋ถ€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ํ–‰๋™์„ ๊ฐ€๋กœ์ฑ„๊ฑฐ๋‚˜ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•˜๋Š” ๊ณต์‹ ์ธํ„ฐํŽ˜์ด์Šค
  • Claude Code๊ฐ€ 21๊ฐ€์ง€ ์ด๋ฒคํŠธ + stdin/stdout JSON ๊ณ„์•ฝ์„ ์ •์˜ํ•˜๊ณ , ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ๊ทธ์— ๋งž๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ฐœ๋ฐœํ•˜์—ฌ ๋“ฑ๋กํ•˜๋Š” 2-๋ ˆ์ด์–ด ๊ตฌ์กฐ
  • ํ•ต์‹ฌ ๊ณ„์•ฝ: stdin JSON in โ†’ stdout JSON out

์ž‘์„ฑ์ผ: 2026-03-14 Claude Code ๊ณต์‹ ๋ฌธ์„œ: https://code.claude.com/docs/en/hooks (21๊ฐœ ์ด๋ฒคํŠธ) OMC ์†Œ์Šค ๋ฒ„์ „: hooks/hooks.json ๊ธฐ์ค€ (11๊ฐœ ์ด๋ฒคํŠธ, 18๊ฐœ ์Šคํฌ๋ฆฝํŠธ ๋“ฑ๋ก)

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

  • Claude Code๋Š” ๊ธฐ๋ณธ ๋„๊ตฌ(Read, Write, Edit, Bash ๋“ฑ)๋งŒ ์ œ๊ณตํ•˜๋ฉฐ, ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ์„ ๊ฐ€๋กœ์ฑ„๊ฑฐ๋‚˜ ์ข…๋ฃŒ๋ฅผ ์ฐจ๋‹จํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์—†๋‹ค
  • ํ”Œ๋Ÿฌ๊ทธ์ธ์ด Claude Code์˜ ๋™์ž‘์— ๊ฐœ์ž…ํ•˜๋ ค๋ฉด, Claude Code๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๊ณต์‹ ์ด๋ฒคํŠธ ํ›… ํฌ์ธํŠธ๋ฅผ ํ†ตํ•ด์•ผ ํ•œ๋‹ค
  • OMC ๊ฐ™์€ ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ์ด Hook ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํ‚ค์›Œ๋“œ ๊ฐ์ง€, ๋ชจ๋“œ ์ง€์†, ์—๋Ÿฌ ๋ณต๊ตฌ ๋“ฑ์„ ๊ตฌํ˜„ํ•œ๋‹ค

AS-IS

sequenceDiagram
    autonumber
    participant U as User
    participant CC as Claude Code

    U->>CC: "ultrawork refactor the API"
    CC->>CC: ๊ธฐ๋ณธ ๋„๊ตฌ๋กœ ์ฒ˜๋ฆฌ
    CC-->>U: ์‘๋‹ต ์™„๋ฃŒ (์ข…๋ฃŒ)
    Note over CC: ํ‚ค์›Œ๋“œ ๊ฐ์ง€ ๋ถˆ๊ฐ€, ์ข…๋ฃŒ ์ฐจ๋‹จ ๋ถˆ๊ฐ€, ๋ชจ๋“œ ๊ฐœ๋… ์—†์Œ

TO-BE

sequenceDiagram
    autonumber
    participant U as User
    participant CC as Claude Code
    box OMC
    participant HK as Hook Script
    end

    U->>CC: "ultrawork refactor the API"
    CC->>HK: UserPromptSubmit ์ด๋ฒคํŠธ (stdin JSON)
    HK->>HK: "ultrawork" ํ‚ค์›Œ๋“œ ๊ฐ์ง€
    HK-->>CC: stdout: { additionalContext: "SKILL ํ˜ธ์ถœ ์ง€์‹œ" }
    CC->>CC: Skill ๋กœ๋“œ โ†’ Agent ์œ„์ž„ โ†’ ๋ณ‘๋ ฌ ์‹คํ–‰
    CC->>HK: Stop ์ด๋ฒคํŠธ (์ข…๋ฃŒ ์‹œ๋„)
    HK-->>CC: { continue: false, decision: "block" } (์•„์ง ์ž‘์—… ์ค‘)
    Note over CC: ์ž‘์—… ์™„๋ฃŒ๊นŒ์ง€ ์ข…๋ฃŒํ•˜์ง€ ์•Š์Œ

Hook ์‹œ์Šคํ…œ์˜ 2-๋ ˆ์ด์–ด ๊ตฌ์กฐ

graph TB
    subgraph Layer2["Layer 2: ํ”Œ๋Ÿฌ๊ทธ์ธ"]
        Scripts["์ด๋ฒคํŠธ์— ๋ฐ˜์‘ํ•  ์Šคํฌ๋ฆฝํŠธ ๊ฐœ๋ฐœ"]
        Register["hooks.json์— ์ด๋ฒคํŠธ๋ณ„ ์Šคํฌ๋ฆฝํŠธ ๋“ฑ๋ก"]
        Logic["๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๊ตฌํ˜„"]
    end

    subgraph Layer1["Layer 1: Claude Code"]
        Events["21๊ฐ€์ง€ Hook ์ด๋ฒคํŠธ ์ •์˜"]
        Contract["stdin/stdout JSON ๊ณ„์•ฝ"]
        HooksJson["hooks.json ๋กœ๋”ฉ & ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰"]
    end

    Logic ~~~ Events

    Events --> HooksJson
    Contract --> HooksJson
    HooksJson -->|"command ์‹คํ–‰, stdin ์ „๋‹ฌ"| Scripts
    Scripts -->|"stdout JSON ๋ฐ˜ํ™˜"| HooksJson
    Register -.->|"๋“ฑ๋ก"| HooksJson

Claude Code๊ฐ€ โ€œ21๊ฐœ์˜ ์ฝ˜์„ผํŠธ(์ด๋ฒคํŠธ)โ€œ๋ฅผ ์ œ๊ณตํ•˜๊ณ , ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ๊ฑฐ๊ธฐ์— ์›ํ•˜๋Š” โ€œ๊ฐ€์ „์ œํ’ˆ(์Šคํฌ๋ฆฝํŠธ)โ€œ์„ ๊ฝ‚๋Š” ๊ตฌ์กฐ. ์ฝ˜์„ผํŠธ ์ž์ฒด๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆœ ์—†์ง€๋งŒ, ๊ฝ‚๋Š” ๊ฑด ์ž์œ ๋‹ค.

ํ†ต์‹  ํ”„๋กœํ† ์ฝœ ์ƒ์„ธ

Hook์˜ ์ž‘๋™ ํ๋ฆ„

sequenceDiagram
    autonumber
    participant CC as Claude Code
    participant HJ as hooks.json
    participant SC as Hook Script (.mjs)

    CC->>CC: ๋‚ด๋ถ€ ์ด๋ฒคํŠธ ๋ฐœ์ƒ (์˜ˆ: UserPromptSubmit)
    CC->>HJ: ํ•ด๋‹น ์ด๋ฒคํŠธ์˜ hook ๋ชฉ๋ก ์กฐํšŒ
    CC->>SC: command ์‹คํ–‰, stdin์œผ๋กœ ์ด๋ฒคํŠธ JSON ์ „๋‹ฌ
    SC->>SC: ์ฒ˜๋ฆฌ (ํ‚ค์›Œ๋“œ ๊ฐ์ง€, ์ƒํƒœ ํ™•์ธ ๋“ฑ)
    SC-->>CC: stdout์œผ๋กœ ์‘๋‹ต JSON ๋ฐ˜ํ™˜
    CC->>CC: ์‘๋‹ต ํ•ด์„ํ•˜์—ฌ ํ–‰๋™ ๊ฒฐ์ •

๊ณตํ†ต stdin ์ž…๋ ฅ (๋ชจ๋“  ์ด๋ฒคํŠธ)

{
  "session_id": "abc123",
  "transcript_path": "/path/to/transcript.jsonl",
  "cwd": "/current/working/directory",
  "permission_mode": "default|plan|acceptEdits|dontAsk|bypassPermissions",
  "hook_event_name": "EventName",
  "agent_id": "optional-subagent-id",
  "agent_type": "optional-agent-name"
}

์ด๋ฒคํŠธ๋ณ„๋กœ tool_name, tool_input, user_prompt, reason ๋“ฑ ์ถ”๊ฐ€ ํ•„๋“œ๊ฐ€ ํฌํ•จ๋œ๋‹ค.

๊ณตํ†ต stdout ์ถœ๋ ฅ (๋ชจ๋“  Hook)

{
  "continue": true,
  "stopReason": "message",
  "suppressOutput": false,
  "systemMessage": "warning"
}
ํ•„๋“œ๊ธฐ๋ณธ๊ฐ’์„ค๋ช…
continuetruefalse๋ฉด Claude๊ฐ€ ์ฒ˜๋ฆฌ ์™„์ „ ์ค‘๋‹จ. ๋ชจ๋“  decision๋ณด๋‹ค ์šฐ์„ 
stopReason์—†์Œcontinue: false์ผ ๋•Œ ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œ (Claude์—๊ฒ ์•ˆ ๋ณด์ž„)
suppressOutputfalsetrue๋ฉด verbose ๋ชจ๋“œ ์ถœ๋ ฅ์—์„œ ์ˆจ๊น€
systemMessage์—†์Œ์‚ฌ์šฉ์ž์—๊ฒŒ ํ‘œ์‹œํ•  ๊ฒฝ๊ณ  ๋ฉ”์‹œ์ง€

์ด๋ฒคํŠธ๋ณ„ hookSpecificOutput

// UserPromptSubmit, SessionStart, SubagentStart, PostToolUseFailure ๋“ฑ
{
  hookSpecificOutput: {
    hookEventName: "UserPromptSubmit",
    additionalContext: "Claude context์— ์ฃผ์ž…ํ•  ํ…์ŠคํŠธ"
  }
}
 
// PreToolUse โ€” ๋„๊ตฌ ์‹คํ–‰ ํ—ˆ์šฉ/์ฐจ๋‹จ/์ˆ˜์ •
{
  hookSpecificOutput: {
    hookEventName: "PreToolUse",
    permissionDecision: "allow" | "deny" | "ask",
    permissionDecisionReason: "์‚ฌ์œ ",
    updatedInput: { field: "์ˆ˜์ •๋œ ๊ฐ’" },
    additionalContext: "Claude์—๊ฒŒ ์ถ”๊ฐ€ ์ปจํ…์ŠคํŠธ"
  }
}
 
// Stop, SubagentStop โ€” ์ข…๋ฃŒ ์ฐจ๋‹จ
{
  continue: false,              // ํ•ต์‹ฌ ํ•„๋“œ: false๋ฉด ์ข…๋ฃŒ ์ฐจ๋‹จ
  decision: "block",            // ๋ณด์กฐ ํ•„๋“œ
  reason: "์ฐจ๋‹จ ์‚ฌ์œ "
}
// ์ข…๋ฃŒ ํ—ˆ์šฉ ์‹œ
{
  continue: true,
  suppressOutput: true
}
 
// PermissionRequest โ€” ๊ถŒํ•œ ์ž๋™ ์Šน์ธ/๊ฑฐ๋ถ€
{
  hookSpecificOutput: {
    hookEventName: "PermissionRequest",
    decision: {
      behavior: "allow" | "deny",
      message: "deny ์‚ฌ์œ "
    }
  }
}

Exit Code ๋™์ž‘

Exit Code๋™์ž‘
0์„ฑ๊ณต, stdout์—์„œ JSON ํŒŒ์‹ฑ
2๋ธ”๋กœํ‚น ์—๋Ÿฌ, stderr๊ฐ€ Claude์—๊ฒŒ ์ „๋‹ฌ, JSON ๋ฌด์‹œ
๊ธฐํƒ€๋น„๋ธ”๋กœํ‚น ์—๋Ÿฌ, ์‹คํ–‰ ๊ณ„์† ์ง„ํ–‰

continue, additionalContext, hookEventName์€ ๋ชจ๋‘ ๊ณต์‹ ํ•„๋“œ

์ด ํ•„๋“œ๋“ค์€ OMC๊ฐ€ ์ž์ฒด ์ •์˜ํ•œ ๊ฒƒ์ด ์•„๋‹ˆ๋ผ Claude Code ๊ณต์‹ ์ธํ„ฐํŽ˜์ด์Šค์˜ ์ผ๋ถ€์ด๋‹ค. ๊ณต์‹ ๋ฌธ์„œ(https://code.claude.com/docs/en/hooks)์— ๋ชจ๋“  ํ•„๋“œ๊ฐ€ ๋ช…์‹œ๋˜์–ด ์žˆ์œผ๋ฉฐ, OMC๋ฅผ ํฌํ•จํ•œ ๋ชจ๋“  ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์ด ๊ณ„์•ฝ์— ๋งž์ถฐ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๊ฐœ๋ฐœํ•œ๋‹ค.

Claude Code ๊ณต์‹ Hook ์ด๋ฒคํŠธ (21๊ฐ€์ง€)

#์ด๋ฒคํŠธ๋ฐœ์ƒ ์‹œ์ OMC ์‚ฌ์šฉ
1SessionStart์„ธ์…˜ ์‹œ์ž‘/์žฌ๊ฐœ ์‹œโœ…
2UserPromptSubmit์‚ฌ์šฉ์ž ํ”„๋กฌํ”„ํŠธ ์ œ์ถœ ์‹œโœ…
3PreToolUse๋„๊ตฌ ์‹คํ–‰ ์ „โœ…
4PermissionRequest๊ถŒํ•œ ๋‹ค์ด์–ผ๋กœ๊ทธ ํ‘œ์‹œ ์‹œโœ…
5PostToolUse๋„๊ตฌ ์„ฑ๊ณต ํ›„โœ…
6PostToolUseFailure๋„๊ตฌ ์‹คํŒจ ํ›„โœ…
7NotificationClaude Code ์•Œ๋ฆผ ๋ฐœ์†ก ์‹œ
8SubagentStart์„œ๋ธŒ์—์ด์ „ํŠธ ์ƒ์„ฑ ์‹œโœ…
9SubagentStop์„œ๋ธŒ์—์ด์ „ํŠธ ์ข…๋ฃŒ ์‹œโœ…
10StopClaude ์‘๋‹ต ์ข…๋ฃŒ ์‹œโœ…
11TeammateIdleํŒ€ ์—์ด์ „ํŠธ๊ฐ€ idle ์ƒํƒœ ์ „ํ™˜ ์‹œ
12TaskCompletedํƒœ์Šคํฌ ์™„๋ฃŒ ํ‘œ์‹œ ์‹œ
13InstructionsLoadedCLAUDE.md/rules ๋กœ๋“œ ์‹œ
14ConfigChange์„ค์ • ํŒŒ์ผ ๋ณ€๊ฒฝ ์‹œ
15WorktreeCreateworktree ์ƒ์„ฑ ์‹œ
16WorktreeRemoveworktree ์ œ๊ฑฐ ์‹œ
17PreCompact์ปจํ…์ŠคํŠธ ์••์ถ• ์ „โœ…
18PostCompact์ปจํ…์ŠคํŠธ ์••์ถ• ํ›„
19ElicitationMCP ์„œ๋ฒ„๊ฐ€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ ์š”์ฒญ ์‹œ
20ElicitationResultMCP elicitation ์‘๋‹ต ํ›„
21SessionEnd์„ธ์…˜ ์ข…๋ฃŒ ์‹œโœ…

OMC๋Š” ์ด ์ค‘ 11๊ฐœ ์ด๋ฒคํŠธ์— ์ปค์Šคํ…€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋“ฑ๋กํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.

hooks.json ๊ตฌ์กฐ

{
  "hooks": {
    "์ด๋ฒคํŠธ์ด๋ฆ„": [
      {
        "matcher": "*",
        "hooks": [
          {
            "type": "command",
            "command": "node \"$CLAUDE_PLUGIN_ROOT\"/scripts/run.cjs ...",
            "timeout": 5
          }
        ]
      }
    ]
  }
}
  • ํ•œ ์ด๋ฒคํŠธ์— ์—ฌ๋Ÿฌ matcher ๋“ฑ๋ก ๊ฐ€๋Šฅ (๋ฐฐ์—ด)
  • ํ•œ matcher์— ์—ฌ๋Ÿฌ hook ๋“ฑ๋ก ๊ฐ€๋Šฅ (์ˆœ์ฐจ ์‹คํ–‰)
  • matcher: "*"๋Š” ๋ชจ๋“  ๊ฒฝ์šฐ์— ์‹คํ–‰, "Bash"๋Š” Bash ๋„๊ตฌ์—๋งŒ ์‹คํ–‰
  • timeout ์ดˆ๊ณผ ์‹œ hook์ด ๋ฌด์‹œ๋˜๊ณ  Claude Code๊ฐ€ ์ •์ƒ ์ง„ํ–‰

OMC hooks.json ์ด๋ฒคํŠธ๋ณ„ ๋“ฑ๋ก ํ˜„ํ™ฉ (18๊ฐœ ์Šคํฌ๋ฆฝํŠธ)

#์ด๋ฒคํŠธmatcher์Šคํฌ๋ฆฝํŠธtimeout์—ญํ• 
1UserPromptSubmit*keyword-detector.mjs5s๋งค์ง ํ‚ค์›Œ๋“œ ๊ฐ์ง€ โ†’ ์Šคํ‚ฌ ์ฃผ์ž…
*skill-injector.mjs3sํ•™์Šต๋œ ์Šคํ‚ฌ ๋งค์นญ โ†’ context ์ฃผ์ž…
2SessionStart*session-start.mjs5s์ดˆ๊ธฐ ์„ค์ •, HUD ์ดˆ๊ธฐํ™”
*project-memory-session.mjs5sํ”„๋กœ์ ํŠธ ๋ฉ”๋ชจ๋ฆฌ ๋กœ๋“œ
initsetup-init.mjs30s์ตœ์ดˆ ์ดˆ๊ธฐํ™” (๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ ๋“ฑ)
maintenancesetup-maintenance.mjs60s์œ ์ง€๋ณด์ˆ˜ (์ƒํƒœ ํŒŒ์ผ ์ •๋ฆฌ ๋“ฑ)
3PreToolUse*pre-tool-enforcer.mjs3sํŒ€ ๋ผ์šฐํŒ…, ์ปจํ…์ŠคํŠธ ์†Œ์ง„ ๊ฐ์ง€
4PermissionRequestBashpermission-handler.mjs5sBash ๋ช…๋ น๋งŒ ์ž๋™ ์Šน์ธ ํŒ๋‹จ
5PostToolUse*post-tool-verifier.mjs3s์—๋Ÿฌ ๋ณต๊ตฌ, ์ปจํ…์ŠคํŠธ ์ฃผ์ž…
*project-memory-posttool.mjs3s๋„๊ตฌ ๊ฒฐ๊ณผ์—์„œ ํ”„๋กœ์ ํŠธ ๋ฉ”๋ชจ๋ฆฌ ํ•™์Šต
6PostToolUseFailure*post-tool-use-failure.mjs3s์‹คํŒจ ์—๋Ÿฌ ๋ณต๊ตฌ ๊ฐ€์ด๋“œ
7SubagentStart*subagent-tracker.mjs start3s์„œ๋ธŒ์—์ด์ „ํŠธ ์‹œ์ž‘ ์ถ”์ 
8SubagentStop*subagent-tracker.mjs stop5s์„œ๋ธŒ์—์ด์ „ํŠธ ์ข…๋ฃŒ ์ถ”์ 
*verify-deliverables.mjs5s์„œ๋ธŒ์—์ด์ „ํŠธ ๊ฒฐ๊ณผ๋ฌผ ๊ฒ€์ฆ
9PreCompact*pre-compact.mjs10s์••์ถ• ์ „ ํ•ต์‹ฌ ์ •๋ณด ๋ณด์กด
*project-memory-precompact.mjs5sํ”„๋กœ์ ํŠธ ๋ฉ”๋ชจ๋ฆฌ ๋ณด์กด
10Stop*context-guard-stop.mjs5s์ปจํ…์ŠคํŠธ ๊ฐ€๋“œ
*persistent-mode.cjs10s๋ชจ๋“œ ์ง€์† โ†’ ์ข…๋ฃŒ ์ฐจ๋‹จ
*code-simplifier.mjs5s์ฝ”๋“œ ๊ฐ„์†Œํ™” ์ฒดํฌ
11SessionEnd*session-end.mjs10s๋ฉ”ํŠธ๋ฆญ ๊ธฐ๋ก, ์ƒํƒœ ์ •๋ฆฌ

hooks.json์—์„œ ์ฝ๋Š” ์„ค๊ณ„ ํŒจํ„ด

์ˆœ์ฐจ ์‹คํ–‰ โ€” ๊ฐ™์€ matcher ์•ˆ์˜ hooks ๋ฐฐ์—ด

๊ฐ™์€ matcher์˜ hooks ๋ฐฐ์—ด์€ ์ˆœ์ฐจ ์‹คํ–‰๋œ๋‹ค.

UserPromptSubmit: keyword-detector.mjs (5s) โ†’ skill-injector.mjs (3s)

ํ‚ค์›Œ๋“œ๋ฅผ ๋จผ์ € ๊ฐ์ง€ํ•œ ๋’ค, ํ•™์Šต๋œ ์Šคํ‚ฌ์„ ๋งค์นญํ•˜๋Š” ์ˆœ์„œ.

matcher๋กœ ์กฐ๊ฑด ๋ถ„๊ธฐ โ€” SessionStart

SessionStart๋งŒ ์œ ์ผํ•˜๊ฒŒ 3๊ฐœ์˜ matcher๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค:

  • * โ€” ํ•ญ์ƒ ์‹คํ–‰ (์„ธ์…˜ ์‹œ์ž‘, ๋ฉ”๋ชจ๋ฆฌ ๋กœ๋“œ)
  • init โ€” ์ดˆ๊ธฐํ™” ์‹œ์—๋งŒ (timeout 30s)
  • maintenance โ€” ์œ ์ง€๋ณด์ˆ˜ ์‹œ์—๋งŒ (timeout 60s๋กœ ๊ฐ€์žฅ ๊ธธ๋‹ค)

ํŠน์ • ๋„๊ตฌ๋งŒ ๊ฐ์‹œ โ€” PermissionRequest

๋‹ค๋ฅธ ์ด๋ฒคํŠธ๋Š” ๋ชจ๋‘ matcher: "*"์ธ๋ฐ, PermissionRequest๋งŒ matcher: "Bash". Bash ๋ช…๋ น ์‹คํ–‰ ๊ถŒํ•œ๋งŒ ์ž๋™ ํŒ๋‹จํ•˜๊ณ , Read/Edit ๋“ฑ ๋‹ค๋ฅธ ๋„๊ตฌ๋Š” ๊ด€์—ฌํ•˜์ง€ ์•Š๋Š”๋‹ค.

Stop ์ด๋ฒคํŠธ๊ฐ€ ๊ฐ€์žฅ ๋ณต์žก โ€” 3๊ฐœ ์Šคํฌ๋ฆฝํŠธ ์ˆœ์ฐจ ์‹คํ–‰

context-guard-stop.mjs โ†’ persistent-mode.cjs โ†’ code-simplifier.mjs

์ข…๋ฃŒ ์‹œ์ ์— ์ปจํ…์ŠคํŠธ ์ƒํƒœ ํ™•์ธ โ†’ ํ™œ์„ฑ ๋ชจ๋“œ๋ฉด ์ข…๋ฃŒ ์ฐจ๋‹จ โ†’ ์ฝ”๋“œ ํ’ˆ์งˆ ์ฒดํฌ๊นŒ์ง€ 3๋‹จ๊ณ„.

์‹คํ–‰ ์ฒด์ธ: scripts/run.cjs

graph LR
    HJ["hooks.json command"] -->|"node run.cjs keyword-detector.mjs"| R["run.cjs"]
    R -->|"process.execPath๋กœ ์Šคํฐ"| KD["keyword-detector.mjs"]
    R -->|"์‹ฌ๋ณผ๋ฆญ ๋งํฌ ํ•ด๊ฒฐ, ์บ์‹œ ๊ฒฝ๋กœ ํ•ด๊ฒฐ"| KD
    KD -->|"stdio: inherit, stdin/stdout ์ „๋‹ฌ"| R

run.cjs๊ฐ€ ํ•„์š”ํ•œ ์ด์œ :

  • ํฌ๋กœ์Šค ํ”Œ๋žซํผ ์ง€์› (Windows์—์„œ sh ๋Œ€์‹  Node.js ์‚ฌ์šฉ)
  • ํ”Œ๋Ÿฌ๊ทธ์ธ ์บ์‹œ ๊ฒฝ๋กœ ํ•ด๊ฒฐ (stale $CLAUDE_PLUGIN_ROOT ๋Œ€์‘)
  • Node ๋ฐ”์ด๋„ˆ๋ฆฌ ๊ฒฝ๋กœ ์ž๋™ ํƒ์ง€

Hook ์Šคํฌ๋ฆฝํŠธ ํŒจํ„ด

๋ชจ๋“  hook ์Šคํฌ๋ฆฝํŠธ๋Š” ๊ฐ™์€ ํŒจํ„ด์„ ๋”ฐ๋ฅธ๋‹ค:

// scripts/my-hook.mjs
import { readStdin } from './lib/stdin.mjs';
 
async function main() {
  // 1. stdin์—์„œ JSON ์ฝ๊ธฐ
  const input = await readStdin();
  const data = JSON.parse(input);
 
  // 2. ์ฒ˜๋ฆฌ (์ด๋ฒคํŠธ ๋ฐ์ดํ„ฐ ๋ถ„์„, ํŒ๋‹จ)
  const prompt = data.prompt || '';
 
  // 3. stdout์œผ๋กœ JSON ์‘๋‹ต
  if (/* ์กฐ๊ฑด ์ถฉ์กฑ */) {
    console.log(JSON.stringify({
      continue: true,
      hookSpecificOutput: {
        hookEventName: 'UserPromptSubmit',
        additionalContext: '์ฃผ์ž…ํ•  ํ…์ŠคํŠธ'
      }
    }));
  } else {
    console.log(JSON.stringify({ continue: true }));
  }
}
 
main();

์ฐธ๊ณ  ๋ฌธ์„œ