๐Ÿš€ Claude Code Hooks ์™„๋ฒฝ ๊ฐ€์ด๋“œ: ๊ฐœ๋ฐœ์ž์˜ ์ƒˆ๋กœ์šด ์ŠˆํผํŒŒ์›Œ

anonymousยท2025๋…„ 7์›” 1์ผ
1
post-thumbnail

"๋งค๋ฒˆ ๊ฐ™์€ ์ผ์„ ๋ฐ˜๋ณตํ•˜๋Š” ๊ฒŒ ์ง€๊ฒน๋‹ค๊ณ ? ํด๋กœ๋“œ์—๊ฒŒ ๋งก๊ฒจ๋ฒ„๋ ค!"

์•ˆ๋…•ํ•˜์„ธ์š”, ์ง€์นœ ๊ฐœ๋ฐœ์ž ์—ฌ๋Ÿฌ๋ถ„! ๐Ÿซ  ๋˜ ์˜ค๋Š˜๋„ ์ฝ”๋“œ ์งœ๊ณ , ํ…Œ์ŠคํŠธ ๋Œ๋ฆฌ๊ณ , ํฌ๋งทํŒ…ํ•˜๊ณ , ๋ฐฑ์—…ํ•˜๊ณ ... ๋์—†๋Š” ๋ฐ˜๋ณต์˜ ๋Šช์—์„œ ํ—ˆ์šฐ์ ๊ฑฐ๋ฆฌ๊ณ  ๊ณ„์‹ ๊ฐ€์š”?

"์•„, ์ด๋Ÿฐ ๊ท€์ฐฎ์€ ์ผ๋“ค์„ ํด๋กœ๋“œ๊ฐ€ ์•Œ์•„์„œ ํ•ด์คฌ์œผ๋ฉด..."

๊ทธ๋Ÿฐ ์—ฌ๋Ÿฌ๋ถ„์„ ์œ„ํ•œ ๊ฒŒ์ž„ ์ฒด์ธ์ €๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค! ๋ฐ”๋กœ Claude Code Hooks์ž…๋‹ˆ๋‹ค. ์ด ๋งˆ๋ฒ• ๊ฐ™์€ ๊ธฐ๋Šฅ์œผ๋กœ ํด๋กœ๋“œ๋ฅผ ์—ฌ๋Ÿฌ๋ถ„๋งŒ์˜ ์™„๋ฒฝํ•œ ๊ฐœ๋ฐœ ์–ด์‹œ์Šคํ„ดํŠธ๋กœ ๋ณ€์‹ ์‹œ์ผœ ๋ณด์„ธ์š”.

๋งˆ์น˜ ์ถฉ์‹คํ•œ ๋ฐ˜๋ ค๊ฒฌ์„ ํ›ˆ๋ จ์‹œํ‚ค๋“ฏ, ํด๋กœ๋“œ์—๊ฒŒ "ํŒŒ์ผ ์ €์žฅํ•˜๋ฉด ์ž๋™์œผ๋กœ ํฌ๋งทํŒ…ํ•ด!", "์œ„ํ—˜ํ•œ ๋ช…๋ น์–ด๋Š” ์ ˆ๋Œ€ ์‹คํ–‰ํ•˜์ง€ ๋งˆ!", "์ž‘์—… ๋๋‚˜๋ฉด ์•Œ๋ฆผ ๋ณด๋‚ด์ค˜!" ๊ฐ™์€ ํŠน๋ณ„ํ•œ ์ง€์‹œ๋ฅผ ๋‚ด๋ฆด ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ค๋Š˜์€ ์—ฌ๋Ÿฌ๋ถ„์˜ ๊ฐœ๋ฐœ ์ƒ์‚ฐ์„ฑ์„ 10๋ฐฐ ํ–ฅ์ƒ์‹œํ‚ฌ Claude Code Hooks์˜ ๋ชจ๋“  ๊ฒƒ์„ ํŒŒํ—ค์ณ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค! ๐ŸŽฏ

๐Ÿ“œ ์˜ค๋Š˜์˜ ํฌ์ŠคํŒ… ๋ชฉ์ฐจ

  1. Hooks๊ฐ€ ๋Œ€์ฒด ๋ญ”๊ฐ€์š”? (feat. ๋‚š์‹œ๋ฐ”๋Š˜์˜ ๋น„์œ )
  2. ๋‚ด ์ฒซ Hook ๋งŒ๋“ค๊ธฐ: "ํด๋กœ๋“œ, ๋„ˆ์˜ ๋ชจ๋“  ๊ฒƒ์„ ๊ธฐ๋กํ•ด!"
  3. Hooks ํ™œ์šฉ ๋ ˆ์‹œํ”ผ: ์ด๋Ÿฐ ๊ฒƒ๊นŒ์ง€ ๋œ๋‹ค๊ณ ?
    • ๋ ˆ์‹œํ”ผ 1: ๊ท€์ฐจ๋‹ˆ์ฆ˜์„ ์œ„ํ•œ ์ž๋™ ์ฝ”๋“œ ์ •๋ฆฌ์˜ ๋‹ฌ์ธ
    • ๋ ˆ์‹œํ”ผ 2: ๋“ ๋“ ํ•œ ์ˆ˜ํ˜ธ์ฒœ์‚ฌ, ์ž๋™ ๋ฐฑ์—… & Git ์ปค๋ฐ‹
    • ๋ ˆ์‹œํ”ผ 3: "๋‚˜ ์—ฌ๊ธฐ ์žˆ์–ด์š”!" ๋‚˜๋งŒ์˜ ์•Œ๋ฆผ ์‹œ์Šคํ…œ
  4. ๐Ÿšจ ์ด๊ฒƒ๋งŒ์€ ๊ผญ! Hooks ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ (feat. ๋ณด์•ˆ ํ™ฉ๊ธˆ๋ฅ )
  5. ๋งˆ์น˜๋ฉฐ: ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ์ƒ๋ ฅ์„ ์ฝ”๋“œ๋กœ ๋งŒ๋“ค์–ด๋ณด์„ธ์š”!

๐ŸŽฃ Hooks๊ฐ€ ๋Œ€์ฒด ๋ญ”๊ฐ€์š”? (feat. ๋‚š์‹œ๋ฐ”๋Š˜์˜ ๋น„์œ )

Hook์€ ์˜์–ด๋กœ '๋‚š์‹œ๋ฐ”๋Š˜'์ด๋‚˜ '๊ฐˆ๊ณ ๋ฆฌ'๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฆ„ ๊ทธ๋Œ€๋กœ, ํ”„๋กœ๊ทธ๋žจ์˜ ํŠน์ • ๋™์ž‘์ด ์ผ์–ด๋‚˜๋Š” ์ˆœ๊ฐ„์„ ๋‚š์•„์ฑ„์„œ(Hooking), ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ํŠน๋ณ„ํ•œ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋Š” ๊ธฐ์ˆ ์ž…๋‹ˆ๋‹ค.

