30 حدث خطاف ينطلق في جلسة Claude Code. ثلاثة فقط يمكنها الرد.

القائمة الكاملة لأحداث خطافات Claude Code، ومتى ينطلق كل منها، وأي 15 منها يمكنه الحظر، وقاعدة stdout التي تبتلع بصمت مخرجات معظم الخطافات. مرجع ميداني بُني من تشغيل الخطافات في الإنتاج عبر آلاف جلسات الوكلاء.

يتكرر عطلان مرارا حين يربط الناس الخطافات بـ Claude Code، وهما لا يشبهان بعضهما في شيء.

الأول: تضيف خطافا، فلا يحدث شيء. لا خطأ، ولا تحذير، ولا سطر في السجل. الخطاف ببساطة لا ينفَّذ أبدا.

الثاني: الخطاف ينفَّذ بوضوح، وترى آثاره الجانبية على القرص، لكن الرسالة التي يطبعها للوكيل لا تصل أبدا. يتصرف الوكيل كأن الخطاف لم يقل شيئا.

كلاهما يأتي من المكان نفسه. نظام الخطافات أكبر وأقل انتظاما من حفنة الأحداث التي تغطيها معظم المقالات، والقواعد التي تحدد من يستطيع مخاطبة الوكيل ليست تلك التي قد تخمّنها. هذا هو المرجع الذي كنا نتمنى لو توفر لنا. نحن نبني AgentsRoom فوق هذه الخطافات، وكل ما يلي إما منقول عن المرجع الرسمي وإما مقيس في الإنتاج.

هناك 30 حدثا، لا ستة

تغطي معظم الأدلة PreToolUse وPostToolUse وUserPromptSubmit وStop وNotification وSubagentStop. هذه الستة حقيقية، وهي تحمل معظم العمل المفيد. وهي أيضا خُمس ما هو موجود.

القائمة الكاملة، مجمّعة بحسب ما تراقبه:

المجموعةالأحداث
الجلسةSessionStart، SessionEnd، Setup
المطالبةUserPromptSubmit، UserPromptExpansion
الأدواتPreToolUse، PostToolUse، PostToolUseFailure، PostToolBatch
الأذوناتPermissionRequest، PermissionDenied
الدورStop، StopFailure
الوكلاء الفرعيون والمهامSubagentStart، SubagentStop، TaskCreated، TaskCompleted، TeammateIdle
السياقPreCompact، PostCompact، InstructionsLoaded
البيئةFileChanged، CwdChanged، ConfigChange
أشجار العمل (worktrees)WorktreeCreate، WorktreeRemove
الواجهةNotification، MessageDisplay
استدراج MCPElicitation، ElicitationResult

مخطط زمني لأحداث خطافات Claude Code الثلاثين بالترتيب الذي تنطلق به خلال جلسة وكيل، من SessionStart مرورا بـ UserPromptSubmit وPreToolUse وPostToolUse وStop وصولا إلى SessionEnd، يوضح أي الأحداث يمكنه حظر الوكيل.

ترتيب انطلاق الأحداث في جلسة واحدة. تتكرر كتلة الأدوات مرة عند كل استدعاء أداة، وتتكرر كتلة المطالبة كاملة مرة عند كل دور.

بعض هذه الأحداث يغيّر طريقة تفكيرك في النظام. PostToolUseFailure موجود، أي أن مسار "هل نجحت الأداة" حدث قائم بذاته، لا شيء تستنتجه من الحمولة. ينطلق PostToolBatch مرة واحدة بعد انتهاء دفعة من استدعاءات الأدوات المتوازية، وهو المكان الصحيح لتشغيل مدقق الشيفرة مرة واحدة بدل مرة عند كل تعديل. ينطلق InstructionsLoaded عند قراءة CLAUDE.md، ما يمنحك نقطة خطاف للتحقق من أن الوكيل حمّل فعلا القواعد التي تظن أنه حمّلها.

قاعدة stdout التي تبتلع معظم مخرجات الخطافات

هذه أنفع معلومة في هذه الصفحة.

عند رمز الخروج 0، يحلل Claude Code محتوى stdout بحثا عن حقول إخراج JSON. لكن ما إذا كان هذا الـ stdout سيُعرض على الوكيل يوما فذلك يتوقف على الحدث، والاستثناءات قائمة قصيرة. من المرجع:

بالنسبة لمعظم الأحداث، يُكتب stdout في سجل التصحيح لكنه لا يظهر في سجل المحادثة. الاستثناءات هي UserPromptSubmit وUserPromptExpansion وSessionStart، حيث يُضاف stdout بوصفه سياقا يستطيع Claude رؤيته والتصرف بناء عليه.

