هوكس Claude Code: كيف تحوّل قواعد الوكيل إلى ضمانات
هوكس Claude Code أوامر shell يشغّلها Claude Code نفسه عند أحداث محددة: قبل استدعاء أداة وبعده، وعند إرسال الطلب، وعند بدء الجلسة، وقبل توقف الوكيل. تُضبط في settings.json، ورمز الخروج 2 يمنع الإجراء ويعيد رسالة الخطأ للوكيل، فيتحول البند من CLAUDE.md إلى ضمانة لا يستطيع النموذج أن ينساها.
ما هي هوكس Claude Code
الهوك أمر لا يشغّله النموذج، بل يشغّله برنامج Claude Code نفسه في لحظة محددة من عمل الوكيل. يهم الوكيل تنفيذ rm -rf فيعمل الهوك ويقرر هل يسمح بالأمر. يعدّل الوكيل ملفًا فيشغّل الهوك أداة التنسيق. يريد الوكيل إنهاء العمل فيشغّل الهوك الاختبارات ولا يسمح بالتوقف ما دامت حمراء.
الفرق الجوهري عن التعليمات في CLAUDE.md: التعليمة نص يأخذه النموذج في الحسبان باحتمال معين، أما الهوك فكود حتمي. يعمل دائمًا، بغض النظر عن طول السياق، وعما «قرره» الوكيل، وعما إذا نسي القاعدة في الدقيقة المئة من الجلسة. لذلك تبقى claude code hooks الوسيلة الأساسية لتحويل الرغبة إلى ضمانة.
لماذا لا تكفي القواعد في CLAUDE.md
صورة نموذجية: أنهى الوكيل إضافة ميزة، واختبارات الوحدة خضراء، وفي المحادثة جملة واثقة «تم». لكن أحدًا لم يشغّل السيناريو الشامل، ولم يُشغَّل المدقق، وفشلت migration في المنتصف. وفي CLAUDE.md مكتوب «قبل الإنهاء شغّل الاختبارات». النموذج لا يخدع عن قصد، لكنه يقيّم نفسه بنفسه، وهذا التقييم غير موثوق.
من هنا يأتي مبدأ الهارنس: كل ما يمكن فحصه آليًا يفحصه الجهاز لا النموذج. القاعدة «شغّل المدقق» تصبح هوكًا يشغّل المدقق. القاعدة «لا تلمس إعدادات الإنتاج» تصبح هوكًا يمنع الكتابة إلى ذلك الملف. تبقى التعليمة النصية، لكنها تشرح للوكيل فقط لماذا أُوقف.
الأحداث: متى تعمل الهوكس
كل هوك مرتبط بحدث من دورة حياة الجلسة. الأحداث الرئيسية:
| الحدث | متى يعمل | استخدام شائع |
|---|---|---|
PreToolUse | قبل استدعاء أداة (Bash وEdit وWrite وغيرها) | منع الأوامر الخطيرة، وحماية الملفات |
PostToolUse | بعد نجاح استدعاء أداة | أداة التنسيق، والمدقق، واختبارات سريعة بعد التعديل |
UserPromptSubmit | عند إرسال المستخدم طلبًا، قبل معالجته | إضافة سياق، أو رفض طلب يحوي سرًا |
Stop | عندما يهم الوكيل بإنهاء ردّه | منعه من التوقف قبل نجاح الفحوص |
SubagentStop | عندما ينتهي وكيل فرعي من عمله | فحص نتيجة الوكيل الفرعي |
SessionStart | عند بدء الجلسة أو استئنافها | تحميل الحالة: git status، والخطة، وسجل التقدم |
SessionEnd | عند انتهاء الجلسة | تنظيف، وكتابة السجلات |
Notification | عندما يرسل Claude Code إشعارًا (مثلًا ينتظر إذنًا) | صوت أو رسالة إلى الهاتف |
PreCompact | قبل ضغط السياق | حفظ الأهم قبل الضغط |
الأكثر فائدة للموثوقية هي PreToolUse وPostToolUse وStop، لأنها تغطي ثلاث نقاط ضعف للوكيل: الأفعال الخطيرة، والتعديلات غير المفحوصة، والإعلان المبكر عن «تم».
أين تُضبط الهوكس: settings.json
تُوصف الهوكس في ملفات إعدادات Claude Code:
~/.claude/settings.json— إعداداتك الشخصية لكل المشاريع؛.claude/settings.jsonداخل المستودع — مشتركة للفريق، تُحفظ في git؛.claude/settings.local.json— محلية للمشروع، لا تدخل git.
البنية: الحدث ← قائمة مجموعات فيها matcher ← قائمة أوامر.
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/lint.sh",
"timeout": 60
}
]
}
]
}
}
matcher هو اسم الأداة أو تعبير نمطي عليها: Bash أو Edit|Write أو .*. وهو مطلوب للأحداث المرتبطة بالأدوات؛ أما مع Stop أو UserPromptSubmit فيمكن حذفه. المتغير CLAUDE_PROJECT_DIR يشير إلى جذر المشروع، لذلك من الأفضل حفظ السكربتات في .claude/hooks/ واستدعاؤها عبره. ولعرض الهوكس الحالية استخدم الأمر /hooks داخل Claude Code.
كيف يستقبل الهوك البيانات ويرد
الدخل: JSON عبر stdin
يمرّر Claude Code للهوك كائن JSON يصف الحدث: معرّف الجلسة، ومجلد العمل، واسم الحدث، وبالنسبة للأدوات tool_name وtool_input. في Bash يوجد الأمر في tool_input.command، وفي Edit وWrite يوجد مسار الملف في tool_input.file_path. ومن الملائم قراءته بـ jq.
{
"session_id": "abc123",
"hook_event_name": "PreToolUse",
"tool_name": "Bash",
"tool_input": { "command": "rm -rf build/" },
"cwd": "/home/dev/project"
}
الخرج: رمز الإرجاع
| الرمز | ما الذي يحدث |
|---|---|
0 | نجاح، والعمل مستمر؛ في UserPromptSubmit وSessionStart يُضاف stdout إلى سياق الوكيل |
2 | خطأ يمنع الإجراء: يُمرَّر stderr إلى الوكيل ويتوقف الإجراء (في PreToolUse يُلغى استدعاء الأداة، وفي Stop يواصل الوكيل عمله) |
| أي رمز آخر | خطأ غير مانع: يُعرض stderr للمستخدم ويستمر العمل |
رمز الخروج 2 هو الآلية المفتاحية. يتلقى الوكيل نص stderr كتغذية راجعة، فيمكنه أن يصحح نفسه: يعيد كتابة الأمر، أو يصلح الاختبار، أو لا يلمس الملف. لذلك اكتب في stderr لا كلمة «خطأ» فقط، بل السبب الواضح وما الذي يُفعل بدلًا منه.
إلى جانب رمز الإرجاع يمكن للهوك أن يطبع في stdout كائن JSON يحوي قرارًا، مثل "decision": "block" و"reason". وهذا مفيد للضبط الدقيق، لكن لأغلب المهام يكفي الرمز 2 والرسالة في stderr.
المثال 1: مدقق واختبارات بعد كل تعديل
هوك PostToolUse مع matcher هو Edit|Write يعمل بعد تعديل الملف. الأداة نفذت بالفعل ولا يمكن التراجع عن التعديل، لكن الرمز 2 يعيد للوكيل مخرجات المدقق، فيصحح الخطأ فورًا لا بعد نصف ساعة.
#!/usr/bin/env bash
# .claude/hooks/lint.sh
file=$(jq -r '.tool_input.file_path // empty')
case "$file" in
*.py)
if ! out=$(ruff check "$file" 2>&1); then
echo "المدقق وجد أخطاء في $file:" >&2
echo "$out" >&2
exit 2
fi ;;
*.php)
if ! out=$(php -l "$file" 2>&1); then
echo "$out" >&2
exit 2
fi ;;
esac
exit 0
لا تضع هنا تشغيل كامل للاختبارات الذي يستغرق عشر دقائق، لأن الهوك يعمل مع كل تعديل. بعد التعديل شغّل فحوصًا سريعة (الصياغة، والمدقق، واختبارات الوحدة المعدّلة)، والفحوص الثقيلة ضعها في هوك Stop.
المثال 2: منع الأوامر الخطيرة
هوك PreToolUse مع matcher هو Bash يرى الأمر قبل تنفيذه. الرمز 2 يلغي الاستدعاء، ويحصل الوكيل على التفسير.
#!/usr/bin/env bash
# .claude/hooks/guard.sh
cmd=$(jq -r '.tool_input.command // empty')
if echo "$cmd" | grep -Eq 'rm -rf /|git push (-f|--force)|DROP (TABLE|DATABASE)'; then
echo "الأمر محظور بسياسة المشروع: $cmd. الأوامر الخطيرة ينفذها الإنسان." >&2
exit 2
fi
exit 0
وبالطريقة نفسها تُحمى الملفات: هوك على Edit|Write يفحص file_path ويمنع الكتابة إلى .env أو إعدادات الإنتاج أو الكود المولَّد أو ملفات migration المطبقة. انتبه إلى أن الفحص بالتعبير النمطي يمكن الالتفاف حوله، فقد يكتب الوكيل الأمر بصيغة أخرى. الهوك حماية قوية، لكنه ليس بديلًا عن صلاحيات الوصول والبيئة المعزولة.
المثال 3: الوكيل لا يقول «تم» ما دامت الاختبارات حمراء
هوك Stop يعمل حين يهم الوكيل بالإنهاء. إذا فشلت الاختبارات، يمنعه الرمز 2 من التوقف، ويتحول خرج الاختبارات إلى مهمة تالية للوكيل. هذه نسخة آلية من تعريف «الإنجاز» (Definition of Done).
#!/usr/bin/env bash
# .claude/hooks/done.sh
input=$(cat)
# حماية من الحلقة اللانهائية: الهوك مدّد العمل مرة واحدة
if [ "$(echo "$input" | jq -r '.stop_hook_active')" = "true" ]; then
exit 0
fi
if ! out=$(npm test --silent 2>&1); then
echo "الاختبارات لم تنجح، والعمل غير مكتمل:" >&2
echo "$out" | tail -n 40 >&2
exit 2
fi
exit 0
الحقل stop_hook_active يساوي true إذا كان الوكيل يواصل العمل بسبب هوك التوقف أصلًا. دون هذا الفحص قد يدفع الهوك الوكيل في دائرة بلا نهاية، وهذه بالضبط الحالة التي «يعمل فيها الوكيل طوال الليل في الاتجاه الخطأ». وفي الحلقات المستقلة أضف حدًا للمحاولات وشرطًا يستدعي الإنسان.
المثال 4: تحميل الحالة في بداية الجلسة
في SessionStart يصل stdout الهوك إلى السياق. من المفيد عرض الفرع الحالي والتعديلات غير الملتزَم بها والمهمة التالية من الخطة، حتى لا يبدأ الوكيل من الصفر.
#!/usr/bin/env bash
echo "الفرع: $(git branch --show-current)"
git status --short | head -n 20
[ -f PROGRESS.md ] && tail -n 15 PROGRESS.md
exit 0
كيف تحوّل الهوكس القواعد إلى ضمانات
من المفيد تقسيم قواعد الهارنس إلى ثلاثة مستويات. الأول نص في CLAUDE.md: يشرح كيف يُعمل، لكنه يُلتزم به احتماليًا. الثاني فحوص قابلة للتنفيذ: الاختبارات، والاختبارات الشاملة، وقواعد المعمارية في شكل سكربت يفشل عند المخالفة. الثالث الهوكس التي تشغّل هذه الفحوص تلقائيًا في اللحظة المناسبة دون مشاركة النموذج.
قاعدة عملية: إذا خالف الوكيل القاعدة نفسها مرتين، فلا تضف إلى CLAUDE.md تحذيرًا آخر بالحروف الكبيرة. اسأل هل يمكن فحص المخالفة بسكربت؟ إن أمكن، فاكتب السكربت وعلّقه على هوك. عندها تصبح التعليمة النصية أقصر، والسلوك أكثر ثباتًا.
| القاعدة في النص | الضمانة عبر الهوك |
|---|---|
| «نسّق الكود وفق المعيار» | PostToolUse يشغّل أداة التنسيق على الملف المعدَّل |
| «لا ترسل push بالقوة» | PreToolUse على Bash يمنع الأمر برمز 2 |
| «لا تقل تم والاختبارات حمراء» | Stop يشغّل الاختبارات ويمنع الإنهاء |
| «لا تعدّل .env» | PreToolUse على Edit|Write يفحص المسار |
| «تذكر أين توقفت» | SessionStart يعرض الخطة وgit status |
الأخطاء الشائعة
- الرمز 1 بدل 2. يفشل السكربت برمز 1، فلا يعرف الوكيل شيئًا ويمر الإجراء. المنع يحدث فقط مع الرمز 2.
- الرسالة في stdout. عند الرمز 2 يصل إلى الوكيل stderr فقط. اكتب عبر
>&2. - هوك بطيء على حدث متكرر. تشغيل كامل للاختبارات في PostToolUse يجعل كل تعديل يستغرق دقائق. الثقيل يذهب إلى Stop.
- Stop بلا نهاية. غياب فحص
stop_hook_activeأو الحد يجعل الوكيل يدور بلا توقف. - مسارات نسبية. يعمل الهوك في مجلد عمل الجلسة؛ استخدم
$CLAUDE_PROJECT_DIR. - هوك غريب غير مفحوص. يعمل الهوك بصلاحياتك دون تأكيد. اقرأ السكربتات من المستودعات الأخرى قبل أن تثق بها.
الخلاصة
تنقل claude code hooks أهم القواعد من النص إلى الكود: يوقف PreToolUse الأفعال الخطيرة، ويفحص PostToolUse كل تعديل، ويمنع Stop الإعلان عن الجاهزية قبل أوانها، ويعيد SessionStart للوكيل ذاكرة المشروع. ابدأ بهوكين أو ثلاثة لقواعد خالفها الوكيل بالفعل، واجعل رسائل stderr واضحة، فيصحح الوكيل أخطاءه بنفسه، وتتحقق أنت من النتيجة لا من العملية. وقد شرحنا التحقق والجاهزية والحلقات المستقلة عمليًا في الدورة.
الأسئلة الشائعة
هل أحتاج إلى إعادة تشغيل Claude Code بعد تغيير الهوكس؟
أضمن تطبيق التغييرات في settings.json يكون ببدء جلسة جديدة؛ ويمكن عرض الإعداد الحالي للهوكس بالأمر /hooks.
هل يمكن كتابة الهوكس بغير bash؟
نعم، فالهوك أي أمر: سكربت بلغة Python أو Node.js أو ملف تنفيذي. المهم أن يقرأ JSON من stdin ويعيد رمز الخروج الصحيح.
هل يرى الوكيل خرج الهوك الناجح؟
عادةً لا: عند الرمز 0 لا يدخل الخرج السياق. الاستثناء هو UserPromptSubmit وSessionStart، حيث يُضاف stdout إلى سياق الوكيل.
هل تعمل الهوكس مع الوكلاء الفرعيين؟
نعم، تمر استدعاءات أدوات الوكلاء الفرعيين عبر الهوكس نفسها PreToolUse وPostToolUse، ولانتهائهم حدث خاص هو SubagentStop.
هل من الآمن رفع الهوكس إلى المستودع؟
نعم، فملف .claude/settings.json وسكربتات .claude/hooks/ ممارسة شائعة للفريق؛ أما الهوكس الشخصية فاحفظها في settings.local.json أو في ~/.claude/settings.json.
يُشرح هذا الموضوع بالتفصيل مع التطبيق العملي في دورة «Harness Engineering: инженерия надёжности AI-агентов».
- Агент написал «готово», а фича не работает: verification gap и Definition of Done
- Все тесты зелёные, а фича сломана: E2E-тесты и архитектурные правила для AI-агента
- Автономный AI-агент часами без присмотра: Loop Engineering и условия остановки