ํด๋กœ๋“œ์˜ ์ž‘์—… ํ๋ฆ„์„ ๊ฐ•๋ฌผ์ด๋ผ๊ณ  ์ƒ์ƒํ•ด ๋ณด์„ธ์š”. ์šฐ๋ฆฌ๋Š” ์ด ๊ฐ•๋ฌผ์— ๋‚š์‹œ๋ฐ”๋Š˜์„ ๋˜์ ธ ๋†“์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • PreToolUse๋ผ๋Š” ๋‚š์‹œ๋ฐ”๋Š˜: ํด๋กœ๋“œ๊ฐ€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ง์ „์ด๋ผ๋Š” ๋ฌผ๊ณ ๊ธฐ๋ฅผ ๋‚š์•„์ฑ•๋‹ˆ๋‹ค.
  • PostToolUse๋ผ๋Š” ๋‚š์‹œ๋ฐ”๋Š˜: ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•œ ์งํ›„๋ผ๋Š” ๋ฌผ๊ณ ๊ธฐ๋ฅผ ๋‚š์•„์ฑ•๋‹ˆ๋‹ค.
  • Stop์ด๋ผ๋Š” ๋‚š์‹œ๋ฐ”๋Š˜: ํด๋กœ๋“œ์˜ ๋ชจ๋“  ์ž‘์—…์ด ๋๋‚˜๋Š” ์ˆœ๊ฐ„์„ ๋‚š์•„์ฑ•๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ๋‚š์•„์ฑˆ ์ˆœ๊ฐ„์—, ์šฐ๋ฆฌ๋Š” ๋ฏธ๋ฆฌ ์ค€๋น„ํ•ด ๋‘” ๋ช…๋ น์–ด(๋ฏธ๋ผ)๋ฅผ ์‹คํ–‰์‹œํ‚ค๋Š” ๊ฑฐ์ฃ . ์ด๊ฒŒ ๋ฐ”๋กœ Hooks์˜ ์ „๋ถ€์ž…๋‹ˆ๋‹ค! ๊ฐ„๋‹จํ•˜์ฃ ?

Hooks, ์™œ ์จ์•ผ ํ• ๊นŒ์š”? ํ•œ๋งˆ๋””๋กœ...

"ํ”„๋กฌํ”„ํŠธ์— ๋งค๋ฒˆ ์ง€์‹œํ•  ์ผ์„, ์ฝ”๋“œ๋กœ ์ž๋™ํ™”ํ•˜์—ฌ ์‹ค์ˆ˜๋ฅผ ์—†์• ๊ณ  ์ƒ์‚ฐ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•˜๊ธฐ ์œ„ํ•ด!"

๋งค๋ฒˆ // ์ด ์ฝ”๋“œ ๋‹ค ์งœ๋ฉด prettier๋กœ ํฌ๋งทํŒ… ํ•ด์ค˜ ๋ผ๊ณ  ์ง€์‹œํ•˜๋Š” ๋Œ€์‹ , ํŒŒ์ผ์ด ์ €์žฅ๋  ๋•Œ๋งˆ๋‹ค ์–ธ์ œ๋‚˜, ํ™•์‹คํ•˜๊ฒŒ ํฌ๋งทํŒ…์„ ์‹คํ–‰ํ•˜๋Š” Hook์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ํ›จ์”ฌ ๋” ๋˜‘๋˜‘ํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

๐Ÿ—๏ธ ๋‚ด ์ฒซ Hook ๋งŒ๋“ค๊ธฐ: "ํด๋กœ๋“œ, ๋„ˆ์˜ ๋ชจ๋“  ๊ฒƒ์„ ๊ธฐ๋กํ•ด!"

์ด๋ก ์€ ๊ทธ๋งŒ! ์ง์ ‘ ๋งŒ๋“ค์–ด๋ณด์ฃ . ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ด๋ฉด์„œ๋„ ์œ ์šฉํ•œ Hook๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๐ŸŽฏ ๋ชฉํ‘œ: ํด๋กœ๋“œ๊ฐ€ ์‹คํ–‰ํ•˜๋Š” ๋ชจ๋“  ๋ช…๋ น์–ด ๊ธฐ๋กํ•˜๊ธฐ

ํด๋กœ๋“œ๊ฐ€ ls, git add, npm install ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ๋กœ๊ทธ ํŒŒ์ผ์— ๊ธฐ๋กํ•ด๋‘๋ฉด, ๋‚˜์ค‘์— "ํด๋กœ๋“œ๊ฐ€ ๋„๋Œ€์ฒด ๋ญ˜ ํ–ˆ์ง€?"๋ผ๊ณ  ๊ถ๊ธˆํ•  ๋•Œ ์‰ฝ๊ฒŒ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“‹ ๋‹จ๊ณ„๋ณ„ ๊ตฌํ˜„

1๋‹จ๊ณ„: Hook ์„ค์ • ๋ฉ”๋‰ด ์—ด๊ธฐ

/hooks

ํด๋กœ๋“œ ์ฑ„ํŒ…์ฐฝ์— ์œ„ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•˜๋ฉด Hook ์„ค์ • ํ™”๋ฉด์ด ์—ด๋ฆฝ๋‹ˆ๋‹ค.

2๋‹จ๊ณ„: Hook ์ด๋ฒคํŠธ ์„ ํƒ

PreToolUse๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค. ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— ๊ธฐ๋กํ•˜๊ณ  ์‹ถ์œผ๋‹ˆ๊นŒ์š”.

3๋‹จ๊ณ„: ๊ฐ์‹œํ•  ๋„๊ตฌ ์ง€์ •

+ Add new matcher... ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๊ณ  Bash๋ผ๊ณ  ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค. Bash๋Š” ํด๋กœ๋“œ๊ฐ€ ํ„ฐ๋ฏธ๋„ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

4๋‹จ๊ณ„: ์‹คํ–‰ํ•  ๋ช…๋ น์–ด ์ž‘์„ฑ

์ด์ œ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค! ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌํ•ด์„œ ๋ถ™์—ฌ๋„ฃ์œผ์„ธ์š”.

jq -r '"["$(date -Iseconds)"] \(.tool_input.command) - \(.tool_input.description // "์„ค๋ช… ์—†์Œ")"' >> ~/.claude/bash-command-log.txt

