خطافات Cursor: دليل شامل، ولماذا لا تعمل أحيانًا
تتيح خطافات (hooks) Cursor لسكربت أن يراقب ما يفعله الوكيل أو يحظره: كل أمر shell، وكل استدعاء MCP، وكل قراءة ملف وتعديله. إنها قوية، وتفشل بطرق صامتة. هذا كل ما تعلّمناه من ربطها في عمل حقيقي.
الإجابة المختصرة
ضع ملف hooks.json يحتوي على "version": 1 في ~/.cursor/ (لكل المشاريع) أو في .cursor/ داخل مستودع، واربط كل حدث بأمر، واطبع JSON على stdout. استخدم beforeShellExecution وbeforeMCPExecution للسماح أو الرفض أو السؤال، واضبط failClosed: true إذا كان يجب أن يحظر الخطاف المعطّل بدلًا من السماح بمرور الأمر. عندما يبدو أن خطافًا متجاهَل، افتح قناة مخرجات Hooks أولًا: معظم المشكلات سببها مسار، أو مساحة عمل غير موثوقة، أو JSON غير صالح، أو حدث لا ترسله Cursor CLI بعد.
ما هي خطافات Cursor
الخطاف أمر يشغّله Cursor عند نقطة محددة في حلقة عمل الوكيل. يرسل Cursor كائن JSON يصف ما هو على وشك الحدوث إلى الإدخال القياسي للأمر، وينتظر، ثم يقرأ إجابة JSON من مخرجاته القياسية. بعض الخطافات تراقب فقط (تسجّل التعديل، أو تنسّق الملف). وبعضها الآخر يقرر: خطاف beforeShellExecution يمكنه السماح بتشغيل أمر، أو إيقافه، أو سؤالك أولًا.
وهذا يجعل الخطافات الأداة المناسبة لثلاث مهام: الحواجز الوقائية (لا تشغّل rm -rf أو git push --force أبدًا دون إنسان)، والأتمتة (التنسيق أو الفحص بعد كل تعديل)، والرؤية (تسجيل ما يفعله الوكيل أو تمريره حتى تعرف متى يحتاجك).
أين يوجد ملف hooks.json
يقرأ Cursor الخطافات من أربعة أماكن ويشغّلها كلها. كل خطاف مطابق من كل مصدر يعمل، ويدمج Cursor إجاباتها.
| المستوى | الملف | ملاحظات |
|---|---|---|
| المستخدم | ~/.cursor/hooks.json | يُطبَّق على كل المشاريع. تُحَل الأوامر النسبية انطلاقًا من ~/.cursor/. |
| المشروع | <project>/.cursor/hooks.json | مُضاف إلى المستودع. لا يعمل إلا في مساحة عمل موثوقة. تُحَل الأوامر النسبية انطلاقًا من جذر المشروع. |
| الفريق | لوحة تحكم Cursor على الويب | لخطة Enterprise فقط، ويُزامَن مع كل عضو. |
| المؤسسة | C:\ProgramData\Cursor\hooks.json (Windows)، و/Library/Application Support/Cursor/hooks.json (macOS)، و/etc/cursor/hooks.json (Linux وWSL) | يديره قسم تقنية المعلومات. |
عندما تختلف الإجابات، تُطبَّق الأكثر صرامة: deny من أي مصدر يتقدم على ask، وask يتقدم على allow. أصغر ملف يعمل يبدو هكذا (وهو المثال الموجود في وثائق Cursor):
يجب أن تكون قيمة version هي 1. يراقب Cursor الملف ويعيد تحميله عند الحفظ. إذا لم يسرِ تغيير ما، فأعد تشغيل Cursor. هذا وحده يحل عددًا مفاجئًا من البلاغات في المنتدى.
الأحداث التي يمكنك ربط خطافات بها
القائمة الحالية من وثائق Cursor، مجمّعة حسب الغرض منها:
| المجموعة | الأحداث | هل يمكنه الحظر؟ |
|---|---|---|
| Shell وMCP | beforeShellExecution, afterShellExecution, beforeMCPExecution, afterMCPExecution | خطافا before…: السماح أو الرفض أو السؤال |
| أي أداة | preToolUse, postToolUse, postToolUseFailure | preToolUse: السماح أو الرفض (السؤال غير مُطبَّق حاليًا) |
| الملفات | beforeReadFile, afterFileEdit | beforeReadFile: السماح أو الرفض |
| الموجّه (Prompt) | beforeSubmitPrompt | نعم، مع continue: false |
| حلقة الوكيل | stop, afterAgentResponse, afterAgentThought, preCompact | لا (يمكن لـ stop إرسال رسالة متابعة) |
| الوكلاء الفرعيون | subagentStart, subagentStop | subagentStart: السماح أو الرفض (السؤال يُحتسب رفضًا) |
| الجلسة والتطبيق | sessionStart, sessionEnd, workspaceOpen | لا |
| إكمالات Tab | beforeTabFileRead, afterTabFileEdit | beforeTabFileRead: السماح أو الرفض |
يتلقى كل حدث بضعة حقول مشتركة (conversation_id وgeneration_id وmodel وhook_event_name وcursor_version وworkspace_roots) إضافةً إلى حقوله الخاصة. يحصل beforeShellExecution على command كاملًا ومعه cwd؛ ويحصل stop على status بقيمة completed أو aborted أو error.
السماح والرفض والسؤال
يطبع الخطاف الذي يتخذ القرار كائن JSON واحدًا. في خطاف shell يبدو هكذا:
- قيمة
permissionهيallowأوdenyأوask. user_messageهو ما تراه أنت في Cursor.agent_messageهو ما يُبلَّغ به الوكيل، حتى يغيّر مساره بدلًا من إعادة محاولة الأمر نفسه.
رموز الخروج مهمة بقدر أهمية JSON. الخروج بالرمز 0 يعني «استخدم JSON الخاص بي». والخروج بالرمز 2 يحظر الإجراء، تمامًا مثل deny. أي رمز خروج آخر يُعامَل على أنه خطاف فاشل، ويستمر الإجراء، ما لم تضبط failClosed. في خطافات الأذونات، يؤدي JSON غير الصالح أو JSON الذي لا يطابق المخطط إلى حظر الإجراء.
تذكر وثائق Cursor أن ask مدعوم في beforeShellExecution وbeforeMCPExecution. في مارس 2026 كتب فريق Cursor في المنتدى أن الخطافات لم تكن تفرض إلا deny، وأن allow وask كانتا «basically ignored» (متجاهَلتين عمليًا)، خاصةً مع تفعيل قائمة السماح بالأوامر أو بيئة الحماية (sandbox). لم نجد إعلانًا عن إصلاح. إذا كان يجب أن يصمد حاجز وقائي، فأعد deny وليس ask، واختبره في إصدارك.
failClosed والمهلة
يمكن لكل إدخال خطاف أن يحمل خيارات بجوار command:
failClosed: trueيحوّل الانهيار أو انتهاء المهلة أو رمز الخروج غير الصفري أو المخرجات الفارغة إلى حظر. القيمة الافتراضيةfalse: خطاف الحماية المعطّل يسمح بمرور كل شيء بصمت. في خطافات الأمان تريدtrueفي معظم الأحيان.timeoutبالثواني. اترك هامشًا كافيًا إذا كان خطافك ينتظر إنسانًا: الشخص الذي يقرأ الفروقات (diff) يحتاج إلى أكثر من خمس ثوانٍ.matcherيحدد متى يعمل الخطاف. في خطافات shell يُطابَق مع سلسلة الأمر الكاملة؛ وفي خطافات الأدوات مع نوع الأداة، مثلShellأوReadأوWriteأوMCP:<tool_name>.
هناك مقايضة. في يوليو 2026 واجه مستخدم على macOS الخطأ «MainThreadShellExec not initialized»: مضيف الـ shell الخاص بـ Cursor لم يكن جاهزًا، ولأن الخطاف كان مضبوطًا على الحظر عند الفشل (fail-closed)، حُظر الـ shell الخاص بالوكيل. قال فريق Cursor إن الإصلاح قد طُرح، وأوصى بالإبقاء على failClosed: true. إذا رأيت هذا الخطأ في إصدار أقدم، فالحل المؤقت كان «Developer: Reload Window».
الخطافات على Windows
على Windows يشغّل تطبيق Cursor لسطح المكتب أوامر الخطافات عبر PowerShell ويمرّر إليها JSON. يقرؤه سكربت PowerShell من $input؛ وأي برنامج آخر يقرأ الإدخال القياسي كالمعتاد. ثلاثة أمور توقع الناس في الخطأ:
- سكربتات Bash لا تعمل كما هي. ملف
guard.shمن زميل يستخدم macOS يفشل في PowerShell. استخدم سكربت.ps1، أو برنامجًا مُصرَّفًا، أو استدعِ المفسّر صراحةً (python .cursor/hooks/guard.py). تُظهر سلسلة في المنتدى من يناير 2026 إعدادًا بـ Git Bash يفشل معsyntax error near unexpected token '[Convert]::FromBase64String'، وهي شيفرة PowerShell تصل إلى bash. - سياسة التنفيذ. إذا رفض PowerShell تشغيل السكربتات، فابدأها بـ
powershell -NoProfile -ExecutionPolicy Bypass -File …، واطبع JSON، واختم بـexit 0. - برامج الواجهة الرسومية تعود مبكرًا جدًا. هذه كلفتنا يومًا كاملًا. إذا كان خطافك برنامج Windows مبنيًا للنظام الفرعي للواجهة الرسومية (GUI)، فإن PowerShell يشغّله ويمضي دون انتظار. يقرأ Cursor مخرجات فارغة، فيبدو الخطاف وكأنه لم يفعل شيئًا (أو يحظر كل شيء مع
failClosed). ابنِ الخطاف كبرنامج وحدة تحكم (console)، أو غلّفه حتى ينتظر PowerShell خروجه.
تحتاج خطافات مستوى المشروع أيضًا إلى مساحة عمل موثوقة. عدّد أحد أعضاء فريق Cursor ما يجب التحقق منه عندما لا تفعل شيئًا: سطر سجل Hooks «Hook N produced no output»، وظهور مساحة العمل على أنها موثوقة في Settings → Hooks، وأخطاء مثل spawn أو ENOENT أو EPERM أو ExecutionPolicy في وحدة التحكم.
الخطافات في Cursor CLI
تقرأ Cursor CLI (cursor-agent) الملفين نفسيهما ~/.cursor/hooks.json و.cursor/hooks.json، لكنها لم ترسل يومًا كل الأحداث التي يرسلها المحرر. في يناير 2026 لم يكن يعمل سوى خطافَي shell. وبحلول أبريل أكد فريق Cursor أن beforeShellExecution وafterShellExecution وafterFileEdit وpostToolUse وstop وsessionStart تعمل في CLI، بينما لم تكن afterAgentResponse وafterAgentThought تعمل بعد (وتأكد ذلك مجددًا في مايو). أما أي حدث غير موجود في هذه القائمة فاختبره قبل أن تعتمد عليه.
الوكلاء السحابيون أكثر صرامة: خطافات مستوى المستخدم من ~/.cursor/hooks.json لا تعمل هناك إطلاقًا.
عندما لا يعمل خطاف: قائمة تحقق
- افتح قناة مخرجات Hooks (View → Output → Hooks) أو علامة تبويب Hooks في Customize. تعرض الخطافات المحمّلة، وكل تشغيل، والأخطاء.
- تحقق من ملف JSON نفسه. وجود
"version": 1، وكتابة أسماء الأحداث بدقة (فهي حساسة لحالة الأحرف)، وصلاحية JSON. - تحقق من المسار. تُحَل الأوامر النسبية انطلاقًا من جذر المشروع لخطافات المشروع، ومن
~/.cursor/لخطافات المستخدم. - ثِق بمساحة العمل. خطافات المشروع لا تعمل في مجلد غير موثوق.
- شغّل الخطاف يدويًا. مرّر إليه JSON تجريبيًا وانظر إلى stdout. أي شيء غير كائن JSON واحد (
echoشارد، أو تحذير) يُفسد التحليل. - أعد تشغيل Cursor. الحفظ يعيد تحميل الملف، لكن عدة بلاغات في المنتدى لم تُحل إلا بإعادة تشغيل كاملة.
- اعرف الثغرات. أُبلغ عن تجاهل
askوallowبوجود قائمة السماح والـ sandbox؛ وأُبلغ عن عدم عملsubagentStart/subagentStopفي بعض الإصدارات؛ وتتخطى CLI بعض الأحداث. لا تُعترَض عمليات commit من لوحة Source Control المدمجة: لا يوجد حدث خطاف قبل الـ commit.
الخطافات والتشغيل التلقائي (Auto-run) والمراجعة التلقائية (Auto-review)
الخطافات منفصلة عن إعدادات الموافقة الخاصة بـ Cursor (Settings → Agents → Approvals & Execution). يحدد Auto-run وAuto-review ما إذا كان Cursor سيسألك في لوحته؛ ويضيف خطافك قراره الخاص فوق ذلك. ولهذا فإن بلاغ «قال خطافي ask، لكن الأمر نُفّذ مباشرة» شائع جدًا: مسار أذونات آخر كان قد سمح به بالفعل.
أمر آخر تعلّمناه بالطريقة الصعبة: مع Auto-review قد يسأل Cursor عن بعض الأوامر في نافذته الخاصة. والخطاف لا يرى هذا السؤال أبدًا. فهو يحدث داخل Cursor، وليس في مسار الخطافات.
أين يأتي دور Pet Island
إذا كان ما تريده من الخطافات هو «أرني كل أمر خطر ودعني أقرر دون التبديل بين النوافذ»، فهذا ما يفعله Pet Island مع Cursor. يثبّت الخطافات نيابةً عنك (beforeShellExecution وbeforeMCPExecution، مع تفعيل failClosed حتى لا تسمح أداة مساعدة متوقفة بمرور أي أمر أبدًا) ويضع كل طلب في جزيرة صغيرة أعلى الشاشة مع الأمر كاملًا. تسمح به أو ترفضه هناك؛ ووكيل Cursor نفسه ينتظر.
الأوامر وتعديلات الملفات من محرر Cursor تعمل من الجزيرة. الأسئلة والخطط تظهر على الجزيرة، وتجيب عنها في Cursor. في Cursor CLI تعمل الأوامر من الجزيرة؛ أما الأحداث الأخرى فتعتمد على ما ترسله CLI. إلغاء التثبيت يزيل فقط الإدخالات التي أضافها Pet Island؛ وتبقى خطافاتك الخاصة.
الأسئلة الشائعة
هل تعمل خطافات Cursor على Windows؟
نعم. يشغّلها تطبيق سطح المكتب عبر PowerShell ويمرّر JSON على الإدخال القياسي ($input في سكربت PowerShell). سكربتات Bash المكتوبة لـ macOS تحتاج إلى نسخة PowerShell أو Python، ويجب تغليف برامج النظام الفرعي للواجهة الرسومية حتى ينتظرها PowerShell.
لماذا يعيد خطافي ask ومع ذلك يُنفَّذ الأمر؟
قال فريق Cursor في مارس 2026 إن الخطافات لم تكن تفرض بشكل موثوق إلا deny؛ وإن allow وask قد تتجاوزهما قائمة السماح أو الـ sandbox. استخدم deny لأي شيء يجب ألا يُنفَّذ، وتحقق من قناة مخرجات Hooks لترى ما أعاده خطافك فعلًا.
ماذا يفعل failClosed؟
عند ضبط failClosed على true، يؤدي الانهيار أو انتهاء المهلة أو رمز الخروج غير الصفري أو المخرجات الفارغة إلى حظر الإجراء. ودونه يسمح الخطاف المعطّل باستمرار الإجراء.
أين أرى أخطاء الخطافات؟
في قناة مخرجات Hooks (View → Output → Hooks) وفي علامة تبويب Hooks في Customize.
هل تعمل الخطافات في Cursor CLI؟
جزئيًا. تقرأ CLI ملفات hooks.json نفسها. حتى مايو 2026 أكد فريق Cursor عمل خطافات shell وafterFileEdit وpostToolUse وstop وsessionStart، دون afterAgentResponse أو afterAgentThought.
هل يمكن لخطاف إيقاف commit في git من لوحة Source Control؟
لا. لا يوجد في Cursor حدث خطاف قبل الـ commit، ولا تُعترَض عمليات commit التي تتم عبر واجهة Source Control المدمجة. استخدم خطاف pre-commit عاديًا في git لذلك.
المصادر
راجعنا كل إعداد وسلوك في هذه الصفحة مقابل هذه الصفحات بتاريخ 26 أكتوبر 2026. الوكلاء يتغيرون بسرعة؛ فإذا لم يعد شيء مطابقًا، فالمرجع هو الصفحة الرسمية.
- وثائق Cursor: الخطافات (Hooks)
- منتدى Cursor: لم تُنفَّذ خطافات Cursor كما هو متوقع (الفريق: deny فقط هو المُطبَّق)
- منتدى Cursor: تجاهل allow/ask في beforeShellExecution، وقائمة السماح لها الأولوية
- منتدى Cursor: خطاف يحظر عند الفشل (fail-closed) وخطأ MainThreadShellExec not initialized
- منتدى Cursor: JSON مشوّه من خطاف سمح بالأمر بصمت (أُصلح)
- منتدى Cursor: Cursor CLI لا ترسل كل أحداث الخطافات
- منتدى Cursor: فشل تنفيذ خطافات مستوى المشروع على Windows
- منتدى Cursor: خطافات المشروع تفشل على Windows مع Git Bash
- منتدى Cursor: subagentStart وsubagentStop لا يعملان أبدًا