ثلاثة أحداث من ثلاثين. إن نفّذت echo "warning: this migration is destructive" من خطاف PostToolUse وتوقعت أن يقرأها الوكيل، فلن يقرأها أبدا. نصك ذهب إلى سجل التصحيح.

هناك طريقتان اثنتان بالضبط لوضع نص أمام الوكيل انطلاقا من أي حدث آخر:

  1. اخرج برمز 2 واكتب على stderr. عند الخروج برمز 2، يتجاهل Claude Code محتوى stdout وأي JSON فيه، ويمرر stderr إلى الوكيل بوصفه رسالة خطأ.
  2. اخرج برمز 0 واطبع كائن JSON يحمل hookSpecificOutput.additionalContext.

لاحظ اللاتناظر في الأولى. الخروج برمز 0 يعني أن stdout مهم وأن stderr غير مهم. والخروج برمز 2 يعني أن stderr مهم وأن stdout يُهمل تماما. عكس هذين هو سبب أن يبدو خطاف صحيحا تماما ويظل أخرس مع ذلك.

أي رمز خروج آخر هو خطأ غير حاجب. يعرض سجل المحادثة إشعار <hook name> hook error مع أول سطر من stderr، ويستمر التنفيذ، ويحط stderr كاملا في سجل التصحيح.

مخطط لرموز خروج خطافات Claude Code: الخروج برمز 0 يرسل JSON الموجود في stdout إلى الوكيل في ثلاثة أحداث فقط، والخروج برمز 2 يحظر الإجراء ويرسل stderr إلى الوكيل، وأي رمز خروج آخر هو خطأ غير حاجب يُكتب في سجل التصحيح.

أي قناة تصل إلى الوكيل، بحسب رمز الخروج. المسار المتقطع هو المسار الذي يفترض الناس وجوده وهو غير موجود.

نصفها بالضبط يمكنه الحظر

خمسة عشر حدثا توقف الإجراء عند الخروج برمز 2. وخمسة عشر تتجاهله وتمضي.

يمكنها الحظر: PreToolUse، PermissionRequest، UserPromptSubmit، UserPromptExpansion، Stop، SubagentStop، TeammateIdle، TaskCreated، TaskCompleted، ConfigChange، PostToolBatch، PreCompact، Elicitation، ElicitationResult، WorktreeCreate.

لا يمكنها الحظر: PostToolUse، PostToolUseFailure، PermissionDenied، StopFailure، Notification، SubagentStart، SessionStart، Setup، SessionEnd، CwdChanged، FileChanged، PostCompact، WorktreeRemove، InstructionsLoaded، MessageDisplay.

النتيجة العملية: حاجز الحماية مكانه PreToolUse، لا PostToolUse أبدا. ينطلق PostToolUse بعد نجاح الأداة. الخروج برمز 2 هناك لا يتراجع عن الكتابة، بل يطبع خطأ فقط بينما الضرر قابع على القرص. إن أردت إيقاف rm -rf فلديك مكان واحد بالضبط لفعل ذلك.

كون PostToolBatch قادرا على الحظر بينما PostToolUse غير قادر يستحق نظرة ثانية. معناه أن فحصا على مستوى الدفعة ما زال بإمكانه إيقاف الدور بعد نزول التعديلات المتوازية، وهو أقرب شيء إلى نقض بعد الكتابة يقدمه النظام.

مطابقات matcher تامة، إلى أن تكفّ فجأة عن ذلك

يبدّل حقل matcher استراتيجية التقييم بناء على محارفه هو، ولا شيء يخبرك أي مسار سلك.

matcherيُقيَّم بوصفه
"*" أو "" أو محذوفيطابق كل شيء
حروف وأرقام و_ و- ومسافات و, و| فقطسلسلة تامة، أو قائمة سلاسل تامة مقسّمة على | أو ,
أي شيء آخرتعبير نمطي JavaScript غير مثبّت الطرفين

عدم تثبيت الطرفين هو الفخ. المرجع صريح في أن التعبير النمطي يُختبر بـ RegExp.prototype.test، وهو ينجح عند وجود تطابق في أي موضع من القيمة. لذا فإن Edit.* يطابق Edit وNotebookEdit. إن كنت تقصد أداة واحدة، فاكتب ^Edit$.

سلوكان يعتمدان على الإصدار، يحسن معرفتهما قبل أن تصحّح المشكلة الخطأ:

  • الفواصل بوصفها فواصل فصل والتسامح مع المسافات البيضاء يحتاجان Claude Code v2.1.191 أو أحدث.
  • انضمت الواصلة إلى مجموعة محارف المطابقة التامة في v2.1.195. قبل ذلك، كان مطابق مثل code-reviewer يُعامل كتعبير نمطي غير مثبّت الطرفين، فينطلق أيضا مع senior-code-reviewer.