์ด ๋งˆ๋ฒ•์˜ ํ•œ ์ค„์ด ํ•˜๋Š” ์ผ:

  • jq: JSON ๋ฐ์ดํ„ฐ๋ฅผ ์˜ˆ์˜๊ฒŒ ๊ฐ€๊ณตํ•˜๋Š” ๋„๊ตฌ
  • date -Iseconds: ํ˜„์žฌ ์‹œ๊ฐ„์„ ISO ํ˜•์‹์œผ๋กœ ๊ฐ€์ ธ์˜ค๊ธฐ
  • tool_input.command: ํด๋กœ๋“œ๊ฐ€ ์‹คํ–‰ํ•˜๋ ค๋Š” ๋ช…๋ น์–ด
  • tool_input.description: ํด๋กœ๋“œ๊ฐ€ ์ ์€ ์„ค๋ช…
  • >> ~/.claude/bash-command-log.txt: ๋ชจ๋“  ๋‚ด์šฉ์„ ๋กœ๊ทธ ํŒŒ์ผ์— ์ถ”๊ฐ€

5๋‹จ๊ณ„: ์ €์žฅ ๋ฐ ํ…Œ์ŠคํŠธ

User settings์— ์ €์žฅํ•˜๊ณ  ESC๋กœ ๋‚˜์˜จ ๋’ค, ํด๋กœ๋“œ์—๊ฒŒ ๊ฐ„๋‹จํ•œ ๋ช…๋ น์–ด๋ฅผ ์š”์ฒญํ•ด๋ณด์„ธ์š”.

ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์˜ ํŒŒ์ผ ๋ชฉ๋ก์„ ๋ณด์—ฌ์ค˜

๊ทธ๋Ÿฌ๋ฉด ~/.claude/bash-command-log.txt ํŒŒ์ผ์— ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ธฐ๋ก์ด ๋‚จ์„ ๊ฑฐ์˜ˆ์š”:

[2025-07-01T15:03:49Z] ls -la - ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์˜ ํŒŒ์ผ ๋ชฉ๋ก์„ ๋ณด์—ฌ์ค˜

์ถ•ํ•˜ํ•ฉ๋‹ˆ๋‹ค! ๐ŸŽ‰ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฒซ ๋ฒˆ์งธ Hook์ด ์™„์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค!

๐Ÿณ Hooks ํ™œ์šฉ ๋ ˆ์‹œํ”ผ: ์ด๋Ÿฐ ๊ฒƒ๊นŒ์ง€ ๋œ๋‹ค๊ณ ?

์ด์ œ ์ง„์งœ ์žฌ๋ฏธ์žˆ๋Š” ์‹œ๊ฐ„์ž…๋‹ˆ๋‹ค. ์‹ค์ œ ๊ฐœ๋ฐœ์—์„œ ๋ฐ”๋กœ ์จ๋จน์„ ์ˆ˜ ์žˆ๋Š” ์œ ์šฉํ•œ Hook ๋ ˆ์‹œํ”ผ๋“ค์„ ์†Œ๊ฐœํ•ด๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

๐Ÿงน ๋ ˆ์‹œํ”ผ 1: ๊ท€์ฐจ๋‹ˆ์ฆ˜์„ ์œ„ํ•œ ์ž๋™ ์ฝ”๋“œ ์ •๋ฆฌ์˜ ๋‹ฌ์ธ

๊ณ ๋ฏผ: "์ฝ”๋“œ ๋‹ค ์ง  ๋‹ค์Œ์— prettier, black ๊ฐ™์€ ํฌ๋งทํ„ฐ ๋Œ๋ฆฌ๋Š” ๊ฑธ ์ž๊พธ ๊นœ๋นกํ•œ๋‹ค..."

ํ•ด๊ฒฐ์ฑ…: ํŒŒ์ผ ์ €์žฅํ•  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ๊ฐ ์–ธ์–ด์— ๋งž๋Š” ํฌ๋งทํ„ฐ๋ฅผ ์‹คํ–‰ํ•˜๋Š” Hook!

#!/bin/bash
# ํŒŒ์ผ: ~/.claude/hooks/auto-format.sh

input=$(cat)
file_path=$(echo "$input" | jq -r '.tool_input.file_path // empty')
tool_name=$(echo "$input" | jq -r '.tool_name')

# ํŒŒ์ผ ์“ฐ๊ธฐ/์ˆ˜์ • ๋„๊ตฌ๊ฐ€ ์•„๋‹ˆ๋ฉด ์ข…๋ฃŒ
if [[ ! "$tool_name" =~ ^(Write|Edit|MultiEdit)$ ]] || [[ -z "$file_path" ]]; then
    exit 0
fi

# ํŒŒ์ผ ํ™•์žฅ์ž๋ณ„๋กœ ๋‹ค๋ฅธ ํฌ๋งทํ„ฐ ์‹คํ–‰
case "$file_path" in
    *.py)
        if command -v black >/dev/null; then
            black "$file_path"
            echo "โœจ Python ์ฝ”๋“œ ์ •๋ฆฌ ์™„๋ฃŒ: $(basename "$file_path")"
        fi
        ;;
    *.js|*.jsx|*.ts|*.tsx|*.json)
        if command -v prettier >/dev/null; then
            prettier --write "$file_path"
            echo "โœจ JavaScript ์ฝ”๋“œ ์ •๋ฆฌ ์™„๋ฃŒ: $(basename "$file_path")"
        fi
        ;;
    *.go)
        if command -v gofmt >/dev/null; then
            gofmt -w "$file_path"
            echo "โœจ Go ์ฝ”๋“œ ์ •๋ฆฌ ์™„๋ฃŒ: $(basename "$file_path")"
        fi
        ;;
esac

์„ค์ • ๋ฐฉ๋ฒ•:

  • Event: PostToolUse
  • Matcher: Write|Edit|MultiEdit
  • Command: /home/user/.claude/hooks/auto-format.sh

๐Ÿ’พ ๋ ˆ์‹œํ”ผ 2: ๋“ ๋“ ํ•œ ์ˆ˜ํ˜ธ์ฒœ์‚ฌ, ์ž๋™ ๋ฐฑ์—… & Git ์ปค๋ฐ‹

๊ณ ๋ฏผ: "์ค‘์š”ํ•œ ํŒŒ์ผ ์ˆ˜์ •ํ•˜๋‹ค๊ฐ€ ์‹ค์ˆ˜๋กœ ๋‚ ๋ ค๋จน์œผ๋ฉด ์–ด๋–กํ•˜์ง€?"

ํ•ด๊ฒฐ์ฑ…: ํŒŒ์ผ ์ˆ˜์ •ํ•  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ๋ฐฑ์—…ํ•˜๊ณ  Git์— ์ปค๋ฐ‹๊นŒ์ง€!

