شو الـ hook وكيف بيشتغل؟
الـ hook أمر إنت بتكتبه، وClaude Code بينفّذه لحاله عند حدث معيّن: قبل ما يشغّل أداة، بعد ما يعدّل ملف، لما يخلص الرد. مش Claude اللي بيقرّر ينفّذه؛ هو بينفّذ دايماً، زي قاعدة بالنظام.
tool_name، ومدخلاتها بـ tool_input (مسار الملف بـ tool_input.file_path لأدوات التعديل، والأمر بـ tool_input.command لأداة Bash). عشان هيك كل الأوامر تحت بتبدأ بـ jq: هو اللي بيقرأ الـ JSON.الـ hooks جزء من إعدادات الأمان الأوسع: الصلاحيات والقواعد بـ دليل إعدادات الأمان.
ملف واحد بمجلد المشروع. الأوامر فيه لمشروع JavaScript/Node؛ بدّلها حسب مشروعك بالقسم 5.
ملف الـ hooks الخمسة (الصقه)
احفظه باسم .claude/settings.json جوّا مجلد المشروع (أو ادمجه مع الملف الموجود إذا عندك واحد). بدّل YOUR-TOPIC بكلمة سرية إلك:
.claude/settings.json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" },
{ "type": "command", "command": "npm test --silent || { echo 'tests failed after this edit' >&2; exit 2; }", "timeout": 120 }
]
},
{
"matcher": "",
"hooks": [
{ "type": "command", "command": "jq -c '[(now|strftime(\"%H:%M\")), .tool_name, (.tool_input.file_path // .tool_input.command // \"\")]' >> .claude/tool-log.jsonl" }
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "sh .claude/guard.sh" }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "curl -s -d 'Claude: done' ntfy.sh/YOUR-TOPIC" }
]
}
]
}
}
- الهيكل: اسم الحدث ← قائمة فيها
matcher(أي أداة) وhooks(الأوامر). الـ Stop ما إله matcher لأنه بيشتغل كل مرة. - الـ matcher: "Edit|Write" يعني أداتي التعديل والكتابة بالضبط. "" (فاضي) أو "*" يعني كل الأدوات.
- الترتيب: الـ hooks اللي بنفس الـ matcher بتشتغل بالتوازي، فما تعتمد على إنه التنسيق بيخلص قبل الاختبارات.
ملف المنع guard.sh
هاد الملف بيقرأ أمر الـ Bash قبل ما ينفّذ. إذا لقى فيه نمط خطر بيرجّع exit 2: الأمر بيتوقف، والسبب بيروح لـ Claude عشان يغيّر طريقته. احفظه باسم .claude/guard.sh:
.claude/guard.sh
#!/bin/sh
# exit 2 = block the command and tell Claude why. exit 0 = let it through.
CMD=$(jq -r '.tool_input.command // ""')
case "$CMD" in
*"rm -rf /"*|*"rm -rf ~"*|*"rm -rf .."*|*"rm -rf *"*|*"git push --force"*|*"git push -f"*|*"git reset --hard"*|*"DROP TABLE"*|*"DROP DATABASE"*|*"mkfs"*|*"> /dev/sd"*)
echo "blocked by guard.sh: $CMD" >&2
exit 2 ;;
esac
exit 0
- الأنماط بين النجمتين: أي أمر فيه هالنص بيتوقف. ضيف أنماطك: *"terraform destroy"*، *".env"*، اسم قاعدة بيانات الإنتاج.
- ليش exit 2 بالذات؟ هو الكود الوحيد اللي بيمنع. exit 0 بيمرّر، وأي رقم تاني بيعرض الخطأ إلك وبيكمّل.
- بديل بالـ JSON: بدل exit 2 بتقدر تطبع {"hookSpecificOutput":{"hookEventName":"PreToolUse","permissionDecision":"deny","permissionDecisionReason":"…"}}. نفس النتيجة، بس بتقدر تختار ask كمان عشان يسألك بدل ما يمنع.
شو بيعمل كل hook وليش هيك
جرّب كل hook لحاله قبل ما تعتمد عليه.
التثبيت والتجربة
- ثبّت jq (قارئ الـ JSON): على Mac
brew install jq، على Windowswinget install jqlang.jq، على Ubuntusudo apt install jq. وعلى Windows لازم Git for Windows عشان أوامر الـ sh. - احفظ الملفين بمجلد
.claude/جوّا المشروع، وبدّل YOUR-TOPIC. على Mac وLinux اعطي ملف المنع صلاحية تنفيذ:chmod +x .claude/guard.sh. - افتح Claude Code بالمشروع (أو خلّيه مفتوح: التعديل على ملف الإعدادات بينلقط لحاله)، واكتب
/hooksعشان تشوف الخمسة مسجّلين مع أوامرهم. هاد الأمر للعرض بس؛ التعديل من الملف. - جرّب المنع: قوله «نفّذ echo test && git push --force». لازم يتوقف ويحكيلك إنه guard.sh منعه.
- جرّب التنسيق والسجل: اطلب تعديل صغير بأي ملف، وافتح .claude/tool-log.jsonl. لازم تلاقي السطر.
- جرّب الإشعار: ثبّت تطبيق ntfy على الجوال واشترك بنفس الـ topic. أول رد بيخلّصه Claude بيوصلك إشعار.
~/.claude/settings.json بدل مجلد المشروع. بس وقتها بدّل الأوامر الخاصة بالمشروع (npm test) بشي عام، أو خلّي التنسيق والاختبارات بملف المشروع والإشعار والسجل بملف الحساب.عدّله على مشروعك
| مشروعك | format | tests |
|---|---|---|
| JavaScript / TypeScript | npx prettier --write (زي الملف) | npm test --silent أو اختبارات الملف بس: npx vitest related --run |
| Python | jq -r '.tool_input.file_path' | xargs ruff format | pytest -q |
| Go | jq -r '.tool_input.file_path' | xargs gofmt -w | go test ./... |
| مش مبرمج؟ | احذف hook التنسيق | احذف hook الاختبارات. خلّي الإشعار والمنع والسجل: هدول بينفعوا بأي شغل |
- الاختبارات بطيئة؟ خلّيها تشتغل عند Stop بدل PostToolUse: مرة لما يخلص، بدل كل تعديل.
- إشعار على Mac بدون جوال: بدّل أمر curl بـ osascript -e 'display notification "Claude: done"'. على Linux: notify-send "Claude: done".
- الـ timeout: الافتراضي لأوامر الـ command طويل (600 ثانية). للاختبارات حدّده إنت زي ما بالملف عشان ما تعلق الجلسة.