في AgentsRoom نحصر خطاف نسبة الملفات الخاص بنا بـ Write|Edit|MultiEdit|NotebookEdit، وهو يبقى على مسار السلسلة التامة ويطابق تلك الأدوات الأربع ولا شيء غيرها. أما خطافات دورة الحياة التي نثبّتها فلا تحمل أي مطابق، لأنها تعنينا دائما.

ستة أماكن يمكنها تعريف الخطافات، وهي تندمج

الغريزة هي البحث عن ترتيب أولوية. لا وجود له، وهذا هو الجزء المثير للاهتمام.

الموقعالنطاق
~/.claude/settings.jsonكل مشاريعك، محلي على جهازك
.claude/settings.jsonمشروع واحد، قابل للإيداع في git
.claude/settings.local.jsonمشروع واحد، يستثنيه Claude Code من git
Managed policy settingsعلى مستوى المؤسسة، يتحكم فيه المسؤول
hooks/hooks.json الخاص بالإضافةطالما كانت الإضافة مفعّلة
ترويسة مهارة أو وكيلطالما كان المكوّن نشطا

من المرجع:

تندمج مدخلات الخطافات عبر مستويات الإعدادات بدل أن يحل بعضها محل بعض: إعدادات المستخدم وإعدادات المشروع والإعدادات المحلية تضيف خطافاتها الخاصة دون إزالة الخطافات المُدارة، ولا يستطيع إعداد disableAllHooks تعطيل الخطافات المُدارة من خارج الإعدادات المُدارة.

إذن لا يتجاوز خطاف المشروع خطافا عاما أبدا، بل يتراكم فوقه. ستة مصادر، كلها تراكمية. منسّق PostToolUse معرّف في إعدادات المستخدم ثم معرّف مرة أخرى في المشروع ينفَّذ مرتين عند كل تعديل، والعرض الوحيد لذلك هو الإحساس بالبطء.

مخطط يوضح مواقع الإعدادات الستة في Claude Code التي يمكنها تعريف الخطافات، وكلها تندمج تراكميا في مجموعة خطافات واحدة بدل أن يتجاوز بعضها بعضا.

ستة مصادر، مجموعة واحدة مدمجة. لا شيء هنا يتجاوز شيئا.

هذا يفسر أيضا لماذا .claude/settings.local.json هو المكان الصحيح لأداة تريد تثبيت خطاف داخل مشروع شخص آخر. نطاقه هو المشروع، ويستثنيه Claude Code من git، ويُحمَّل من دون أي راية في سطر الأوامر. هناك يكتب AgentsRoom مدخلاته، فلا يُمَس أبدا ملف .claude/settings.json المُودع لدى المستخدم، ولا يرث زملاؤه أبدا مسارا خاصا بجهاز بعينه.

ما علّمنا إياه تشغيل الخطافات في الإنتاج

يثبّت AgentsRoom خطافات في كل مشروع يفتحه، ليتتبع حالة الوكلاء بشكل حتمي وينسب الملفات المعدَّلة إلى الوكيل الصحيح. بعض الأمور لا تظهر إلا على هذا المقياس.

أسماء الأحداث غير المعروفة تُتجاهل بصمت. هذا غير موجود في التوثيق، ونحن نعتمد عليه. حين نضيف حدث دورة حياة جديدا إلى مثبّتنا، يحصل المستخدمون العاملون على إصدار أقدم من الـ CLI على settings.local.json يحتوي اسم حدث لم يسمع به ملفهم التنفيذي قط. لا شيء ينكسر، ولا شيء يحذّر، ويُتخطى المدخل ببساطة. هذا ما يجعل شحن المثبّت قبل إصدار الـ CLI آمنا. وهو أيضا، حتما، سبب أن يُنتج خطأ إملائي صمتا تاما بدل رسالة خطأ.

agent_id هو ما يخبرك أنك داخل وكيل فرعي. الحقل موجود فقط حين ينطلق الخطاف داخل استدعاء وكيل فرعي. وهذا أهم مما يبدو: ينطلق Stop حين ينهي وكيل فرعي دوره، لا عند الوكيل الرئيسي فقط. قاعدة ساذجة من نوع "علّم الجلسة منتهية عند Stop" تعلّم الجلسة كلها منتهية أول مرة يعود فيها أي وكيل فرعي. نحن نتخطى أحداث الدور التي تحمل agent_id لهذا السبب بالضبط.

لا تقرأ transcript_path للدور الحالي. يحذّر المرجع من أن سجل المحادثة يُكتب بشكل غير متزامن وقد يتأخر عن المحادثة الموجودة في الذاكرة، فقد لا تكون أحدث الرسائل موجودة فيه بعد حين ينطلق خطافك. يتلقى Stop وSubagentStop الحقل last_assistant_message تحديدا حتى لا تضطر أبدا إلى مسابقة الملف.