#!/usr/bin/env python3
# ํŒŒ์ผ: ~/.claude/hooks/auto-backup-commit.py
import json
import sys
import os
import subprocess
from datetime import datetime
from pathlib import Path

def main():
    try:
        input_data = json.load(sys.stdin)
    except json.JSONDecodeError:
        sys.exit(1)

    tool_name = input_data.get("tool_name", "")
    file_path = input_data.get("tool_input", {}).get("file_path")

    # ํŒŒ์ผ ์ˆ˜์ • ๋„๊ตฌ์ด๊ณ  ํŒŒ์ผ์ด ์กด์žฌํ•  ๋•Œ๋งŒ ์‹คํ–‰
    if tool_name not in ["Write", "Edit", "MultiEdit"] or not file_path or not os.path.exists(file_path):
        sys.exit(0)

    # 1. ๋ฐฑ์—… ์ƒ์„ฑ
    backup_dir = Path.home() / ".claude" / "backups" / datetime.now().strftime("%Y-%m-%d")
    backup_dir.mkdir(parents=True, exist_ok=True)

    timestamp = datetime.now().strftime("%H%M%S")
    backup_file = backup_dir / f"{Path(file_path).name}.{timestamp}.bak"

    subprocess.run(["cp", file_path, str(backup_file)])
    print(f"๐Ÿ’พ ๋ฐฑ์—… ์™„๋ฃŒ: {backup_file}")

    # 2. Git ์ปค๋ฐ‹ (Git ์ €์žฅ์†Œ์ธ ๊ฒฝ์šฐ์—๋งŒ)
    if os.path.exists(".git"):
        try:
            # ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์žˆ๋Š”์ง€ ํ™•์ธ
            result = subprocess.run(["git", "diff", "--quiet", "HEAD", "--", file_path], 
                                  capture_output=True)
            if result.returncode != 0:  # ๋ณ€๊ฒฝ์‚ฌํ•ญ ์žˆ์Œ
                subprocess.run(["git", "add", file_path])
                commit_msg = f"[Auto] {Path(file_path).name} ์ˆ˜์ •"
                subprocess.run(["git", "commit", "-m", commit_msg])
                print(f"๐Ÿ“ Git ์ปค๋ฐ‹ ์™„๋ฃŒ: {commit_msg}")
        except Exception as e:
            print(f"Git ์ปค๋ฐ‹ ์‹คํŒจ: {e}", file=sys.stderr)

if __name__ == "__main__":
    main()

๐Ÿ”” ๋ ˆ์‹œํ”ผ 3: "๋‚˜ ์—ฌ๊ธฐ ์žˆ์–ด์š”!" ๋‚˜๋งŒ์˜ ์•Œ๋ฆผ ์‹œ์Šคํ…œ

๊ณ ๋ฏผ: "ํด๋กœ๋“œ๊ฐ€ ์ž…๋ ฅ ๊ธฐ๋‹ค๋ฆด ๋•Œ ์•Œ๋ฆผ์ด ๋„ˆ๋ฌด ์‹ฌ์‹ฌํ•˜๋‹ค..."

ํ•ด๊ฒฐ์ฑ…: ์šด์˜์ฒด์ œ๋ณ„๋กœ ๋‹ค๋ฅธ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ๋˜‘๋˜‘ํ•œ Hook!

#!/usr/bin/env python3
# ํŒŒ์ผ: ~/.claude/hooks/smart-notification.py
import json
import sys
import subprocess
import platform

def send_notification():
    try:
        input_data = json.load(sys.stdin)
    except json.JSONDecodeError:
        sys.exit(1)

    message = input_data.get("message", "ํด๋กœ๋“œ๊ฐ€ ๋‹น์‹ ์„ ์ฐพ๊ณ  ์žˆ์–ด์š”! ๐Ÿ’ญ")
    title = input_data.get("title", "Claude Code")

    system = platform.system().lower()

    try:
        if system == "darwin":  # macOS
            subprocess.run([
                "osascript", "-e",
                f'display notification "{message}" with title "{title}" sound name "Glass"'
            ])
        elif system == "windows":  # Windows
            ps_command = f'''
            Add-Type -AssemblyName System.Windows.Forms;
            $notification = New-Object System.Windows.Forms.NotifyIcon;
            $notification.Icon = [System.Drawing.SystemIcons]::Information;
            $notification.BalloonTipTitle = "{title}";
            $notification.BalloonTipText = "{message}";
            $notification.Visible = $true;
            $notification.ShowBalloonTip(5000);
            Start-Sleep -Seconds 1;
            $notification.Dispose();
            '''
            subprocess.run(["powershell", "-Command", ps_command])
        else:  # Linux
            subprocess.run(["notify-send", title, message])

        print(f"๐Ÿ”” ์•Œ๋ฆผ ์ „์†ก ์„ฑ๊ณต: {message}")
    except Exception as e:
        print(f"์•Œ๋ฆผ ์ „์†ก ์‹คํŒจ: {e}", file=sys.stderr)

if __name__ == "__main__":
    send_notification()

๐Ÿ›ก๏ธ ๋ ˆ์‹œํ”ผ 4: ์œ„ํ—˜ํ•œ ๋ช…๋ น์–ด ์ฐจ๋‹จํ•˜๋Š” ์ˆ˜ํ˜ธ์ž

๊ณ ๋ฏผ: "์‹ค์ˆ˜๋กœ rm -rf๋‚˜ sudo ๊ฐ™์€ ์œ„ํ—˜ํ•œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์–ด๋–กํ•˜์ง€?"

ํ•ด๊ฒฐ์ฑ…: ์œ„ํ—˜ํ•œ ๋ช…๋ น์–ด ํŒจํ„ด์„ ๋ฏธ๋ฆฌ ์ฐจ๋‹จํ•˜๋Š” ๋ณด์•ˆ Hook!

#!/usr/bin/env python3
# ํŒŒ์ผ: ~/.claude/hooks/security-guard.py
import json
import sys
import re

# ์œ„ํ—˜ํ•œ ๋ช…๋ น์–ด ํŒจํ„ด๋“ค
DANGEROUS_PATTERNS = [
    (r"\brm\s+(-rf?|--recursive)", "ํด๋” ๊ฐ•์ œ ์‚ญ์ œ๋Š” ์œ„ํ—˜ํ•˜์—ฌ ์ฐจ๋‹จ๋˜์—ˆ์Šต๋‹ˆ๋‹ค."),
    (r"\bsudo\b", "๊ด€๋ฆฌ์ž ๊ถŒํ•œ ์‹คํ–‰์€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."),
    (r"\bchmod\s+(777|666)", "๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ถŒํ•œ์„ ์ฃผ๋Š” ๊ฒƒ์€ ์œ„ํ—˜ํ•ฉ๋‹ˆ๋‹ค."),
    (r"\bcurl\b.*\|.*(bash|sh)", "์ธํ„ฐ๋„ท ์Šคํฌ๋ฆฝํŠธ ์ง์ ‘ ์‹คํ–‰์€ ๋ณด์•ˆ ์œ„ํ—˜์ด ์žˆ์Šต๋‹ˆ๋‹ค."),
]

