สวัสดีค่าา 👋
EP นี้เป็นหนึ่งในที่เราชอบที่สุดเลย เพราะมันแก้ปัญหาที่ทำให้หัวร้อนมานานมาก
เคยเขียนใน CLAUDE.md ว่า "รัน linter ทุกครั้งหลังแก้ไฟล์" แล้ว Claude ก็... ไม่รัน? หรือรันบ้างไม่รันบ้าง? เดี๋ยวลืมเดี๋ยวไม่ลืม?
Hooks แก้ปัญหานี้ ครั้งเดียวจบ
CLAUDE.md "แนะนำ" แต่ Hooks "บังคับ"
นี่คือความต่างที่สำคัญมาก
CLAUDE.md บอกว่า: "รัน linter หลังแก้ไฟล์นะ"
→ Claude อ่าน → เข้าใจ → ตั้งใจทำ
→ แต่บางครั้งก็ลืม หรือข้ามไปเพราะคิดว่าไม่จำเป็น
→ compliance rate: ~70%
Hook บอกว่า: [รัน linter ทุกครั้งที่ไฟล์ถูกแก้ไข โดยอัตโนมัติ]
→ ไม่ผ่าน Claude เลย ระบบทำเองตรงๆ
→ compliance rate: 100%
CLAUDE.md คือ advisory
Hooks คือ enforcement
ถ้ากฎอะไรต้องเกิดขึ้น 100% ทุกครั้ง จะใส่ใน Hook ไม่ใช่ CLAUDE.md
Hook คืออะไรในเชิงเทคนิค?
Hook คือ script ที่รันอัตโนมัติ เมื่อ Claude Code ทำ action บางอย่าง เช่น เขียนไฟล์ รัน command หรือเริ่ม session
Claude Code มี lifecycle events หลายสิบอย่าง แต่ที่ใช้บ่อยๆ คือ:
PreToolUse → ก่อนที่ Claude จะทำ action (ป้องกัน)
PostToolUse → หลังจาก Claude ทำ action (ตรวจสอบ)
SessionStart → ตอนเริ่ม session
SessionEnd → ตอนจบ session
Stop → ตอน Claude คิดว่าทำเสร็จแล้ว
ตัวอย่าง Hooks ที่ใช้บ่อย
Hook 1: รัน linter หลังแก้ไฟล์
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "npm run lint --fix 2>&1",
"statusMessage": "กำลัง lint..."
}
]
}
]
}
}
ทุกครั้งที่ Claude แก้ไขไฟล์ linter จะรันอัตโนมัติ และ output ของ linter จะถูกส่งกลับไปให้ Claude แก้ต่อเอง ไม่ต้องสั่งเอง
Hook 2: บล็อคคำสั่งอันตราย
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "check-dangerous-commands.sh"
}
]
}
]
}
}
Script check-dangerous-commands.sh:
#!/bin/bash
# รับคำสั่งที่ Claude จะรัน
COMMAND="$CLAUDE_TOOL_INPUT"
# ถ้ามี rm -rf ให้บล็อค
if echo "$COMMAND" | grep -q "rm -rf /"; then
echo "❌ ไม่อนุญาต: rm -rf / อันตรายเกินไป"
exit 2 # exit 2 = บล็อค, exit 1 = แค่เตือน
fi
Hook 3: Auto-commit ตอนจบ session
{
"hooks": {
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "git add -A && git commit -m 'WIP: auto-save session' 2>/dev/null || true"
}
]
}
]
}
}
ไม่ต้องกลัวลืม commit แล้ว
exit codes ต่างกันยังไง?
Hook script สื่อสารกับ Claude ผ่าน exit code:
exit 0 → สำเร็จ ดำเนินการต่อ
exit 1 → มีปัญหา แจ้งเตือน Claude แต่ยังทำต่อได้
exit 2 → บล็อค! หยุดทำทันที Claude ต้องหาทางอื่น
ส่วน output ที่ script พิมพ์ออกมา Claude จะอ่านได้ทั้งหมด เหมือนส่งข้อความกลับไปบอก Claude ว่าเกิดอะไรขึ้น
ทำไมห้ามบล็อคกลางแผน?
มีกฎสำคัญที่ต้องจำ จาก EP.3 เรื่อง Plan-First:
❌ อย่าทำ: Hook บล็อค file write ระหว่างที่ Claude กำลัง implement plan
เพราะ: Claude จะ "หลง" ไม่รู้ว่าตัวเองอยู่ step ไหนของแผน
✅ ทำแบบนี้แทน: ให้ Claude ทำแผนเสร็จก่อน
แล้วค่อยใช้ PostToolUse hook ตรวจสอบทีหลัง
เหมือนให้คนทำงานเสร็จ แล้วค่อย QC ตอนส่งงาน ดีกว่าไปหยุดกลางคันทุกสเต็ป
วิธีตั้งค่า Hooks
Hooks ตั้งค่าได้ใน .claude/settings.json ของโปรเจค:
{
"hooks": {
"PostToolUse": [...],
"PreToolUse": [...],
"SessionEnd": [...]
}
}
หรือใช้คำสั่ง /hooks ใน Claude Code เพื่อ setup แบบ interactive
จริงๆให้ Claude เขียน hook script ให้เราเลยก็ได้นะ พิมพ์ว่า "เขียน hook ที่รัน ESlint หลังทุกครั้งที่แก้ไขไฟล์ .ts ให้หน่อย" หรือ "write a hook that runs ESLint every time a .ts file is modified"
Anti-pattern ที่เจอบ่อย
ลืม chmod +x
# ถ้า script ไม่มี execute permission → hook ไม่ทำงาน (แล้วไม่บอกเราด้วยนะ)
chmod +x .claude/hooks/check-dangerous.sh
ใช้ exit 1 แทน exit 2 ตอนบล็อค
# exit 1 = แค่เตือน Claude ยังทำต่อได้
# exit 2 = บล็อคจริงๆ ใช้อันนี้ถ้าต้องการหยุด
exit 2
matcher case ผิด
// ❌ ผิด
"matcher": "edit|write"
// ✅ ถูก
"matcher": "Edit|Write|MultiEdit"
สรุป
Hooks เป็น "ระบบบังคับให้ทำตามกฎ" สำหรับ workflows
เพื่อให้เรามั่นใจในระดับนึงที่ว่า linter รันทุกครั้ง ไม่มีการ rm -rf / และ code ถูก commit ก่อนปิดคอม
EP ถัดไป: MCP (Model Context Protocol) เชื่อม Claude Code กับโลกภายนอก GitHub, Database, Slack, Figma และอีกกว่า 3,000 integrations
วันนี้ขอบคุณที่อ่านจบนะคะ ขอให้มีวันที่ดีค่าาา
Tags: Claude Code, AI, Hooks, Automation, Developer Tools, Enforcement