الخطافات هي إشارة الحالة الموثوقة الوحيدة. قبل الخطافات، كنا نكشط الـ PTY لنعرف ما إذا كان الوكيل يفكر أو ينتظر أو انتهى. ينكسر ذلك في اللحظة التي يعرض فيها الـ CLI عبر شاشة الطرفية البديلة، وهو ما يفعله /tui fullscreen. تنطلق الخطافات بالطريقة نفسها تحت كل محرك عرض. إن كنت تبني أي شيء يراقب وكيلا من الخارج، فهذه هي الطبقة التي تُبنى عليها، ويبقى الكشط حلا احتياطيا في أحسن الأحوال.

async: true لا يكلف شيئا. يستطيع أمر الخطاف أن يعلن async: true، فلا ينتظره الوكيل. خطافنا يرسل POST إلى نقطة نهاية محلية بسقف قدره ثانيتان ثم يعود، وزمن استجابة دور الوكيل لا يتأثر حتى حين يكون التطبيق المستقبِل مغلقا. إن كان خطافك يراقب فقط ولا يقرر أبدا، فاجعله غير متزامن وتوقف عن دفع ثمنه.

لا تدع خطافا يكتب نفايات في الطرفية أبدا. سكربتنا يبتلع كل استثناء، بما في ذلك على المستوى الأعلى. تتبّع استدعاءات Python غير معالَج قادم من خطاف لا يفشل بهدوء فحسب، بل يطبع مكدس التتبّع داخل جلسة طرفية المستخدم في وسط عمله.

المهل الزمنية

القيم الافتراضية سخية، مع ثلاثة استثناءات ليست كذلك:

نوع الخطافالمهلة الافتراضية
command، http، mcp_tool600 s
prompt30 s
agent60 s
UserPromptSubmit (command, http, mcp_tool)30 s
MessageDisplay (command, http, mcp_tool)10 s
SessionEnd1.5 s مشتركة بين كل الخطافات، تُرفع لتطابق timeout أطول محدد لخطاف بعينه، حتى 60 s

ميزانية SessionEnd هي التي تفاجئ الناس. إنها ميزانية مشتركة، لا مخصص لكل خطاف على حدة، فثلاثة خطافات تنظيف تتقاسم 1.5 ثانية بينها ما لم ترفعها صراحة.

النسخة المختصرة

  • 30 حدثا موجودة. ستة منها مشهورة.
  • يصل stdout إلى الوكيل في UserPromptSubmit وUserPromptExpansion وSessionStart فقط. في كل مكان آخر، استخدم الخروج برمز 2 مع stderr، أو additionalContext داخل JSON.
  • 15 حدثا تحظر عند الخروج برمز 2، و15 تتجاهله. حواجز الحماية مكانها PreToolUse.
  • مطابقات matcher سلاسل تامة إلى أن يحوّلها محرف خاص إلى تعبير نمطي غير مثبّت الطرفين.
  • ستة مصادر إعدادات تندمج تراكميا. لا شيء يتجاوز شيئا.
  • اسم حدث مكتوب بشكل خاطئ يفشل بصمت تام.

إن أردت أن تشاهد هذه الأحداث وهي تنطلق بدل أن تستنتجها بالتفكير، فهذا ما بنيناه: يعرض AgentsRoom كل إطلاق خطاف، لكل وكيل، ولكل مشروع، ولكل تشغيل، عبر عشرات الوكلاء المتوازيين وجلسات الوكلاء الفرعيين. الخطافات التي تضبطها في إعداداتك الخاصة تظل تعمل تماما كما كُتبت، لأنه يشغّل الـ CLI الحقيقي.

تابع القراءة

تحميل AgentsRoom

شغّل وكلاء الذكاء الاصطناعي (Claude، Codex، Antigravity CLI، OpenCode، Aider، Grok Build، Mistral Vibe، Kimi Code) على جميع مشاريعك من نافذة واحدة.

مجانيتحميل AgentsRoom

التطبيق المرافق: تابع وكلاءك أينما كنت

استخدم Claude أو Codex أو Antigravity CLI أو أي مزود AI آخر.

تثبيت الملحق
Chrome Web Store

أرسل الأخطاء والطلبات مباشرة إلى قائمة المهام العامة.

لمحة عن AgentsRoom أثناء العمل.

مشاريع متعددة
متعدد المزوّدين
وكلاء متعددون
حالة مباشرة
فرق الملفات والإيداع
تطبيق الهاتف
معاينة مباشرة
فرق الوكلاء
أتمتة المتصفح
تطوير موجّه بالـ backlog
مكتبة البرومبت
مكتبة المهارات
عرض جميع الميزات