def check_dangerous_command():
    try:
        input_data = json.load(sys.stdin)
    except json.JSONDecodeError:
        sys.exit(1)

    if input_data.get("tool_name") != "Bash":
        sys.exit(0)

    command = input_data.get("tool_input", {}).get("command", "")
    if not command:
        sys.exit(0)

    # ์œ„ํ—˜ํ•œ ํŒจํ„ด ๊ฒ€์‚ฌ
    for pattern, message in DANGEROUS_PATTERNS:
        if re.search(pattern, command, re.IGNORECASE):
            print(f"๐Ÿšซ ๋ณด์•ˆ ๊ฒฝ๊ณ : {message}", file=sys.stderr)
            print(f"์ฐจ๋‹จ๋œ ๋ช…๋ น์–ด: {command}", file=sys.stderr)
            sys.exit(2)  # ์ž‘์—… ์ค‘๋‹จ

    print("โœ… ๋ช…๋ น์–ด ์•ˆ์ „์„ฑ ๊ฒ€์‚ฌ ํ†ต๊ณผ")

if __name__ == "__main__":
    check_dangerous_command()

๐ŸŽญ Hook ์ด๋ฒคํŠธ ์™„๋ฒฝ ์ •๋ณต: ์–ธ์ œ, ์–ด๋–ป๊ฒŒ ์‹คํ–‰๋˜๋Š”๊ฐ€?

๊ฐ Hook ์ด๋ฒคํŠธ๊ฐ€ ์–ธ์ œ ์‹คํ–‰๋˜๋Š”์ง€ ์ •ํ™•ํžˆ ์•Œ์•„์•ผ ์ ์ ˆํ•œ Hook์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โšก PreToolUse: "์ž ๊น! ์‹œ์ž‘ํ•˜๊ธฐ ์ „์—..."

์‹คํ–‰ ์‹œ์ : ํด๋กœ๋“œ๊ฐ€ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ง์ „

์ฃผ์š” ์šฉ๋„:

  • ์œ„ํ—˜ํ•œ ๋ช…๋ น์–ด ์ฐจ๋‹จ
  • ํŒŒ์ผ ์ ‘๊ทผ ๊ถŒํ•œ ๊ฒ€์ฆ
  • ์ž‘์—… ์ „ ์‚ฌ์ „ ์ค€๋น„

๋Œ€๋‹ต ๋ฐฉ๋ฒ•:

  • Exit Code 2: ์ž‘์—… ์ค‘๋‹จ
  • JSON: {"decision": "block", "reason": "์ด์œ "}

โœจ PostToolUse: "์ž, ์ด์ œ ๋๋‚ฌ์œผ๋‹ˆ..."

์‹คํ–‰ ์‹œ์ : ํด๋กœ๋“œ๊ฐ€ ๋„๊ตฌ ์‚ฌ์šฉ์„ ์„ฑ๊ณต์ ์œผ๋กœ ๋งˆ์นœ ์งํ›„

์ฃผ์š” ์šฉ๋„:

  • ์ž๋™ ์ฝ”๋“œ ํฌ๋งทํŒ…
  • ๋ฐฑ์—… ํŒŒ์ผ ์ƒ์„ฑ
  • ํ›„์† ์ž‘์—… ์‹คํ–‰

๐Ÿ”” Notification: "ํด๋กœ๋“œ๊ฐ€ ํ•  ๋ง์ด ์žˆ๋Œ€!"

์‹คํ–‰ ์‹œ์ : ํด๋กœ๋“œ๊ฐ€ ์‚ฌ์šฉ์ž ์ž…๋ ฅ์„ ๊ธฐ๋‹ค๋ฆฌ๊ฑฐ๋‚˜ ์•Œ๋ฆผ์„ ๋ณด๋‚ผ ๋•Œ

์ฃผ์š” ์šฉ๋„:

  • ์ปค์Šคํ…€ ์•Œ๋ฆผ ์‹œ์Šคํ…œ
  • ๋‹ค๋ฅธ ์„œ๋น„์Šค๋กœ ์•Œ๋ฆผ ์ „๋‹ฌ (Slack, Discord ๋“ฑ)
  • ์†Œ๋ฆฌ๋‚˜ ์‹œ๊ฐ์  ํšจ๊ณผ ์ถ”๊ฐ€

๐Ÿ›‘ Stop: "์•„์ง ๋๋‚˜์ง€ ์•Š์•˜์–ด!" (๊ณ ๊ธ‰ ๊ธฐ๋Šฅ)

์‹คํ–‰ ์‹œ์ : ํด๋กœ๋“œ์˜ ๋ชจ๋“  ์ž‘์—…์ด ์™„๋ฃŒ๋˜์–ด ๋Œ€ํ™”๊ฐ€ ๋๋‚˜๋ ค๋Š” ์ˆœ๊ฐ„

์ฃผ์š” ์šฉ๋„:

  • ์ตœ์ข… ์ฝ”๋“œ ํ’ˆ์งˆ ๊ฒ€์‚ฌ
  • ์ž๋™ ํ…Œ์ŠคํŠธ ์‹คํ–‰
  • ์ž‘์—… ์™„๋ฃŒ ์ „ ๋งˆ์ง€๋ง‰ ๊ฒ€์ฆ

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ: ์ž˜๋ชป ์‚ฌ์šฉํ•˜๋ฉด ๋ฌดํ•œ ๋ฃจํ”„์— ๋น ์งˆ ์ˆ˜ ์žˆ์œผ๋‹ˆ stop_hook_active ์ฒดํฌ ํ•„์ˆ˜!

๐ŸŒ ๊ณ ๊ธ‰ ๊ธฐ๋Šฅ: MCP, Computer Use, Tool Use์™€์˜ ๋งŒ๋‚จ

๐Ÿ”— MCP (Model Context Protocol) Hooks

MCP๋Š” ํด๋กœ๋“œ๊ฐ€ ์™ธ๋ถ€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค, ํŒŒ์ผ ์‹œ์Šคํ…œ, API ๋“ฑ๊ณผ ์—ฐ๊ฒฐํ•˜๋Š” ํ‘œ์ค€ ํ”„๋กœํ† ์ฝœ์ž…๋‹ˆ๋‹ค.

