الخطّافات هي أوامر Claude Code يشغّلها في نقاط ثابتة في جلسة: قبل استدعاء أداة، بعده، عندما ينتهي دور. هذا كيفية تنسيق الملفات، ورفض التحريرات إلى .env, وتسجيل أوامر shell بدون تذكر الطلب. أوامر مائلة التي يكتبها إنسان تعيش في أوامر مائلة مخصصة. هذه الصفحة هي المسار التلقائي.
حيث تُنسق الخطّافات
تعريف خطّاف له ثلاثة مستويات: الحدث، مجموعة محقق، ومعالجات واحدة أو أكثر.
| قطعة | مثال |
|---|---|
| الحدث | PreToolUse, PostToolUse, Stop |
| محقق | اسم الأداة أو نوع الإخطار. احذفه فقط في الأحداث التي تتجاهل المحققات |
| معالج | "type": "command" بالإضافة إلى أمر shell |
| ملف | نطاق | شارك مع git |
|---|---|---|
~/.claude/settings.json |
جميع المشاريع على هذا الجهاز | لا |
.claude/settings.json |
هذا المستودع | نعم |
.claude/settings.local.json |
هذا المستودع، أنت فقط | تُتجاهل عندما يحفظ Claude Code إعدادا هناك |
على Windows، ~/.claude هو %USERPROFILE%\.claude. السياسة المدارة والمكونات الإضافية يمكنها إضافة المزيد من الخطّافات. الأمثلة الخمسة أدناه تنتمي إلى ملف المشروع بحيث الفريق يشاركها.
معالجات يمكنها أن تكون أمر shell أو POST HTTP أو موجه أو وكيل أو أداة MCP. هذه الأمثلة تستخدم type: command لأن السكريبت مرئي في المستودع. أوامر الخطّاف تستقبل الحدث JSON على stdin.
$CLAUDE_PROJECT_DIR هو جذر المشروع Claude Code يُصدّره لأوامر الخطّاف. اقتبسه. المسارات التي فيها فراغات سيتم تقسيمها بخلاف ذلك.
mkdir -p .claude/hooks
chmod +x .claude/hooks/*.sh
على macOS و Linux السكريبت يجب أن يكون قابلا للتنفيذ. على Windows أصلي، ثبت Git for Windows. إذا أبلغ الخطّاف بأن Git Bash لم يُعثر عليه، الخطّاف يمكنه حجب استدعاء الأداة حتى تتوفر Bash. خطوات التثبيت تغطي هذا المثبت.
/hooks قوائم ما حمّلت الجلسة. "disableAllHooks": true في ملف إعدادات يطفئ الخطّافات في ذلك المستوى بعد تطبيق الأولوية. سياسة مدارة لا تزال تستطيع فرض الخطّافات.
إذا حرّرت ملف الإعدادات بينما الجلسة مفتوحة، مراقب الملفات عادة يعيد تحميل الخطّافات بنفسه.
الأحداث التي تستحق المعرفة
المرجع يوثّق الكثير من الأحداث. هذه التي تستخدمها الأمثلة، بالإضافة إلى الجيران التي ستراها في /hooks.
| الحدث | متى يطلق | محقق |
|---|---|---|
PreToolUse |
قبل تشغيل أداة. يمكنه حجبها | اسم الأداة: Bash, Edit, Write |
PostToolUse |
بعد أداة تنجح | اسم الأداة |
Notification |
عندما Claude Code يصدر إخطارا | نوع الإخطار، بما في ذلك permission_prompt, idle_prompt, auth_success, agent_needs_input, agent_completed |
Stop |
عندما Claude ينتهي من رد | لا أحد. يعمل دائما |
SubagentStop |
عندما وكيل فرعي ينتهي | نوع الوكيل |
UserPromptSubmit |
عندما موجه مُرسل، قبل Claude يتعامل معه. أيضا على أدوار Claude Code يبدأها نفسه | لا أحد. يعمل دائما |
agent_completed يطلق فقط بينما عرض الوكيل مفتوح، لذا هو سيء “المهمة تمت” إشارة. استخدم Stop لنهاية دور.
أيضا موثّق، وترك من السكريبتات هنا: SessionStart, SessionEnd, Setup, PostToolUseFailure, PermissionRequest, PermissionDenied, SubagentStart, PreCompact, PostCompact, StopFailure, FileChanged, ConfigChange. المحققات وحقول JSON لتلك تعيش في مرجع الخطّافات. استدعاءات أداة EndConversation تتخطى PreToolUse و PostToolUse.
محقق هو تعبير نمطي JavaScript مختبِر ضد الحقل، ومطابقة في أي مكان في القيمة يحسب. Edit لذا يطابق أيضا NotebookEdit. الأنماط أدناه تستخدم ^Edit$|^Write$ بحيث فقط تلك الأداتان تشغّل السكريبت. المرجع يقبل | بين البدائل على أحداث الأداة. الأمثلة الرسمية غالبا تظهر النموذج الأقصر Edit|Write. استخدم الشكل الموضح عندما اسم أداة أطول يجب أن يبقى خارج.
Stop و UserPromptSubmit تتجاهل المحققات. محقق على تلك الأحداث لا يصفيها.
الحقول الشائعة على stdin تشمل session_id, cwd, و hook_event_name. أحداث الأداة تضيف tool_name, tool_input, و tool_use_id. لـ Bash, سلسلة shell هي tool_input.command. لـ Edit و Write, المسار هو tool_input.file_path.
أكواد الخروج و JSON
| كود الخروج | النتيجة |
|---|---|
| 0 | النجاح. كائن JSON واحد على stdout يُطبّق. خرج آخر هو نص عادي |
| 2 | خطأ حاجب في الأحداث التي يمكنها حجب. stderr هو السبب، ما لم يكن JSON قد حمل قرارا بالفعل |
| أي شيء آخر | خطأ غير حاجب. الإجراء يستمر، و النسخة الشفافة تظهر خطأ خطّاف |
على PreToolUse, هذا JSON يرفض الاستدعاء بدون الاعتماد على الخروج 2:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "مسار محمي"
}
}
permissionDecision قد يكون deny, ask, أو allow. الخروج 2 لا يزال يحجب حتى إذا كان JSON يقول allow.
Stdout هو JSON فقط عندما هو كائن واحد وليس شيء آخر مطبوع. jq -n هو طريقة موثوقة لطباعة ذلك الكائن. سطران log قبل JSON يحولان الإخراج إلى نص عادي.
على PostToolUse, الأداة قد انتهت بالفعل. الخروج 2 لا يُرجع التحرير. فإنه يُرجع stderr مرة أخرى إلى Claude. الخروج 0 stdout من PostToolUse يذهب إلى سجل تصحيح، ليس إلى النموذج. UserPromptSubmit مختلفة: stdout نصي يُضاف إلى السياق Claude يمكنه قراءته، والخروج 2 يرفض الموجه.
Stop يمكنه حجب وطلب Claude لتبقى. بعد ثمان حجب متتالية بدون استدعاء أداة بينها، Claude Code يستمر على أي حال. السكريبتات في هذا المختبر تخرج 0 على Stop بحيث هي فقط تخطّر.
خمسة خطّافات
السكريبتات تفترض jq مثبت (brew install jq أو حزمة توزيعك). هي وسائط أصلية حول حقول stdin أعلاه.
1. نسّق مع Prettier أو Black
.claude/hooks/format-file.sh
#!/bin/bash
# نسّق الملف الذي كتبه Claude للتو، حسب الامتداد.
input=$(cat)
path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty')
[ -z "$path" ] && exit 0
[ -f "$path" ] || exit 0
case "$path" in
*.js|*.jsx|*.ts|*.tsx|*.css|*.md|*.json|*.yml|*.yaml)
npx prettier --write "$path" || exit 0
;;
*.py)
if command -v black >/dev/null 2>&1; then
black "$path" || exit 0
fi
;;
esac
exit 0
أعطال المنسّق تخرج 0 بقصد. تثبيت Prettier مفقود لا يجب أن يبدو محتجزا. إذا أردت Claude ترى حادثة منسّق، أخرج 2 واطبع الخطأ على stderr بدلا من ذلك.
سجّلها على PostToolUse:
{
"hooks": {
"PostToolUse": [
{
"matcher": "^Edit$|^Write$",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-file.sh",
"timeout": 30
}
]
}
]
}
}
timeout هو ثواني. الافتراضي لأمر خطّاف هو 600، الذي طويل جدا لمنسّق. أمر Bash يُعيد كتابة ملف لا يطابق Edit أو Write. حدث FileChanged هو الحدث الذي يُراقب مسارا بغض النظر عن أي أداة كتبته.
Prettier و Black كلاهما يعيد كتابة الملف على القرص بعد تحرير Claude. القراءة التالية ترى النسخة المنسّقة.
2. احجب التحريرات للملفات المحمية
.claude/hooks/protect-files.sh
#!/bin/bash
# ارفض Edit/Write على الأسرار وملفات الأقفال والـ git الداخلية.
input=$(cat)
path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty')
path=${path//\\//}
case "$path" in
*.env|*.env.*|*/.env|*/.env.*)
echo "محتجز: $path هو ملف env. حرّر قالب نموذج بدلا من ذلك." >&2
exit 2
;;
*/.git/*|*.git/*)
echo "محتجز: $path داخل .git." >&2
exit 2
;;
*package-lock.json|*pnpm-lock.yaml|*yarn.lock|*poetry.lock|*Cargo.lock)
echo "محتجز: $path هو ملف قفل. حدّثه من خلال مدير الحزمة." >&2
exit 2
;;
esac
exit 0
{
"hooks": {
"PreToolUse": [
{
"matcher": "^Edit$|^Write$",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh"
}
]
}
]
}
}
Claude يستقبل نص stderr ويمكنه اختيار مسار آخر. هذا لا يوقف أمر Bash مثل rm .env أو إعادة توجيه. أضف مجموعة PreToolUse ثانية مع محقق ^Bash$ إذا أوامر shell تكتب إلى تلك المسارات مهمة. لرفض صعب الذي لا يزال يخرج 0، اطبع JSON permissionDecision من قسم كود الخروج وأخرج 0.
3. سجّل أوامر shell
.claude/hooks/log-bash.sh
#!/bin/bash
# أضيف كل أمر Bash إلى سجل محلي. لا تحجب أبدا.
input=$(cat)
log="${CLAUDE_PROJECT_DIR:-.}/.claude/hooks/bash-log.jsonl"
printf '%s\n' "$input" | jq -c '{t: (now | todate), cmd: .tool_input.command, cwd: .cwd}' >> "$log"
exit 0
أضف .claude/hooks/bash-log.jsonl إلى .gitignore. السجل سيحتوي على كل ما وضعه Claude في سلسلة الأمر، بما في ذلك الأسرار إذا كان أمر يُدرج فيها.
{
"hooks": {
"PreToolUse": [
{
"matcher": "^Bash$",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/log-bash.sh"
}
]
}
]
}
}
if يمكنه تضييق هذا أيضا على أحداث الأداة، باستخدام صيغة قاعدة الإذن مثل Bash(git *). بدون if, كل استدعاء Bash يضيف سطرا. if التي لا تطابق تتخطى العملية كليا.
4. أخطّر عندما ينتهي الدور
Stop لا محقق. اِبقِ الأمر قصيرا. المهلة الزمنية الافتراضية طويلة، وخطّاف معلّق يمسك نهاية الدور.
macOS، بعد يُسمح محرر Script بالإخطار:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "osascript -e 'display notification \"انتهى الدور\" with title \"Claude Code\"'",
"timeout": 5
}
]
}
]
}
}
Linux، عندما خيط إخطار يعمل:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "notify-send 'Claude Code' 'انتهى الدور'",
"timeout": 5
}
]
}
]
}
}
Windows PowerShell يفتح حوارا، الذي يمكنه أن ينزل خلف المحطة:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "powershell.exe -NoProfile -Command \"[System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms') | Out-Null; [System.Windows.Forms.MessageBox]::Show('انتهى الدور','Claude Code') | Out-Null\"",
"timeout": 15
}
]
}
]
}
}
notify-send لا يفعل شيء مفيد على SSH أو في حاوية. اختبر الأمر في محطة عادية قبل وضعه في الإعدادات. خطّاف Notification مع محقق permission_prompt هي الحالة المنفصلة “Claude ينتظر”، الذي هو ما تريده أثناء وقفة طويلة، وليس في النهاية.
SubagentStop هو حدث المطابقة لـ وكيل فرعي ينتهي. محقق هو الاسم name للوكيل، على سبيل المثال code-reviewer. خطّاف Stop في الواجهة الأمامية للوكيل نفسه يُسلّم كـ SubagentStop.
5. شغّل الاختبارات بعد تحرير
تشغيل مجموعة كاملة بعد كل keystroke مزعج. هذا السكريبت يشغّل فقط لملفات اختبار Python و JavaScript، و فقط عندما تكون نقطة دخول معروفة موجودة.
.claude/hooks/test-after-edit.sh
#!/bin/bash
# أعد تشغيل ملف اختبار ضيق بعد تحرير Claude له.
input=$(cat)
path=$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty')
case "$path" in
*test_*.py|*tests/*.py)
pytest "$path" >&2 || exit 2
;;
*.test.js|*.test.ts|*.spec.js|*.spec.ts)
# حجج إضافية يتم إلحاقها بنص npm test. وجّه هذا في الملف الثنائي الرائد إذا كان ذلك السكريبت تتجاهل مسار الملف.
npm test -- "$path" >&2 || exit 2
;;
esac
exit 0
Pytest يكتب إلى stderr هنا بحيث فشل هو السبب الحاجب Claude يقرأه. الخروج 2 على PostToolUse لا يُرجع الملف. يخبر Claude التحرير وصل والأمر اختبار فشل.
{
"hooks": {
"PostToolUse": [
{
"matcher": "^Edit$|^Write$",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/test-after-edit.sh",
"timeout": 120
}
]
}
]
}
}
استبدل npm test بالرائد الذي يوثّقه مستودعك بالفعل. أمر مائل يسمى /test هو الملاءمة الأفضل عندما إنسان يجب أن يقرر تشغيل المجموعة. الخطّاف لـ التحريرات التي لا تريد دمج بدون فحص أحمر/أخضر.
ملف إعدادات واحد
دمّج المجموعات. مجموعتا PostToolUse عادية. المعالجات في مجموعة تعمل عندما محقق يطابق.
{
"hooks": {
"PreToolUse": [
{
"matcher": "^Edit$|^Write$",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/protect-files.sh" }
]
},
{
"matcher": "^Bash$",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/log-bash.sh" }
]
}
],
"PostToolUse": [
{
"matcher": "^Edit$|^Write$",
"hooks": [
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-file.sh", "timeout": 30 },
{ "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/test-after-edit.sh", "timeout": 120 }
]
}
],
"Stop": [
{
"hooks": [
{ "type": "command", "command": "notify-send 'Claude Code' 'انتهى الدور'", "timeout": 5 }
]
}
]
}
}
بدّل أمر Stop لخط macOS أو Windows إذا كنت على نظام التشغيل لا Linux. اطلب Claude تحرير ملف تحت src/ وأكّد السجل نما والمنسّق عمل. اطلب تحرير .env وأكّد استدعاء الأداة مرفوض.
الخطّافات هي أتمتة محلية. هي ليست بديل CI، وهي ليست خادم MCP. خادم MCP يضيف أدوات Claude يمكنه استدعاؤها. خطّاف يلف الأدوات Claude لديه بالفعل.
الأسئلة الشائعة
أين تذهب خطّافات Claude Code؟
أضف كائن hooks إلى .claude/settings.json لمشاركة الخطّافات مع المستودع، أو إلى ~/.claude/settings.json لتشغيلها في كل مشروع. .claude/settings.local.json يحمل جوانب شخصية من المشروع ويتم تجاهله عندما يكتب Claude Code إعدادا هناك. شغّل /hooks في جلسة لترى القائمة المدمجة. عيّن disableAllHooks إلى true لإيقاف الخطّافات في مستوى الإعدادات ذلك.
ما الفرق بين كود الخروج 0 و كود الخروج 2؟
الخروج 0 يعني النجاح. إذا كان stdout كائن JSON واحد، Claude Code يطبق تلك الحقول. الخروج 2 يحجب الأحداث التي يمكنها حجب، و stderr هو السبب الذي يراه Claude. أي كود خروج آخر هو خطأ غير حاجب: استدعاء الأداة لا يزال يتقدم، ما لم يُنسب إليه هذا الخطّاف بحيث الفشل يحجب. على PreToolUse, JSON permissionDecision صحيح يمكنه رفض الاستدعاء حتى عندما تخرج العملية 0.
أي خطّاف يعمل قبل تحرير Claude ملف؟
PreToolUse, مع محقق للأدوات Edit و Write. السكريبت يقرأ JSON على stdin. المسار المستهدف هو tool_input.file_path. أخرج 2 لإلغاء التحرير واطبع السبب على stderr. PostToolUse يعمل فقط بعد أن تكون الأداة قد نجحت بالفعل، لذا هو المكان الصحيح للتنسيق، وليس لمنع الكتابة.
هل يمكن خطّاف تشغيل Prettier أو Black؟
نعم. خطّاف أمر PostToolUse يمكنه قراءة tool_input.file_path وتشغيل Prettier على ملفات JavaScript و TypeScript أو Black على ملفات Python. إخراج الخطّاف لا يُعرض لـ Claude على الخروج 0. إذا فشل المنسّق وأخرجت 2، Claude يرى stderr حتى على الرغم من أن التحرير وصل بالفعل.
هل تقبل Stop و UserPromptSubmit محقق؟
لا. Stop و UserPromptSubmit يطلقان في كل تكرار. محققات تنطبق على أحداث الأداة مثل PreToolUse و PostToolUse، حيث المنمط يُطابق ضد اسم الأداة، وإلى Notification, حيث يُطابق ضد نوع الإخطار. SubagentStop يطابق نوع الوكيل.
كيف تم التحقق من هذا الدليل
كُتب يدويًا من الوثائق الرسمية، وأُعيد فحص كل أمر، ثم رُوجع مرة ثانية قبل النشر. آخر مراجعة في .
المصادر الرسمية التي قُرئت لهذا المقال

