เปลี่ยน Claude Code จากผู้ช่วยที่ต้องคอยเตือน ให้ทำงานตามกฎอัตโนมัติด้วย Hooks
เวลาสั่ง Claude Code ทำงาน เรามักเพิ่มคำแนะนำไว้ท้าย Prompt ว่า
หลังแก้ไฟล์แล้วช่วยรัน Formatter ด้วย ก่อน Commit ช่วยรัน Test ให้เรียบร้อย ห้ามแก้ไฟล์ .env ถ้าทำงานเสร็จแล้วช่วยแจ้งเตือนด้วย
คำแนะนำเหล่านี้ช่วยให้ Claude เข้าใจ Workflow ที่เราต้องการ แต่ยังมีข้อจำกัดสำคัญ เพราะมันเป็นเพียงข้อความที่ Claude ต้องจดจำและตัดสินใจปฏิบัติตาม
หาก Session ยาวขึ้น Context ถูกย่อ งานมีหลายขั้นตอน หรือ Claude มุ่งแก้ปัญหาหลักจนลืมขั้นตอนประกอบ ก็มีโอกาสที่ Formatter จะไม่ถูกรัน Test ไม่ครบ หรือไฟล์ที่ไม่ควรแก้ถูกแตะโดยไม่ได้ตั้งใจ
ถ้าเป็นเรื่องที่ “ควรทำ” เราสามารถเขียนไว้ใน CLAUDE.md
แต่ถ้าเป็นเรื่องที่ “ต้องเกิดขึ้นเมื่อถึงเหตุการณ์นั้น” Claude Code มีเครื่องมืออีกชนิดหนึ่งที่เหมาะกว่า เรียกว่า Hooks
Claude Code Hooks คืออะไร
Hooks คือคำสั่งหรือกระบวนการที่ Claude Code เรียกใช้อัตโนมัติ เมื่อเกิดเหตุการณ์ที่กำหนดไว้ในวงจรการทำงาน
ตัวอย่างเช่น
- ก่อน Claude เรียกใช้เครื่องมือแก้ไฟล์
- หลัง Claude เขียนไฟล์สำเร็จ
- ก่อน Claude รันคำสั่งใน Terminal
- หลังคำสั่งใน Terminal ทำงานเสร็จ
- เมื่อ Claude ต้องการให้ผู้ใช้อนุมัติ
- เมื่อ Claude หยุดตอบ
- เมื่อ Session เริ่มต้นหรือสิ้นสุด
- เมื่อ Claude Code ส่งการแจ้งเตือน
เราไม่ต้องรอให้ Claude “นึกได้” ว่าต้องทำสิ่งนั้น เพราะเมื่อ Event ตรงกับเงื่อนไข Claude Code จะเรียก Hook ที่ตั้งค่าไว้
หลักการจึงแตกต่างกันดังนี้
CLAUDE.md บอก Claude ว่าควรทำงานอย่างไร Hook กำหนดให้กระบวนการบางอย่างถูกรันเมื่อเกิด Event Permission กำหนดว่า Claude ได้รับอนุญาตให้ทำอะไร Sandbox จำกัดขอบเขตระบบที่ Claude เข้าถึงได้
Hooks จึงเหมาะกับงานที่มีเงื่อนไขชัดเจนและตรวจสอบได้ เช่น Format ไฟล์ บันทึก Log ตรวจสอบชื่อ Branch ป้องกันไฟล์สำคัญ หรือแจ้งเตือนเมื่อ Claude ต้องการความสนใจจากเรา
Hooks ช่วยแก้ปัญหาอะไรได้บ้าง
ลองนึกภาพว่าเราตั้งกฎไว้ใน CLAUDE.md ว่า
หลังแก้ไฟล์ JavaScript หรือ TypeScript ต้องรัน Prettier
Claude มักทำตาม แต่กฎนี้ยังเป็นคำแนะนำ
ถ้าเราเปลี่ยนเป็น PostToolUse Hook เมื่อ Claude ใช้เครื่องมือ Edit หรือ Write สำเร็จ ระบบจะเรียก Prettier กับไฟล์นั้นโดยอัตโนมัติ
อีกตัวอย่างหนึ่งคือกฎ
ห้ามแก้ไฟล์ .env
ถ้าเขียนไว้ใน CLAUDE.md Claude จะพยายามไม่แก้ แต่หากต้องการควบคุมให้แน่นขึ้น เราสามารถสร้าง PreToolUse Hook ให้ตรวจสอบเส้นทางไฟล์ก่อนคำสั่งแก้ไขจะเริ่มทำงาน
หากเส้นทางตรงกับ .env Hook สามารถปฏิเสธ Tool Call นั้นก่อนที่ไฟล์จะถูกเปลี่ยนแปลง
นี่คือความแตกต่างระหว่างการเตือนกับการวาง Guardrail
ตำแหน่งสำหรับตั้งค่า Hooks
Hooks สามารถกำหนดไว้ใน Settings หลายระดับ
ใช้กับทุกโปรเจกต์ในเครื่อง
วางไว้ใน
~/.claude/settings.json
เหมาะกับพฤติกรรมส่วนตัวที่ต้องการใช้ทุกที่ เช่น
- แจ้งเตือนเมื่อ Claude รอคำตอบ
- บันทึกคำสั่งที่ Claude เรียกใช้
- ตั้งค่า Workflow ส่วนตัว
- เชื่อมระบบแจ้งเตือนในเครื่อง
ใช้ร่วมกันในโปรเจกต์
วางไว้ใน
.claude/settings.json
ไฟล์นี้สามารถ Commit เข้า Repository เพื่อให้สมาชิกในทีมใช้ Hook ชุดเดียวกันได้
เหมาะกับกฎระดับโปรเจกต์ เช่น
- Format ด้วยเครื่องมือเดียวกัน
- ป้องกัน Directory สำคัญ
- ตรวจสอบก่อน Commit
- บันทึก Audit Log
- เรียกใช้ Script มาตรฐานของทีม
ใช้เฉพาะเครื่องโดยไม่แชร์กับทีม
วางไว้ใน
.claude/settings.local.json
เหมาะกับ Hook ที่ขึ้นอยู่กับโปรแกรมหรือ Path ภายในเครื่องของแต่ละคน
ตัวอย่างเช่น Script แจ้งเตือนเฉพาะเครื่อง หรือคำสั่งที่ต้องอ้างถึงโปรแกรมซึ่งไม่ได้ติดตั้งในเครื่องของสมาชิกทุกคน
Hook แรกที่ควรลอง คือแจ้งเตือนเมื่อ Claude ต้องการเรา
เมื่อมอบหมายงานที่ใช้เวลาหลายขั้นตอน เรามักสลับไปทำงานอื่น แล้วต้องคอยกลับมาดูว่า Claude ทำเสร็จหรือยัง
สามารถใช้ Notification Hook เพื่อแจ้งเตือนเมื่อ Claude ต้องการให้เรากลับมาที่ Terminal
ตัวอย่างสำหรับ macOS ใน ~/.claude/settings.json
{
"hooks": {
"Notification": [
{
"matcher": "idle_prompt",
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"Claude Code รอคำสั่งต่อไป\" with title \"Claude Code\"'"
}
]
}
]
}
}
idle_prompt หมายถึง Claude ทำงานในรอบนั้นเสร็จแล้ว และกำลังรอ Prompt ถัดไป
ถ้าต้องการให้แจ้งเฉพาะตอน Claude รอการอนุมัติ สามารถเปลี่ยน Matcher เป็น
permission_prompt
สำหรับ Linux สามารถใช้ระบบแจ้งเตือนที่รองรับคำสั่ง notify-send
{
"hooks": {
"Notification": [
{
"matcher": "idle_prompt",
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'Claude Code กำลังรอคำสั่งต่อไป'"
}
]
}
]
}
}
ส่วน Windows สามารถกำหนด Command Hook ให้ทำงานผ่าน PowerShell ได้ แต่ควรปรับคำสั่งแจ้งเตือนตามเวอร์ชันของ Windows และระบบ Notification ที่ใช้อยู่
Format ไฟล์อัตโนมัติหลัง Claude แก้โค้ด
หนึ่งใน Hook ที่นำไปใช้ได้ง่ายที่สุดคือการรัน Formatter หลัง Claude แก้ไฟล์
ตัวอย่างต่อไปนี้ใช้ PostToolUse ซึ่งจะทำงานหลังเครื่องมือทำงานสำเร็จ และเลือกเฉพาะ Tool ชื่อ Edit หรือ Write
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_input.file_path' | xargs npx prettier --write"
}
]
}
]
}
}
เมื่อ Claude ใช้ Edit หรือ Write Claude Code จะส่งข้อมูลเกี่ยวกับ Tool Call เข้ามาทาง Standard Input ในรูปแบบ JSON
ส่วนนี้
jq -r '.tool_input.file_path'
ใช้ดึงเส้นทางไฟล์ที่ถูกแก้ไขออกมา แล้วส่งต่อให้
npx prettier --write
ข้อควรระวังคือเครื่องต้องมี jq และโปรเจกต์ต้องสามารถเรียกใช้ Prettier ผ่านคำสั่งดังกล่าวได้
หากโปรเจกต์ใช้คำสั่งอื่น เช่น
pnpm prettier --write
หรือมี Script เฉพาะของทีม ก็ควรเปลี่ยน Command ให้ตรงกับระบบจริง ไม่ควร Copy ตัวอย่างไปใช้โดยไม่ทดสอบ
ไม่ควรรัน Formatter กับไฟล์ทุกชนิด
ตัวอย่างแบบง่ายจะส่งทุกไฟล์ที่ Claude แก้ไปให้ Prettier แต่ในโปรเจกต์จริงอาจมีไฟล์ที่ Prettier ไม่รองรับ หรือไม่ต้องการให้ Formatter แตะต้อง
วิธีที่ปลอดภัยกว่าคือแยก Logic ไปไว้ใน Script
สร้างไฟล์
.claude/hooks/format-edited-file.sh
ตัวอย่างเนื้อหา
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
case "$FILE_PATH" in
*.js|*.jsx|*.ts|*.tsx|*.json|*.css|*.md)
npx prettier --write "$FILE_PATH"
;;
esac
exit 0
จากนั้นทำให้ไฟล์รันได้บน macOS หรือ Linux
chmod +x .claude/hooks/format-edited-file.sh
แล้วลงทะเบียน Hook
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-edited-file.sh"
}
]
}
]
}
}
การใช้ "$CLAUDE_PROJECT_DIR" ช่วยอ้างอิง Root ของโปรเจกต์ได้ชัดเจน แม้ Claude จะเปลี่ยน Working Directory ระหว่างทำงาน
ป้องกัน Claude แก้ไฟล์สำคัญด้วย PreToolUse
สมมติว่าโปรเจกต์มีไฟล์ที่ไม่ต้องการให้ Claude แก้โดยตรง เช่น
.env .env.production .git/ production.config.js database/migrations/
สามารถสร้าง Script ตรวจสอบเส้นทางไฟล์ก่อน Edit หรือ Write
สร้างไฟล์
.claude/hooks/protect-files.sh
แล้วใส่เนื้อหา
#!/bin/bash
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
case "$FILE_PATH" in
*.env|*/.env|*.env.production|*/.env.production)
echo "Blocked: ห้ามแก้ Environment File โดยตรง" >&2
exit 2
;;
*/.git/*)
echo "Blocked: ห้ามแก้ไฟล์ภายใน .git" >&2
exit 2
;;
*/database/migrations/*)
echo "Blocked: ต้องได้รับอนุมัติก่อนแก้ Migration" >&2
exit 2
;;
esac
exit 0
ทำให้ Script รันได้
chmod +x .claude/hooks/protect-files.sh
จากนั้นเพิ่ม PreToolUse Hook
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}
PreToolUse ทำงานก่อน Tool Call จึงเหมาะกับการตรวจสอบและปฏิเสธการกระทำ
เมื่อ Script จบด้วย
exit 2
Claude Code จะ Block การกระทำนั้น และส่งข้อความจาก stderr กลับให้ Claude เห็น เพื่อให้ Claude เปลี่ยนแนวทางทำงาน
จุดที่ต้องระวังคือ Pattern สำหรับตรวจสอบ Path ต้องออกแบบอย่างรอบคอบ ไม่ควรใช้การค้นหาข้อความแบบกว้างจน Block ไฟล์ที่ไม่เกี่ยวข้อง
เช่น การค้นเพียงคำว่า
env
อาจ Block ไฟล์ชื่อ environment.ts โดยไม่ได้ตั้งใจ
Exit Code 1 ไม่ได้หมายถึง Block เสมอไป
คนที่เขียน Shell Script มักคุ้นเคยว่า Exit Code ที่ไม่ใช่ศูนย์หมายถึงเกิดข้อผิดพลาด
แต่สำหรับ Claude Code Hooks ใน Event ส่วนใหญ่ ความหมายที่ต้องจำคือ
exit 0 Hook ทำงานสำเร็จ exit 1 เกิดข้อผิดพลาดแบบไม่ Block การกระทำใน Event ส่วนใหญ่ exit 2 ส่งสัญญาณให้ Block ใน Event ที่รองรับการควบคุม
ดังนั้น หากต้องการสร้าง Guardrail จริง อย่าใช้เพียง
exit 1
แล้วคิดว่า Claude จะหยุด Tool Call เพราะ Claude Code อาจรายงานข้อผิดพลาดของ Hook แต่ยังปล่อยให้การกระทำเดินหน้าต่อ
ควรตรวจสอบเอกสารของ Event ที่ใช้ด้วย เพราะแต่ละ Event มีรายละเอียดของผลลัพธ์และการควบคุมไม่เหมือนกันทั้งหมด
PreToolUse กับ PostToolUse ต่างกันอย่างไร
สอง Event นี้เป็น Event ที่ใช้บ่อยที่สุด แต่มีวัตถุประสงค์ต่างกัน
PreToolUse
ทำงานก่อน Claude ใช้ Tool
เหมาะกับงาน เช่น
- Block คำสั่งที่ไม่อนุญาต
- ป้องกันการแก้ไฟล์
- ตรวจสอบ Path
- ตรวจสอบ Branch ก่อน Push
- ตรวจสอบคำสั่งก่อนรัน
- เพิ่มข้อจำกัดก่อนเกิดการเปลี่ยนแปลง
PostToolUse
ทำงานหลัง Tool ทำงานสำเร็จแล้ว
เหมาะกับงาน เช่น
- Format ไฟล์
- บันทึก Log
- ตรวจสอบผลลัพธ์
- รัน Lint
- เรียก Test ที่เกี่ยวข้อง
- ส่งข้อมูลไปยังระบบ Audit
สิ่งสำคัญคือ PostToolUse ไม่สามารถย้อนกลับ Tool Call ที่เกิดขึ้นไปแล้ว
หาก Claude ลบไฟล์หรือเขียนข้อมูลลงไฟล์สำเร็จแล้ว การที่ Post Hook แจ้งว่าไม่ควรทำ ไม่ได้ทำให้ไฟล์กลับมาเหมือนเดิมโดยอัตโนมัติ
หากต้องการป้องกันการกระทำ ต้องตรวจสอบด้วย PreToolUse
กรองเฉพาะคำสั่ง Git ก่อน Commit
สมมติว่าเราไม่ต้องการรัน Script ตรวจสอบกับคำสั่ง Bash ทุกครั้ง แต่ต้องการให้รันเฉพาะเมื่อ Claude กำลัง Commit
Claude Code รองรับฟิลด์ if สำหรับกรอง Tool Name และ Argument ให้ละเอียดกว่าการใช้ Matcher อย่างเดียว
ตัวอย่าง
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"if": "Bash(git commit *)",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/pre-commit-check.sh"
}
]
}
]
}
}
Hook นี้จะไม่ถูกรันกับ Bash ทุกคำสั่ง แต่จะสนใจ Tool Call ที่ตรงกับรูปแบบ git commit
ตัวอย่าง Script อาจเป็น
#!/bin/bash
cd "$CLAUDE_PROJECT_DIR" || exit 2
echo "Running pre-commit checks..." >&2
pnpm typecheck || {
echo "Blocked: Typecheck failed" >&2
exit 2
}
pnpm lint || {
echo "Blocked: Lint failed" >&2
exit 2
}
exit 0
วิธีนี้ช่วยป้องกัน Claude Commit โค้ดทั้งที่ Typecheck หรือ Lint ยังไม่ผ่าน
อย่างไรก็ตาม ไม่ควรใช้ Hook นี้แทน CI ทั้งหมด เพราะ CI ยังเป็นด่านตรวจสอบกลางที่ทำงานในสภาพแวดล้อมของ Repository และตรวจทุก Commit หรือ Pull Request ได้อย่างเป็นระบบมากกว่า
Hook เหมาะกับการจับปัญหาให้เร็วขึ้นก่อนงานออกจากเครื่อง ส่วน CI คือด่านยืนยันอีกชั้นหนึ่ง
อย่ารัน Test ชุดใหญ่หลังแก้ทุกไฟล์
แนวคิดที่ดูปลอดภัยแต่สร้างปัญหาได้คือ
ทุกครั้งที่ Claude แก้ไฟล์ ให้รัน Test ทั้งหมด
หาก Test Suite ใช้เวลาหลายนาที Claude อาจต้องหยุดรอทุกครั้งที่แก้ไฟล์หนึ่งรายการ ทำให้ Workflow ช้าลงมาก และอาจมี Test หลายชุดรันซ้อนกันโดยไม่จำเป็น
แนวทางที่เหมาะสมกว่าคือแบ่งการตรวจสอบเป็นหลายระดับ
หลังแก้ไฟล์ รัน Formatter หรือ Lint เฉพาะไฟล์ หลังแก้ Feature เสร็จ รัน Test ที่เกี่ยวข้อง ก่อน Commit รัน Typecheck และชุดตรวจสอบหลัก ใน CI รัน Test Suite เต็มรูปแบบ
หากต้องการรันงานที่ใช้เวลานานโดยไม่หยุด Claude สามารถกำหนด Command Hook เป็นแบบ Async ได้
ตัวอย่าง
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/run-related-tests.sh",
"async": true,
"timeout": 300
}
]
}
]
}
}
เมื่อกำหนด
"async": true
Claude Code จะเริ่ม Process ในเบื้องหลังและเดินหน้าทำงานต่อ โดยไม่รอ Hook เสร็จ
แต่ต้องเข้าใจข้อจำกัดสำคัญว่า Async Hook ไม่สามารถ Block การกระทำที่เกิดขึ้นแล้วได้ เพราะ Claude เดินหน้าต่อไปก่อนที่จะได้รับผลลัพธ์
จึงเหมาะกับ
- รัน Test เบื้องหลัง
- ส่ง Log
- แจ้งเตือน
- เรียก External API
- งานวิเคราะห์ที่ไม่ต้องหยุด Workflow
และไม่เหมาะกับ
- ป้องกันการลบไฟล์
- ปฏิเสธคำสั่ง
- ตรวจสอบก่อน Deploy
- Guardrail ที่ต้องตัดสินใจก่อนการกระทำ
ใช้ Stop Hook บังคับให้ Claude ตรวจงานก่อนหยุดได้หรือไม่
Claude Code มี Stop Event ซึ่งทำงานเมื่อ Claude กำลังจะจบรอบการตอบ
เราสามารถใช้ Hook ตรวจสอบว่าเงื่อนไขบางอย่างผ่านหรือยัง และส่งเหตุผลกลับไปให้ Claude ทำงานต่อ
แต่ต้องระวังว่า Stop ไม่ได้หมายถึง “งานทั้งหมดเสร็จแล้ว” เสมอไป
มันทำงานเมื่อ Claude จบการตอบแต่ละรอบ ซึ่งอาจเป็นเพียงการถามคำถาม สรุปแผน หรือรอข้อมูลเพิ่มเติมจากผู้ใช้
ดังนั้นไม่ควรตั้ง Stop Hook ที่รัน Test Suite ขนาดใหญ่ทุกครั้งโดยไม่ตรวจสอบสถานการณ์ เพราะ Claude อาจพยายามหยุดหลายครั้งและ Hook ก็รันซ้ำหลายครั้ง
Stop Hook เหมาะกับ Workflow ที่ควบคุมขอบเขตชัดเจน เช่น Session สำหรับทำ Code Review โดยเฉพาะ หรือกระบวนการอัตโนมัติที่กำหนดผลลัพธ์ไว้แน่นอน
ตรวจสอบ Hooks ที่ตั้งไว้ด้วย /hooks
หลังแก้ settings.json ไม่ควรสรุปทันทีว่า Hook ถูกโหลดแล้ว
ให้เปิด Claude Code และพิมพ์
/hooks
Claude Code จะแสดง Hook ที่ตั้งค่าไว้ โดยจัดกลุ่มตาม Event
เราสามารถตรวจสอบได้ว่า
- Hook อยู่ใน Event ถูกต้องหรือไม่
- Matcher ถูกโหลดหรือไม่
- Command ที่กำหนดคืออะไร
- Hook มาจาก Settings ระดับใด
- มี Hook ซ้ำจากไฟล์อื่นหรือไม่
เมนู /hooks ใช้สำหรับดูการตั้งค่า ไม่ใช่ Editor สำหรับแก้ไขโดยตรง หากต้องการเพิ่ม แก้ หรือลบ Hook ต้องแก้ Settings File หรือสั่ง Claude ให้ช่วยแก้ไฟล์
ทดสอบ Hook แยกจาก Claude ก่อน
ก่อนนำ Hook ที่ Block การทำงานไปใช้จริง ควรทดสอบ Script โดยส่ง JSON จำลองเข้าไป
ตัวอย่างทดสอบ Script ป้องกันไฟล์
echo '{
"tool_name": "Write",
"tool_input": {
"file_path": "/project/.env"
}
}' | .claude/hooks/protect-files.sh
จากนั้นตรวจสอบ Exit Code
echo $?
หาก Script ทำงานถูกต้อง ควรได้ Exit Code ตามที่ออกแบบไว้
บน Windows PowerShell วิธีส่ง Input และตรวจสอบ Exit Code จะแตกต่างจาก Bash จึงควรสร้าง Script และชุดทดสอบให้เหมาะกับระบบปฏิบัติการของทีม
Debug เมื่อ Hook ไม่ทำงาน
หาก Hook ไม่ถูกเรียก ให้ตรวจสอบตามลำดับนี้
ตรวจสอบว่า Hook ถูกโหลดหรือไม่
ใช้
/hooks
ตรวจสอบตำแหน่งไฟล์
ไฟล์ระดับโปรเจกต์ควรอยู่ที่
.claude/settings.json
หรือ
.claude/settings.local.json
ไฟล์ระดับผู้ใช้ควรอยู่ที่
~/.claude/settings.json
ตรวจสอบ JSON
ไฟล์ JSON ไม่รองรับ Comment และไม่ควรมี Comma ต่อท้ายรายการสุดท้าย
ตรวจสอบ Matcher
ชื่อ Tool และ Matcher มีความแตกต่างระหว่างตัวพิมพ์ใหญ่กับตัวพิมพ์เล็ก
Edit
ไม่เหมือนกับ
edit
ตรวจสอบสิทธิ์ของ Script
บน macOS และ Linux อาจต้องรัน
chmod +x .claude/hooks/example.sh
ตรวจสอบ Dependency
หาก Script ใช้ jq, Node.js, Python, pnpm หรือโปรแกรมอื่น ต้องมั่นใจว่าโปรแกรมนั้นอยู่ใน Environment ที่ Hook มองเห็น
เปิด Debug Log
สามารถเริ่ม Claude Code พร้อมระบุไฟล์ Log
claude --debug-file /tmp/claude-hooks.log
แล้วเปิดอีก Terminal เพื่อติดตาม
tail -f /tmp/claude-hooks.log
Debug Log จะช่วยให้เห็นว่า Hook ใดตรงกับ Event คำสั่งใดถูกรัน Exit Code เท่าใด และมีข้อความใน stdout หรือ stderr อย่างไร
Hooks ไม่ควรถูกใช้แทนระบบความปลอดภัยทุกอย่าง
แม้ Hooks จะช่วยสร้าง Guardrail ได้ แต่ไม่ควรถือว่า Hooks คือระบบ Security ที่สมบูรณ์
ตัวอย่างเช่น Script ป้องกัน .env อาจตรวจเฉพาะ Tool Edit และ Write แต่ Claude อาจใช้ Bash Command เพื่อแก้ไฟล์แทน หากเราไม่ได้ตรวจสอบ Bash ด้วย
หรือ Pattern ตรวจ Path อาจพลาดกรณี Relative Path, Symbolic Link หรือ Path Traversal
งานที่มีความเสี่ยงสูงควรใช้หลายชั้นร่วมกัน เช่น
CLAUDE.md บอกหลักการและ Workflow Permissions กำหนดคำสั่งที่อนุญาตหรือปฏิเสธ Hooks ตรวจสอบ Event และเงื่อนไขเฉพาะ Sandbox จำกัด Filesystem และ Network Git เก็บประวัติและย้อนกลับการเปลี่ยนแปลง CI ตรวจสอบงานอีกครั้งก่อน Merge หรือ Deploy
การป้องกันที่ดีไม่ควรขึ้นอยู่กับ Script เล็ก ๆ เพียงไฟล์เดียว
ระวัง Hook ที่นำมาจากคนอื่น
Command Hooks ทำงานด้วยสิทธิ์ของผู้ใช้ที่กำลังรัน Claude Code
หมายความว่า Script สามารถอ่าน แก้ หรือลบไฟล์ที่บัญชีผู้ใช้นั้นเข้าถึงได้
จึงไม่ควร Copy Hook จาก Internet หรือ Plugin ที่ไม่ทราบที่มา แล้วเปิดใช้งานทันที
ก่อนใช้ควรตรวจสอบว่า
- Script อ่าน Input อะไร
- ส่งข้อมูลออกไปที่ใด
- มีการเรียก Network หรือไม่
- เข้าถึง Environment Variable ใด
- มีคำสั่งลบหรือเขียนไฟล์หรือไม่
- รับ Path จาก Input โดยไม่ตรวจสอบหรือไม่
- Quote Shell Variable ถูกต้องหรือไม่
- ใช้ Absolute Path หรือ Project Path ชัดเจนหรือไม่
โดยเฉพาะ Script ที่นำค่าจาก Prompt, File Path หรือ Tool Input ไปต่อเป็น Shell Command โดยตรง อาจเปิดช่องให้เกิด Command Injection ได้
Hooks ที่ดีควรเล็ก ชัดเจน และทดสอบได้
Hook ที่ดีไม่ควรทำทุกอย่างใน Script เดียว
แทนที่จะสร้าง Hook หนึ่งตัวที่ Format, Lint, Test, Commit, Push และ Deploy ควรแยกตามหน้าที่ เช่น
format-edited-file.sh รับผิดชอบ Format ไฟล์ protect-files.sh รับผิดชอบป้องกันไฟล์ pre-commit-check.sh รับผิดชอบตรวจสอบก่อน Commit notify-complete.sh รับผิดชอบส่งการแจ้งเตือน
ข้อดีคือ
- ทดสอบแต่ละส่วนได้ง่าย
- หา Error ได้เร็ว
- ปิด Hook บางตัวได้โดยไม่กระทบทั้งหมด
- สมาชิกทีมเข้าใจหน้าที่ของ Script
- ลดความเสี่ยงจาก Side Effect ที่คาดไม่ถึง
เริ่มจาก 3 Hooks ที่ช่วยงานได้จริง
สำหรับผู้เริ่มต้น ไม่จำเป็นต้องสร้างระบบซับซ้อนทันที
สามารถเริ่มจาก Hooks สามชุดนี้
Notification Hook
แจ้งเตือนเมื่อ Claude รอคำตอบหรือการอนุมัติ ช่วยให้เราไปทำงานอื่นระหว่าง Claude ทำงานได้
Format Hook
รัน Formatter หลัง Claude แก้ไฟล์ ลดปัญหาเรื่องรูปแบบโค้ดและ Diff ที่ไม่จำเป็น
Protected Files Hook
ป้องกันไฟล์ที่ไม่ควรถูกแก้โดยตรง เช่น Environment File, Production Configuration หรือ Migration ที่ต้องผ่านการตรวจสอบ
เมื่อ Workflow เริ่มนิ่ง จึงค่อยเพิ่ม
- Pre-commit Check
- Command Audit
- Test Automation
- Session Logging
- Context Injection
- Integration กับระบบภายนอก
จากการเขียน Prompt สู่การออกแบบระบบควบคุม AI
การใช้ Claude Code ระดับเริ่มต้นมักเน้นว่าเราควรเขียน Prompt อย่างไรให้ Claude ทำงานถูกต้อง
แต่เมื่อ Claude เริ่มรับผิดชอบงานจริงมากขึ้น คำถามสำคัญจะเปลี่ยนเป็น
สิ่งใดควรให้ Claude ตัดสินใจเอง สิ่งใดควรเขียนเป็นกติกาใน CLAUDE.md สิ่งใดต้องถูกตรวจสอบก่อนทำ สิ่งใดต้องทำอัตโนมัติหลังเกิด Event สิ่งใดต้อง Block โดยไม่มีข้อยกเว้น สิ่งใดต้องผ่านการอนุมัติจากมนุษย์
Hooks เป็นจุดเชื่อมระหว่าง AI ที่ใช้ภาษาในการตัดสินใจ กับระบบซอฟต์แวร์ที่ต้องการกฎที่ตรวจสอบได้
เราไม่จำเป็นต้องคอยเตือน Claude ว่าให้ Format ทุกครั้ง ไม่ต้องหวังว่า Claude จะจำว่าห้ามแตะไฟล์ใด และไม่ต้องนั่งเฝ้า Terminal ตลอดเวลาว่างานเสร็จหรือยัง
แต่เราต้องออกแบบ Event, Matcher, Script และ Guardrail ให้ถูกต้อง
เพราะเป้าหมายของการใช้ Claude Code อย่างมืออาชีพ ไม่ใช่เพียงทำให้ Claude เขียนโค้ดได้เร็วขึ้น
แต่คือการสร้างสภาพแวดล้อมที่ทำให้ Claude สามารถทำงานได้เร็วขึ้น โดยยังอยู่ภายใต้กฎ คุณภาพ และขอบเขตที่ทีมตรวจสอบได้