# MCP ์„œ๋ฒ„ ์ถ”๊ฐ€
claude mcp add-json filesystem '{
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-filesystem", "/safe/directory"],
  "tool_configuration": {
    "allowed_tools": ["read_file", "write_file"]
  }
}'

MCP Hook ์˜ˆ์ œ:

{
  "hooks": {
    "PreToolUse": [{
      "matcher": "mcp__.*",
      "hooks": [{
        "type": "command",
        "command": "echo 'MCP ๋„๊ตฌ ์‚ฌ์šฉ ๊ฐ์ง€' >> ~/.claude/mcp-log.txt"
      }]
    }]
  }
}

๐Ÿ–ฑ๏ธ Computer Use Hooks

Computer Use๋Š” ํด๋กœ๋“œ๊ฐ€ ์‹ค์ œ๋กœ ํ™”๋ฉด์„ ๋ณด๊ณ  ๋งˆ์šฐ์Šค/ํ‚ค๋ณด๋“œ๋ฅผ ์กฐ์ž‘ํ•˜๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

์ฃผ์š” ์•ก์…˜๋“ค:

  • screenshot: ํ™”๋ฉด ์บก์ฒ˜
  • left_click: ๋งˆ์šฐ์Šค ํด๋ฆญ
  • type: ํ…์ŠคํŠธ ์ž…๋ ฅ
  • key: ํ‚ค๋ณด๋“œ ๋‹จ์ถ•ํ‚ค
  • scroll: ์Šคํฌ๋กค
  • left_click_drag: ๋“œ๋ž˜๊ทธ

๐Ÿ› ๏ธ Tool Use Hooks

์™ธ๋ถ€ ๋„๊ตฌ๋“ค๊ณผ์˜ ์—ฐ๋™์„ ๊ด€๋ฆฌํ•˜๋Š” Hook ์‹œ์Šคํ…œ์ž…๋‹ˆ๋‹ค.

def weather_tool_hook(location):
    # Pre-hook: ์ž…๋ ฅ ๊ฒ€์ฆ
    if not validate_location(location):
        return {"error": "Invalid location"}

    # Execution: API ํ˜ธ์ถœ
    weather_data = fetch_weather(location)

    # Post-hook: ์‘๋‹ต ํฌ๋งทํŒ…
    return format_weather_response(weather_data)

๐Ÿšจ ์ด๊ฒƒ๋งŒ์€ ๊ผญ! Hooks ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ธฐ (feat. ๋ณด์•ˆ ํ™ฉ๊ธˆ๋ฅ )

์ž, ์ด์ œ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ์‹œ๊ฐ„์ž…๋‹ˆ๋‹ค. Hooks๋Š” ์—ฌ๋Ÿฌ๋ถ„์˜ ์ปดํ“จํ„ฐ์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ถŒํ•œ์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค. ์ฆ‰, ๊ฐ•๋ ฅํ•œ ๋งŒํผ ์œ„ํ—˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๋œป์ด์ฃ . ์•„๋ž˜ 5๊ฐ€์ง€ ๋ณด์•ˆ ํ™ฉ๊ธˆ๋ฅ ์„ ๋งˆ์Œ์— ์ƒˆ๊ธฐ๊ณ , ์•ˆ์ „ํ•˜๊ฒŒ Hooks๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.

  • ํ™ฉ๊ธˆ๋ฅ  1: ์˜์‹ฌํ•˜๊ณ , ๋˜ ์˜์‹ฌํ•˜์„ธ์š”.
    ์ธํ„ฐ๋„ท์—์„œ ๋ณธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ดํ•ด ์—†์ด ๋ณต์‚ฌ-๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•˜๋Š” ๊ฒƒ์€ ์ง‘์— ๋ชจ๋ฅด๋Š” ์‚ฌ๋žŒ์„ ๋“ค์ด๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฅผ ํ•œ ์ค„ ํ•œ ์ค„ ๋œฏ์–ด๋ณด๊ณ , ์–ด๋–ค ์—ญํ• ์„ ํ•˜๋Š”์ง€ ์™„๋ฒฝํžˆ ์ดํ•ดํ•˜๊ธฐ ์ „์—๋Š” ์ ˆ๋Œ€ ์‹คํ–‰ํ•˜์ง€ ๋งˆ์„ธ์š”.
  • ํ™ฉ๊ธˆ๋ฅ  2: ๋ณ€์ˆ˜๋Š” "ํฐ๋”ฐ์˜ดํ‘œ" ์•ˆ์— ๊ฐ€๋‘์„ธ์š”.
    ์…ธ ์Šคํฌ๋ฆฝํŠธ์—์„œ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•  ๋•, ํ•ญ์ƒ "$MY_VAR" ์ฒ˜๋Ÿผ ํฐ๋”ฐ์˜ดํ‘œ๋กœ ๊ฐ์‹ธ์ฃผ์„ธ์š”. ํŒŒ์ผ ์ด๋ฆ„์— ๊ณต๋ฐฑ์ด ์žˆ๊ฑฐ๋‚˜ ํ•  ๋•Œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜๋งŽ์€ ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ๋ฌธ์ œ๋ฅผ ๋ง‰์•„์ฃผ๋Š” ์ตœ๊ณ ์˜ ๋ฐฉ์–ด๋ง‰์ž…๋‹ˆ๋‹ค.
  • ํ™ฉ๊ธˆ๋ฅ  3: ๋น„๋ฐ€์˜ ๋ฌธ์€ ๊ตณ๊ฒŒ ์ž ๊ทธ์„ธ์š”.
    ์—ฌ๋Ÿฌ๋ถ„์˜ ๋น„๋ฐ€ํ‚ค(.key), ํ™˜๊ฒฝ๋ณ€์ˆ˜ ํŒŒ์ผ(.env), ๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ ํžŒ ํŒŒ์ผ ๋“ฑ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋Š” Hook์ด ์ ˆ๋Œ€ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋ก ๋ง‰์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠน์ • ํŒŒ์ผ์ด๋‚˜ ํด๋” ์ ‘๊ทผ์„ ๋ง‰๋Š” Hook์„ ๊ฐ€์žฅ ๋จผ์ € ๋งŒ๋“ค์–ด ๋‘๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค.
  • ํ™ฉ๊ธˆ๋ฅ  4: ์œ„ํ—˜ํ•œ ๋ช…๋ น์–ด๋Š” ์‚ฌ์šฉ ๊ธˆ์ง€ ๋ชฉ๋ก์„ ๋งŒ๋“œ์„ธ์š”.
    rm -rf (๊ฐ•์ œ ์‚ญ์ œ), sudo (๊ด€๋ฆฌ์ž ๊ถŒํ•œ ์‹คํ–‰), chmod 777 (๋ชจ๋‘์—๊ฒŒ ๋ชจ๋“  ๊ถŒํ•œ ๋ถ€์—ฌ) ๊ฐ™์€ ๋ช…๋ น์–ด๋Š” ์‹œ์Šคํ…œ์„ ํŒŒ๊ดดํ•  ์ˆ˜ ์žˆ๋Š” ๊ฐ•๋ ฅํ•œ ํž˜์„ ๊ฐ€์กŒ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๋ช…๋ น์–ด๋“ค์€ ์•„์˜ˆ ์‹คํ–‰๋  ์ˆ˜ ์—†๋„๋ก ์ฐจ๋‹จํ•˜๋Š” Hook์„ ๋งŒ๋“ค์–ด ๋‘๋ฉด ์•ˆ์‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ํ™ฉ๊ธˆ๋ฅ  5: ํ…Œ์ŠคํŠธ, ํ…Œ์ŠคํŠธ, ๋˜ ํ…Œ์ŠคํŠธ!
    ์ƒˆ๋กœ์šด Hook์€ ๋ฐ˜๋“œ์‹œ ์‹ค์ œ ์ž‘์—… ํ™˜๊ฒฝ์ด ์•„๋‹Œ, Docker ๊ฐ™์€ ๊ฒฉ๋ฆฌ๋œ ๊ฐ€์ƒ ํ™˜๊ฒฝ์—์„œ ์ถฉ๋ถ„ํžˆ ํ…Œ์ŠคํŠธํ•˜์„ธ์š”. ๋‚ด ์†Œ์ค‘ํ•œ ์ปดํ“จํ„ฐ๋Š” ์•ˆ์ „ํ•  ๋•Œ ์ง€ํ‚ค๋Š” ๊ฒ๋‹ˆ๋‹ค.

