สารบัญ
- ใช้ฮุกไหนกับสถานการณ์ไหน
- สิ่งที่ต้องมี
- ขั้นที่ 1 — สร้างสองช่อง
- ขั้นที่ 2 — เพิ่มฮุก
- ขั้นที่ 3 — ทดสอบโดยไม่ต้องรอพรอมต์จริง
- ขั้นที่ 4 — ทำให้ช่อง blocked ดังเป็นสายโทรเข้า
- หลีกเลี่ยงการแจ้งเตือนท่วม
- รัน Claude Code จากระยะไกลหรือใน CI
- การแก้ปัญหา
- คำถามที่พบบ่อย
- จะรับแจ้งเตือนเมื่อ Claude Code ขออนุญาตได้อย่างไร
- จะรู้ได้อย่างไรว่า Claude Code ทำงานเสร็จแล้ว
- การแจ้งเตือนทะลุโหมดห้ามรบกวนได้ไหม
- ใช้กับ Claude Code บนเว็บหรือเซสชันระยะไกลได้ไหม
- ใส่เว็บฮุก URL ใน settings.json ปลอดภัยไหม
- สรุป
- บทความที่เกี่ยวข้อง
Claude Code หยุดทำงานในสองจังหวะที่สำคัญ คือเมื่อมันติดอยู่และรอคุณ (ขออนุญาตหรือถามคำถาม) กับเมื่อมันทำงานเสร็จแล้ว ถ้าคุณไม่ได้มองเทอร์มินัลอยู่ ทั้งสองกรณีดูเหมือนกันหมด คือไม่มีอะไรเกิดขึ้น และเซสชันก็นิ่งอยู่อย่างนั้นจนกว่าคุณจะกลับมา วิธีแก้คือฮุก: เพิ่มไม่กี่บรรทัดใน settings.json เพื่อส่งเว็บฮุกไปที่มือถือของคุณทันทีที่เกิดเหตุการณ์ใดเหตุการณ์หนึ่ง
คู่มือนี้ให้คอนฟิกที่คัดลอกไปใช้ได้เลย อธิบายว่าควรใช้ฮุกอีเวนต์ไหนกับสถานการณ์ใด และครอบคลุมรายละเอียดที่ทำให้ระบบทำงานได้เสถียร ได้แก่ การอ่านอินพุตของฮุก การจัดการเครื่องหมายอัญประกาศใน shell และการไม่ให้ตัวเองจมอยู่กับการแจ้งเตือน
ใช้ฮุกไหนกับสถานการณ์ไหน
Claude Code รันฮุกตามอีเวนต์ในวงจรการทำงาน มีสองอีเวนต์ที่ตอบโจทย์นี้ (เอกสารอ้างอิงฮุก)
| คุณอยากรู้เมื่อ… | ฮุกอีเวนต์ | Matcher / ตัวกรอง |
|---|---|---|
| Claude กำลังรอการตัดสินใจเรื่องสิทธิ์ | Notification | permission_prompt |
| Claude อยู่เฉย ๆ และรออินพุตจากคุณ | Notification | idle_prompt |
| Claude ตอบเสร็จแล้ว | Stop | ไม่ต้องใช้ |
matcher ของฮุก Notification กรองตามประเภทการแจ้งเตือน คุณจึงเลือกได้ว่าการแจ้งเตือนแบบไหนจะไปถึงมือถือ อินพุตมาในรูป JSON ทาง stdin และมี notification_type, message, cwd และ session_id ฮุก Notification บล็อกหรือเปลี่ยนแปลงอะไรไม่ได้ มันเป็นแค่ผู้สังเกตการณ์ ซึ่งตรงกับสิ่งที่เราต้องการพอดี
อินพุตของ Stop มี last_assistant_message ซึ่งเป็นข้อความสุดท้ายที่ Claude เขียน นั่นคือบรรทัดสรุปสำหรับการแจ้งเตือนที่ได้มาฟรี ๆ
สิ่งที่ต้องมี
- Echobell บนมือถือ (App Store / Google Play)
curlและjqบนเครื่องที่รัน Claude Code- เวลาสองนาที
ขั้นที่ 1 — สร้างสองช่อง
อย่าส่งทุกอย่างเข้าช่องเดียว ใน Echobell ให้สร้าง:
- Claude Blocked ประเภท Time Sensitive หรือ Calling — สำหรับการขออนุญาต เพราะเอเจนต์หยุดค้างอยู่ และทุกนาทีที่ผ่านไปคือทรัพยากรและเวลาที่เสียเปล่า
- Claude Done ประเภท Normal — พุชธรรมดา อ่านตอนไหนก็ได้
คัดลอกเว็บฮุก URL ของแต่ละช่อง หน้าตาประมาณ https://hook.echobell.one/t/<channel-token> ให้ดูแลเหมือนรหัสผ่าน ใครมี URL นี้ก็ทำให้โทรศัพท์คุณดังได้
เก็บทั้งสองไว้เป็นตัวแปรสภาพแวดล้อม จะได้ไม่หลุดเข้าไฟล์คอนฟิกที่ถูกคอมมิต:
export ECHOBELL_CLAUDE_BLOCKED_URL="https://hook.echobell.one/t/<blocked-token>"
export ECHOBELL_CLAUDE_DONE_URL="https://hook.echobell.one/t/<done-token>"
ใส่ไว้ในโปรไฟล์ shell เพื่อให้ Claude Code รับค่าไปด้วย
ขั้นที่ 2 — เพิ่มฮุก
เพิ่มส่วนนี้ลงใน ~/.claude/settings.json เพื่อใช้กับทุกโปรเจกต์ หรือใน .claude/settings.local.json เพื่อใช้กับรีโพเดียว
{
"hooks": {
"Notification": [
{
"matcher": "permission_prompt",
"hooks": [
{
"type": "command",
"command": "jq -c '{title: \"Claude ขออนุญาต\", body: .message, project: (.cwd | split(\"/\") | last)}' | curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- \"$ECHOBELL_CLAUDE_BLOCKED_URL\""
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "jq -c '{title: \"Claude ทำงานเสร็จแล้ว\", body: (.last_assistant_message // \"เสร็จแล้ว\" | .[0:200]), project: (.cwd | split(\"/\") | last)}' | curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- \"$ECHOBELL_CLAUDE_DONE_URL\""
}
]
}
]
}
}
แต่ละส่วนทำหน้าที่ดังนี้
jq -c '{...}'อ่าน JSON ของฮุกจาก stdin แล้วสร้างเพย์โหลดขนาดเล็ก Echobell จึงได้รับเฉพาะฟิลด์ที่คุณต้องการ ไม่ใช่เอกสารของฮุกทั้งก้อน.cwd | split("/") | lastเปลี่ยน/home/me/code/apiเป็นapiการแจ้งเตือนจึงบอกได้ว่าโปรเจกต์ไหนเป็นฝ่ายเรียก.[0:200]ตัดข้อความสุดท้ายให้สั้นลง เวิร์กเกอร์ของ Echobell จำกัดเนื้อหาแจ้งเตือนไว้ที่ 1500 ไบต์ และหน้าจอล็อกก็แสดงได้น้อยกว่านั้นมากอยู่แล้ว-m 10ตั้งเวลาหมดอายุ 10 วินาทีให้curlปัญหาเครือข่ายจึงไม่ทำให้ Claude Code ต้องรอฮุกของคุณค้างอยู่
Echobell แสดงคีย์ที่คุณส่งผ่านเทมเพลตของช่อง และช่องใหม่ยังไม่มีเทมเพลตที่อ่านคีย์เหล่านี้ ให้ตั้งค่าในการตั้งค่าช่อง: เทมเพลตหัวข้อ {{title}} และเทมเพลตเนื้อหา {{body}} ถ้าอยากให้แสดงชื่อโปรเจกต์ด้วย ให้เพิ่ม {{project}} ลงในอันใดอันหนึ่ง เช่น {{title}} ({{project}})
ขั้นที่ 3 — ทดสอบโดยไม่ต้องรอพรอมต์จริง
รันไปป์ไลน์เดียวกันด้วยมือ โดยใช้เพย์โหลดฮุกปลอม:
echo '{"message":"Claude ต้องการสิทธิ์ใช้ Bash","cwd":"/home/me/code/api","notification_type":"permission_prompt"}' \
| jq -c '{title: "Claude ขออนุญาต", body: .message, project: (.cwd | split("/") | last)}' \
| curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- "$ECHOBELL_CLAUDE_BLOCKED_URL"
ถ้ามือถือคุณสว่างขึ้น แปลว่าฝั่ง Echobell ใช้งานได้ และปัญหาที่เหลือน่าจะอยู่ที่วิธีที่ Claude Code อ่านคอนฟิก ใน Claude Code ให้รัน /hooks เพื่อยืนยันว่าโหลดฮุกแล้ว การเปลี่ยนการตั้งค่าระหว่างที่เซสชันกำลังรันอาจต้องผ่านเมนู hooks หรือรีสตาร์ตก่อนจึงจะมีผล
ขั้นที่ 4 — ทำให้ช่อง blocked ดังเป็นสายโทรเข้า
พุชธรรมดาแพ้โหมดห้ามรบกวน ช่อง Calling ทำงานเหมือนสายเรียกเข้าและทะลุโหมดโฟกัสของ iOS ได้ ซึ่งสำคัญมากเมื่อคุณสั่งงานยาว ๆ แล้วเดินออกไปทั้งเย็น ถ้าอยากถูกรบกวนเฉพาะบางพรอมต์ ให้กรองด้วยเงื่อนไขของช่องใน Echobell จากตัวแปรที่คุณส่งไป เช่น project == "api" แทนการแก้ฮุก ดูรายการตัวแปรทั้งหมดได้ที่ เอกสารอ้างอิงเงื่อนไข
หลีกเลี่ยงการแจ้งเตือนท่วม
เซสชันที่วุ่นวายอาจยิงอีเวนต์ Stop ออกมามาก เพราะทุกการตอบจบด้วยหนึ่งครั้ง มีสามวิธีรักษาสัญญาณที่มีค่าไว้
- อย่าส่ง
Stopเข้าช่องที่ดังเป็นสายโทรเข้า การทำงานเสร็จไม่ใช่เรื่องเร่งด่วน ให้ใช้ช่อง Normal - ใช้
idle_promptแทนStopถ้าอยากรู้เฉพาะตอนที่ Claude หยุดและรอคุณ ไม่ใช่ทุกครั้งที่ตอบเสร็จ - จำกัดตามโปรเจกต์ ด้วยเงื่อนไข เพื่อให้รีโพที่ใช้ลองเล่นไม่ส่งแจ้งเตือนมาเลย
รัน Claude Code จากระยะไกลหรือใน CI
วิธีเดียวกันใช้ได้ในสภาพแวดล้อมคลาวด์หรือรีโมต เพราะฮุกเป็นเพียงคำขอ HTTPS ขาออก ไม่ต้องมีอะไรที่เข้าถึงได้จากอินเทอร์เน็ต ให้ตั้งตัวแปรสภาพแวดล้อมสองตัวนี้ในซีเคร็ตของสภาพแวดล้อมแทนโปรไฟล์ shell แล้วการแจ้งเตือนก็จะไปถึงมือถือคุณไม่ว่าเซสชันจะรันอยู่ที่ไหน
การแก้ปัญหา
ไม่มีอะไรมาถึง และการทดสอบด้วยมือก็ล้มเหลว ตรวจว่าตัวแปร URL ถูกตั้งไว้ใน shell ที่เปิด Claude Code: echo "$ECHOBELL_CLAUDE_BLOCKED_URL" ตัวแปรที่ว่างเปล่าทำให้ curl ล้มเหลวแบบเงียบ ๆ
ทดสอบด้วยมือได้ แต่ฮุกไม่ทำงาน ตรวจ matcher: permission_prompt กับ idle_prompt เป็นคนละตัว และ matcher ที่ไม่ตรงก็จะไม่รันเลย รัน /hooks และตรวจว่า JSON ถูกต้อง เครื่องหมายจุลภาคเกินท้ายแค่ตัวเดียวก็ทำให้ฮุกทั้งไฟล์การตั้งค่านั้นใช้ไม่ได้
เนื้อหาแจ้งเตือนว่างเปล่า ฟิลเตอร์ jq อ้างถึงฟิลด์ที่ไม่มีในอีเวนต์นั้น message มีในอินพุตของ Notification ส่วน last_assistant_message มีในอินพุตของ Stop ใช้ // เพื่อกำหนดค่าเริ่มต้น เหมือนในคอนฟิกด้านบน
แจ้งเตือนถี่เกินไป ดูหัวข้อด้านบน ให้เปลี่ยนจาก Stop เป็น idle_prompt หรือเพิ่มเงื่อนไข
คำถามที่พบบ่อย
จะรับแจ้งเตือนเมื่อ Claude Code ขออนุญาตได้อย่างไร
เพิ่มฮุก Notification ที่มี matcher เป็น permission_prompt เพื่อส่งเว็บฮุกไปยังช่อง Echobell จะเปลี่ยนคำขอนั้นเป็นพุชหรือการแจ้งเตือนแบบสายโทรเข้าบนมือถือของคุณ
จะรู้ได้อย่างไรว่า Claude Code ทำงานเสร็จแล้ว
เพิ่มฮุก Stop มันรันเมื่อ Claude ตอบเสร็จ และอินพุตมี last_assistant_message ซึ่งใช้เป็นเนื้อหาแจ้งเตือนได้
การแจ้งเตือนทะลุโหมดห้ามรบกวนได้ไหม
ได้ ถ้าช่องที่รับเป็นช่อง Calling มันทำงานเหมือนสายเรียกเข้าซึ่งโหมดโฟกัสของ iOS ปล่อยผ่าน พุชธรรมดาจากแอปอื่นทำแบบนี้ไม่ได้
ใช้กับ Claude Code บนเว็บหรือเซสชันระยะไกลได้ไหม
ได้ ฮุกแค่ส่งคำขอ HTTPS ขาออก จึงใช้ได้ทุกที่ที่เซสชันเชื่อมต่ออินเทอร์เน็ตได้ ส่ง URL ของช่องผ่านซีเคร็ตของสภาพแวดล้อม
ใส่เว็บฮุก URL ใน settings.json ปลอดภัยไหม
ควรใช้ตัวแปรสภาพแวดล้อมอย่างที่แสดงไว้ข้างบน เพื่อไม่ให้โทเค็นถูกคอมมิตเข้ารีโพ ถ้ารั่วไหล ให้สร้างช่องใหม่แล้วเลิกใช้ช่องเดิม
สรุป
สองช่อง สองฮุก และไปป์ไลน์ jq | curl เพียงเท่านี้: ช่อง Calling หรือ Time Sensitive สำหรับ permission_prompt และช่อง Normal สำหรับ Stop จากนั้นคุณก็สั่งงานเอเจนต์ยาว ๆ แล้วออกจากห้องได้ และถูกเรียกกลับมาเฉพาะตอนที่เอเจนต์ต้องการคุณจริง ๆ
ดาวน์โหลด Echobell สำหรับ iPhone หรือ ติดตั้งจาก Google Play แล้วรันการทดสอบด้วยมือด้านบนก่อนจะเชื่อใจมันกับงานยาว ๆ