๐Ÿš€ ๋งˆ์น˜๋ฉฐ: ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ์ƒ๋ ฅ์„ ์ฝ”๋“œ๋กœ ๋งŒ๋“ค์–ด๋ณด์„ธ์š”!

์˜ค๋Š˜ ์šฐ๋ฆฌ๋Š” Claude Code Hooks์˜ ๊ธฐ๋ณธ ๊ฐœ๋…๋ถ€ํ„ฐ ์‹ค์ œ ํ™œ์šฉ๋ฒ•, ๊ทธ๋ฆฌ๊ณ  ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋ณด์•ˆ ๊ทœ์น™๊นŒ์ง€ ํ•จ๊ป˜ ์•Œ์•„๋ดค์Šต๋‹ˆ๋‹ค.

Hooks๋Š” ๋‹จ์ˆœํžˆ ๋ฐ˜๋ณต ์ž‘์—…์„ ์ค„์—ฌ์ฃผ๋Š” ๊ฒƒ์„ ๋„˜์–ด, ์—ฌ๋Ÿฌ๋ถ„์˜ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ๊ณผ ์›Œํฌํ”Œ๋กœ์šฐ ์ž์ฒด๋ฅผ ์—ฌ๋Ÿฌ๋ถ„์˜ ์Šคํƒ€์ผ์— ๋งž๊ฒŒ ์žฌ์ฐฝ์กฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌดํ•œํ•œ ๊ฐ€๋Šฅ์„ฑ์˜ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

  • ๋นŒ๋“œ๊ฐ€ ๋๋‚  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ์Šฌ๋ž™์— ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด๋‚ด๋ณผ๊นŒ์š”?
  • ํŠน์ • ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜๋ฉด, ๊ด€๋ จ๋œ ๋‹ค๋ฅธ ํŒŒ์ผ์„ ์ž๋™์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ๋ณผ๊นŒ์š”?
  • ๋‚ด๊ฐ€ ์ž์ฃผํ•˜๋Š” ์‹ค์ˆ˜๋“ค์„ ๋ฏธ๋ฆฌ ๊ฐ์ง€ํ•˜๊ณ  ๊ฒฝ๊ณ ํ•ด์ฃผ๋Š” Hook์„ ๋งŒ๋“ค์–ด๋ณด๋ฉด ์–ด๋–จ๊นŒ์š”?

์ด์ œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฐจ๋ก€์ž…๋‹ˆ๋‹ค. ์˜ค๋Š˜ ๋ฐฐ์šด ๋‚ด์šฉ์„ ๋ฐ”ํƒ•์œผ๋กœ, ์—ฌ๋Ÿฌ๋ถ„์˜ ๊ฐœ๋ฐœ ์ƒํ™œ์„ ๋”์šฑ ์Šค๋งˆํŠธํ•˜๊ณ  ํŽธ๋ฆฌํ•˜๊ฒŒ ๋งŒ๋“ค์–ด ์ค„ ์ž์‹ ๋งŒ์˜ Hook์„ ๋งŒ๋“ค์–ด ๋ณด์„ธ์š”. ํด๋กœ๋“œ๋ผ๋Š” ๊ฐ•๋ ฅํ•œ ๋น„์„œ๋ฅผ ์—ฌ๋Ÿฌ๋ถ„์˜ ์Šคํƒ€์ผ์— ๋งž๊ฒŒ ๊ธธ๋“ค์ด๋Š” ์žฌ๋ฏธ, ์˜ค๋Š˜๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด ๋ณด์„ธ์š”!

Happy Hacking!


๐Ÿ“š ๋” ๊นŠ์ด ์•Œ์•„๋ณด๊ธฐ

์œ ์šฉํ•œ ์ฐธ๊ณ  ์ž๋ฃŒ

๋„์›€์ด ๋˜๋Š” ๋„๊ตฌ๋“ค

  • jq: JSON ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์˜ ์Šค์œ„์Šค ์•„๋ฏธ ๋‚˜์ดํ”„
  • prettier: JavaScript/TypeScript ์ฝ”๋“œ ํฌ๋งทํ„ฐ
  • black: Python ์ฝ”๋“œ ํฌ๋งทํ„ฐ
  • gofmt: Go ์–ธ์–ด ์ฝ”๋“œ ํฌ๋งทํ„ฐ
  • notify-send: Linux ๋ฐ์Šคํฌํ†ฑ ์•Œ๋ฆผ ๋„๊ตฌ

๐Ÿงšโ€โ™€๏ธ ์šฉ์–ด ์„ค๋ช… (์–ด๋ฆฐ์ด๋„ ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋„๋ก)

์šฉ์–ด์‰ฌ์šด ์„ค๋ช…
HookํŠน์ • ์ƒํ™ฉ์—์„œ ์ž๋™์œผ๋กœ ์‹คํ–‰๋˜๋Š” ๋ช…๋ น์–ด (๋‚š์‹œ ๋ฐ”๋Š˜์ฒ˜๋Ÿผ ํŠน์ • ์‹œ์ ์„ "๋‚š์•„์ฑ„๋Š”" ๊ธฐ๋Šฅ)
PreToolUse๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์ „์— ์‹คํ–‰๋˜๋Š” hook
PostToolUse๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•œ ํ›„์— ์‹คํ–‰๋˜๋Š” hook
Matcher์–ด๋–ค ๋„๊ตฌ์— hook์„ ์ ์šฉํ• ์ง€ ์ •ํ•˜๋Š” ํŒจํ„ด (์ •๊ทœํ‘œํ˜„์‹ ์ง€์›)
Shell Command์ปดํ“จํ„ฐ์—๊ฒŒ ์ง์ ‘ ๋ช…๋ น์„ ๋‚ด๋ฆฌ๋Š” ํ…์ŠคํŠธ
JSON์ปดํ“จํ„ฐ๋“ค์ด ์„œ๋กœ ์ •๋ณด๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํ˜•์‹ (์ •๋ฆฌ์ •๋ˆ๋œ ๋ฉ”๋ชจ์žฅ ๊ฐ™์€ ๊ฒƒ)
Exit Codeํ”„๋กœ๊ทธ๋žจ์ด ๋๋‚  ๋•Œ ๋ณด๋‚ด๋Š” ์ˆซ์ž ์‹ ํ˜ธ (0=์„ฑ๊ณต, 2=์ค‘๋‹จํ•ด์ฃผ์„ธ์š”)
MCPํด๋กœ๋“œ๊ฐ€ ์™ธ๋ถ€ ํ”„๋กœ๊ทธ๋žจ๋“ค๊ณผ ๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๋ฒˆ์—ญ๊ธฐ
Computer Useํด๋กœ๋“œ๊ฐ€ ๋งˆ์šฐ์Šค์™€ ํ‚ค๋ณด๋“œ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜๋Š” ๊ธฐ๋Šฅ
Tool Useํด๋กœ๋“œ๊ฐ€ ๋‹ค์–‘ํ•œ ๋„๊ตฌ๋“ค์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•
Regex๋ณต์žกํ•œ ๊ธ€์ž ํŒจํ„ด์„ ์ฐพ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ํŠน๋ณ„ํ•œ ๊ทœ์น™
Transcriptํด๋กœ๋“œ์™€์˜ ๋Œ€ํ™” ๋‚ด์šฉ์ด ๋ชจ๋‘ ๊ธฐ๋ก๋˜๋Š” ์ผ๊ธฐ์žฅ

๐Ÿ™‹โ€โ™€๏ธ ์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธ (FAQ)

Q: Hook์ด ์‹คํ–‰ ์•ˆ ๋ผ์š”!
A: /hooks ๋ฉ”๋‰ด์—์„œ ์„ค์ •์„ ํ™•์ธํ•˜๊ณ , Ctrl-R๋กœ transcript๋ฅผ ํ™•์ธํ•ด๋ณด์„ธ์š”. ๊ทธ๋ฆฌ๊ณ  ์Šคํฌ๋ฆฝํŠธ ํŒŒ์ผ์˜ ์‹คํ–‰ ๊ถŒํ•œ(chmod +x)๋„ ํ™•์ธํ•ด๋ณด์„ธ์š”.

Q: Hook์ด ๋„ˆ๋ฌด ์ž์ฃผ ์‹คํ–‰๋ผ์„œ annoyingํ•ด์š”.
A: Matcher๋ฅผ ๋” ๊ตฌ์ฒด์ ์œผ๋กœ ์„ค์ •ํ•˜๊ฑฐ๋‚˜, Hook ๋‚ด๋ถ€์— ์กฐ๊ฑด๋ฌธ์„ ์ถ”๊ฐ€ํ•ด์„œ ํŠน์ • ์ƒํ™ฉ์—๋งŒ ์‹คํ–‰๋˜๋„๋ก ๋งŒ๋“ค์–ด๋ณด์„ธ์š”.

Q: Hook์—์„œ ์—๋Ÿฌ๊ฐ€ ๋‚˜๋Š”๋ฐ ์–ด๋–ป๊ฒŒ ๋””๋ฒ„๊น…ํ•˜์ฃ ?
A: Hook ์Šคํฌ๋ฆฝํŠธ ๋งจ ์œ„์— echo "Hook ์‹œ์ž‘: $(date)" >> /tmp/hook-debug.log ๊ฐ™์€ ๋กœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์‹คํ–‰ ์—ฌ๋ถ€๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

Q: ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๋งŒ๋“  Hook์„ ์“ฐ๊ณ  ์‹ถ์–ด์š”.
A: ์ ˆ๋Œ€ ์ดํ•ดํ•˜์ง€ ๋ชปํ•œ ์ฝ”๋“œ๋Š” ์‹คํ–‰ํ•˜์ง€ ๋งˆ์„ธ์š”! ํ•œ ์ค„ ํ•œ ์ค„ ์ฝ์–ด๋ณด๊ณ , ๋ฌด์—‡์„ ํ•˜๋Š”์ง€ ์™„์ „ํžˆ ์ดํ•ดํ•œ ๋‹ค์Œ์— ์‚ฌ์šฉํ•˜์„ธ์š”.

Q: Hook์ด ๋‚ด ์ปดํ“จํ„ฐ๋ฅผ ๋ง๊ฐ€๋œจ๋ฆด ์ˆ˜ ์žˆ๋‚˜์š”?
A: ๋„ค, ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๋ณด์•ˆ ํ™ฉ๊ธˆ๋ฅ ์„ ๊ผญ ์ง€์ผœ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ rm, sudo, chmod ๊ฐ™์€ ๋ช…๋ น์–ด๋Š” ์กฐ์‹ฌํ•˜์„ธ์š”.


์ด ๋ธ”๋กœ๊ทธ ํฌ์ŠคํŠธ๊ฐ€ ๋„์›€์ด ๋˜์…จ๋‚˜์š”? ๋Œ“๊ธ€๋กœ ์—ฌ๋Ÿฌ๋ถ„๋งŒ์˜ ์ฐฝ์˜์ ์ธ Hook ์•„์ด๋””์–ด๋ฅผ ๊ณต์œ ํ•ด์ฃผ์„ธ์š”! ํ•จ๊ป˜ ๋” ์Šค๋งˆํŠธํ•œ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๋งŒ๋“ค์–ด ๋‚˜๊ฐ€์š”! ๐Ÿš€

profile
๊ธฐ์ˆ ๋ธ”๋กœ๊ฑฐ์ž…๋‹ˆ๋‹ค

0๊ฐœ์˜ ๋Œ“๊ธ€