מדריך עזר לאירועי hook של Claude Code, לסכמת ההגדרות, לפורמטים של קלט ופלט JSON, לקודי יציאה, ל-hooks אסינכרוניים, ל-hooks של HTTP, ל-hooks של prompt, ול-hooks של כלי MCP.
Hooks הם פקודות מעטפת, נקודות קצה של HTTP, קריאות לכלי MCP, prompts של LLM, או סוכני משנה שהמשתמש מגדיר, והם רצים אוטומטית בנקודות מסוימות במחזור החיים של Claude Code. Claude Code מפעיל את אותם אירועי hook בכל מקום שבו הוא רץ: סשנים בטרמינל, הרחבות IDE, אפליקציית Desktop, וסשנים בענן. השתמש במדריך העזר הזה כדי לחפש סכמות של אירועים, אפשרויות הגדרה, פורמטים של קלט ופלט JSON, ותכונות מתקדמות כמו hooks אסינכרוניים, hooks של HTTP, ו-hooks של כלי MCP.
תוסף יכול גם לרשום hooks כפונקציות JavaScript ש-Claude Code קורא להן בתהליך שלו, והן יכולות גם לצייר בממשק וגם לפעול על אירועים. תוסף שעושה זאת הוא mod, וה-hooks האלה כפונקציות מכוסים בתגובה לאירועים ולא כאן. ה-hooks בדף הזה ממשיכים לעבוד לצד mods.
Claude Code מריץ hooks בנקודות מסוימות במהלך סשן. כשאירוע מופעל ו-matcher תואם, Claude Code מעביר למטפל ה-hook הקשר JSON על האירוע. ב-hooks של פקודה, הקלט מגיע ב-stdin. ב-hooks של HTTP, הוא מגיע כגוף בקשת POST. המטפל יכול לבדוק את הקלט, לפעול, ואם רוצים גם להחזיר החלטה.
האירועים מתחלקים לשלושה קצבים:
לכל סשן: SessionStart ו-SessionEnd
לכל תור: UserPromptSubmit, Stop, ו-StopFailure
בכל קריאת כלי בתוך הלולאה הסוכנית: PreToolUse ו-PostToolUse, למעט קריאות EndConversation, שמדלגות על שניהם
הטבלה הבאה מסכמת מתי כל אירוע מופעל. הסעיף אירועי hook מתעד את סכמת הקלט המלאה ואת אפשרויות בקרת ההחלטה של כל אחד.
אירוע
מתי הוא מופעל
SessionStart
כשסשן מתחיל או ממשיך
Setup
כשמתחילים את Claude Code עם --init-only, או עם --init או --maintenance במצב -p. להכנה חד פעמית ב-CI או בסקריפטים
כשפקודה שהמשתמש הקליד מתרחבת ל-prompt, לפני שהיא מגיעה ל-Claude. יכול לחסום את ההרחבה
PreToolUse
לפני שקריאת כלי רצה. יכול לחסום אותה
PermissionRequest
כשקריאת כלי צריכה החלטת הרשאה
PermissionDenied
כשמצב אוטומטי דוחה קריאת כלי, כולל דחיות בלי פסק דין של מסווג. השתמש ב-JSON hookSpecificOutput.retry: true כדי לומר למודל שהוא רשאי לנסות שוב את קריאת הכלי שנדחתה. Claude Code מתעלם מ-retry כשהמסווג לא הפיק פסק דין
PostToolUse
אחרי שקריאת כלי מצליחה
PostToolUseFailure
אחרי שקריאת כלי נכשלת
PostToolBatch
אחרי שכל אצווה של קריאות כלי מקבילות מסתיימת, לפני קריאת המודל הבאה
הסקריפט קורא את קלט ה-JSON מ-stdin, מחלץ את הפקודה, ומחזיר permissionDecision של "deny" אם היא מכילה rm -rf. שמור אותו ב-.claude/hooks/block-rm.sh בפרויקט, והפוך אותו לבר הרצה עם chmod +x .claude/hooks/block-rm.sh כדי ש-Claude Code יוכל להריץ אותו:
#!/bin/bash
# .claude/hooks/block-rm.sh
COMMAND=$(jq -r '.tool_input.command')
if echo "$COMMAND" | grep -q 'rm -rf'; then
jq -n '{
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: "Destructive command blocked by hook"
}
}'
else
exit 0 # no decision; normal permission flow applies
fi
הסקריפט הזה, כמו שאר דוגמאות Bash בדף הזה שמפענחות קלט JSON, משתמש ב-jq, אז התקן את jq וודא שהוא ב-PATH לפני שמנסים אותן.
ה-matcher Bash|PowerShell מכסה את כלי PowerShell וגם את Bash. כלל if יחיד תואם רק לקריאות של כלי אחד, ולכן לכל כלי יש מטפל משלו: הראשון מצמצם לפקודות משנה של Bash שתואמות ל-rm *, והשני לפקודות PowerShell שתואמות ל-Remove-Item *. שניהם מריצים את אותו סקריפט דרך powershell.exe:
הדגל -NoProfile מדלג על טעינת פרופיל PowerShell כדי שה-hook יתחיל מהר, ו--ExecutionPolicy Bypass מאפשר ל-PowerShell להריץ את קובץ הסקריפט המקומי.
הסקריפט קורא את קלט ה-JSON מ-stdin, מחלץ את הפקודה, ומחזיר permissionDecision של "deny" אם היא מכילה rm -rf או Remove-Item ואחריו -Recurse. שמור אותו ב-.claude/hooks/block-rm.ps1 בפרויקט:
ה-matcher "Bash" תואם לשם הכלי, ולכן קבוצת ה-hook הזו מופעלת. אם משמיטים את ה-matcher או משתמשים ב-"*", הקבוצה מופעלת בכל מופע של האירוע.
3. בדיקות תנאי ה-if
תנאי ה-if"Bash(rm *)" תואם כי rm -rf /tmp/build היא פקודת משנה שתואמת ל-rm *, ולכן המטפל הזה נוצר. אם הפקודה הייתה npm test, בדיקת ה-if הייתה נכשלת ו-block-rm.sh לא היה רץ אף פעם, וכך נמנעת התקורה של יצירת תהליך. השדה if אופציונלי. בלעדיו, כל מטפל בקבוצה שתואמה רץ.
4. מטפל ה-hook רץ
הסקריפט בודק את הפקודה המלאה ומוצא rm -rf, ולכן הוא מדפיס החלטה ל-stdout:
אם הפקודה הייתה גרסת rm בטוחה יותר כמו rm file.txt, הסקריפט היה מגיע ל-exit 0 במקום זאת. קוד יציאה 0 בלי פלט אומר של-hook אין החלטה לדווח, ולכן קריאת הכלי ממשיכה דרך זרימת ההרשאות הרגילה. ה-hook יכול לדחות את הקריאה, אבל שתיקה לא מאשרת אותה.
5. Claude Code פועל לפי התוצאה
Claude Code קורא את החלטת ה-JSON, חוסם את קריאת הכלי, ומראה ל-Claude את הסיבה.
הסעיף הגדרות למטה מתעד את הסכמה המלאה, וכל סעיף אירוע hook מתעד איזה קלט הפקודה מקבלת ואיזה פלט היא יכולה להחזיר.
הדף הזה משתמש במונחים מסוימים לכל רמה: אירוע hook לנקודה במחזור החיים, קבוצת matcher למסנן, ומטפל hook לפקודת המעטפת, לנקודת הקצה של HTTP, לכלי MCP, ל-prompt, או לסוכן שרץ. "Hook" לבדו מתייחס לתכונה הכללית.
סשנים בענן לא קוראים את ~/.claude/settings.json המקומי שלך. בסביבה באירוח עצמי, Claude Code גם מריץ את ההוקים שהמפעיל זרע מתוך ~/.claude/ של מארח ה-runner, והוא מריץ את ההוקים בקובץ ההגדרות המנוהלות של תמונת ה-runner כשהקובץ הזה נמצא בין המקורות המנוהלים ש-Claude Code מחיל, מה שבברירת המחדל אומר רק כשאף הגדרות מנוהלות שרת ואף מדיניות Claude Code שנמסרה ב-MDM לא מספקות את שכבת הניהול. ראו מה עובר מההגדרה שלך לגבי אילו קבצי הגדרות ותוספים, ולכן אילו הוקים, מגיעים לסשן ענן.
הוקים מקבצי הגדרות, מהגדרות מדיניות מנוהלות ומתוספים רצים גם בתוך subagents. כש-subagent קורא לכלי, אירועי כלים כמו PreToolUse ו-PostToolUse מפעילים את אותם הוקים מוגדרים כמו בשיחה הראשית, והקלט נושא את agent_id ו-agent_typeשדות הקלט המשותפים שמזהים את ה-subagent.
Claude Code גם משבית תוספים עם מקור command, כולל תוספים שהופעלו בכפייה בהגדרות המנוהלות enabledPlugins, אלא אם disableCommandPluginSources מוגדר במפורש ל-false. מקורות command דורשים Claude Code מגרסה v2.1.229 ואילך
Claude Code גם חוסם פקודות headersHelper של marketplace אלא אם disableCommandPluginSources מוגדר במפורש ל-false, למעט marketplace שההגדרות המנוהלות עצמן מצהירות עליו
רשומות הוקים מתמזגות בין רמות ההגדרות במקום להחליף זו את זו: הגדרות משתמש, פרויקט ומקומיות מוסיפות את ההוקים שלהן בלי להסיר הוקים מנוהלים, וההגדרה disableAllHooks לא יכולה להשבית הוקים מנוהלים מחוץ להגדרות מנוהלות.
שדה matcher מסנן מתי הוקים מופעלים. אופן הערכת matcher תלוי בתווים שהוא מכיל:
ערך matcher
מוערך כ
דוגמה
"*", "", או מושמט
התאמה להכל
מופעל בכל מופע של האירוע
רק אותיות, ספרות, _, -, רווחים, , ו-|
מחרוזת מדויקת, או רשימת מחרוזות מדויקות מופרדות ב-| או , עם רווח אופציונלי מסביב
Bash תואם רק לכלי Bash; Edit|Write ו-Edit, Write כל אחד תואם לאחד משני הכלים במדויק; code-reviewer תואם רק לסוג הסוכן הזה
מכיל כל תו אחר
ביטוי רגולרי של JavaScript, בלי עיגון
^Notebook תואם לכל כלי ששמו מתחיל ב-Notebook; mcp__memory__.* תואם לכל כלי משרת memory
matcher במסלול הביטוי הרגולרי נבדק עם RegExp.prototype.test של JavaScript, שמצליח על התאמה בכל מקום בערך. Edit.* תואם גם ל-Edit וגם ל-NotebookEdit. עטפו את התבנית ב-^ וב-$, כמו ב-^Edit$, כשצריך התאמה למחרוזת שלמה.
FileChanged ו-StopFailure משתמשים בקבוצת התאמה מדויקת צרה יותר של אותיות, ספרות, _ ו-| בלבד. מקף, רווח או פסיק ב-matcher של שני האירועים האלה משאירים אותו במסלול הביטוי הרגולרי, ורק | מפריד חלופות. כל אירוע אחר עם תמיכה ב-matcher בטבלה שאחרי זה מקבל | או ,.
אירוע FileChanged לא פועל לפי הכללים האלה כשהוא בונה את רשימת המעקב שלו. ראו FileChanged.
התאמת StopFailure ל-cloud_credential_error דורשת Claude Code מגרסה v2.1.267 ואילך, הגרסה הראשונה שמדווחת על כשלי טעינת credentials תחת הערך הזה במקום server_error או unknown.
ברוב האירועים, Claude Code מעריך את ה-matcher מול שדה מקלט ה-JSON שהוא שולח להוק שלך ב-stdin. באירועי כלים, השדה הזה הוא tool_name. ב-PreModelSwitch וב-PostModelSwitch, Claude Code מעריך את ה-matcher מול השם הקנוני שהוא גוזר מ-to_model, כפי שמתואר תחת PreModelSwitch. כל מקטע אירוע הוק מפרט את קבוצת ערכי ה-matcher המלאה ואת סכמת הקלט של האירוע.
הדוגמה הזו מריצה סקריפט linting רק כש-Claude כותב או עורך קובץ:
אם מוסיפים שדה matcher לאירוע בלי תמיכה ב-matcher, הוא מושמט בשקט.
באירועי כלים, אפשר לסנן בצורה צרה יותר על ידי הגדרת שדה if על מטפלי הוק בודדים. if משתמש בתחביר כללי הרשאה כדי להתאים לשם הכלי ולפרמטרים יחד, כך ש-"Bash(git *)" רץ כשתת-פקודה כלשהי של קלט Bash תואמת ל-git * ו-"Edit(*.ts)" רץ רק לקובצי TypeScript.
כלי שרת MCP מופיעים ככלים רגילים באירועי כלים (PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, PermissionDenied), כך שאפשר להתאים אותם באותו אופן שבו מתאימים לכל שם כלי אחר.
כלי MCP פועלים לפי תבנית השמות mcp__<server>__<tool>, לדוגמה:
mcp__memory__create_entities: כלי יצירת הישויות של שרת Memory
mcp__filesystem__read_file: כלי קריאת הקובץ של שרת Filesystem
mcp__github__search_repositories: כלי החיפוש של שרת GitHub
כדי להתאים לכל כלי משרת, הוסיפו .* לקידומת השרת. ה-.* נדרש: matcher כמו mcp__memory או mcp__brave-search מכיל רק תווי התאמה מדויקת, ולכן הוא מושווה כמחרוזת מדויקת ולא תואם לאף כלי.
mcp__memory__.* תואם לכל הכלים משרת memory
mcp__brave-search__.* תואם לכל הכלים משרת ששמו מכיל מקף
mcp__.*__write.* תואם לכל כלי ששמו מתחיל ב-write מכל שרת
כלים משרת MCP ארוז בתוסף משתמשים במקטע שרת בהיקף שכולל את שם התוסף: mcp__plugin_<plugin-name>_<server-name>__<tool>. matcher שנכתב מול מפתח השרת החשוף אף פעם לא מופעל עבור הכלים האלה. בתוסף בשם my-plugin שאורז שרת תחת המפתח db, כלי query מופיע כ-mcp__plugin_my-plugin_db__query, כך שה-matcher לכל כלי מהשרת הזה הוא mcp__plugin_my-plugin_db__.*. השתמשו באותו שם כלי בהיקף בשדה if של מטפל. ראו שרתי MCP שמסופקים על ידי תוסף לאופן שבו השם בהיקף נבנה.
הדוגמה הזו רושמת את כל פעולות שרת memory ומאמתת פעולות כתיבה מכל שרת MCP:
כל אובייקט במערך הפנימי hooks הוא מטפל hook: פקודת המעטפת, נקודת הקצה HTTP, כלי ה-MCP, הנחיית ה-LLM, או הסוכן שרץ כשה-matcher תואם. יש חמישה סוגים:
hooks מסוג פקודה (type: "command"): מריצים פקודת מעטפת. הסקריפט מקבל את קלט ה-JSON של האירוע ב-stdin ומחזיר תוצאות דרך קודי יציאה ו-stdout.
hooks מסוג HTTP (type: "http"): שולחים את קלט ה-JSON של האירוע כבקשת HTTP POST לכתובת URL. נקודת הקצה מחזירה תוצאות דרך גוף התגובה באותו פורמט פלט JSON כמו hooks מסוג פקודה.
hooks מסוג כלי MCP (type: "mcp_tool"): קוראים לכלי בשרת MCP מוגדר. פלט הטקסט של הכלי מטופל כמו stdout של hook מסוג פקודה.
hooks מסוג הנחיה (type: "prompt"): שולחים הנחיה למודל Claude להערכה של תור אחד. המודל מחזיר את ההחלטה שלו כ-JSON. ראו hooks מבוססי הנחיה.
hooks מסוג סוכן (type: "agent"): מפעילים תת-סוכן שיכול להשתמש בכלים כמו Read, Grep ו-Glob כדי לאמת תנאים לפני החזרת החלטה. hooks מסוג סוכן הם ניסיוניים ועשויים להשתנות. ראו hooks מבוססי סוכן.
כשאירוע מופעל, ה-hooks התואמים שלו רצים במקביל. אם יותר מ-12 מהם הם hooks מסוג הנחיה או סוכן, 12 מהם רצים בבת אחת והשאר מתחילים כשהרצים מסתיימים. ה-timeout של כל hook שממתין מתחיל להיספר כשה-hook הזה מתחיל.
אם מגדירים את אותו מטפל ביותר מקובץ הגדרות אחד, הוא רץ פעם אחת. עותק של אותו מטפל בתוסף או ב-skill נשאר נפרד.
המטפלים רצים בתיקייה הנוכחית עם הסביבה של Claude Code. אם התיקייה הנוכחית כבר לא קיימת, למשל worktree או תיקייה זמנית שמעטפת אחרת מחקה באמצע הסשן, Claude Code מריץ hooks מסוג פקודה מהראשונה מבין אלה שעדיין קיימת: התיקייה שבה הסשן התחיל, שורש הפרויקט, תיקיית הבית, או תיקיית temp של המערכת. Claude Code רושם אזהרה שמציינת את תיקיית ה-fallback ביומן הניפוי. לסשן worktree שמתחילים מאפליקציית שולחן העבודה, ראו מה worktrees חולקים עם ה-checkout הראשי.
משתנה הסביבה $CLAUDE_CODE_REMOTE הוא "true" בסביבות web מרוחקות ואינו מוגדר ב-CLI המקומי. Claude Code מגרסה v2.1.199 ואילך מגדיר את $CLAUDE_CODE_BRIDGE_SESSION_ID למזהה הסשן של Remote Control בזמן שלסשן המקומי יש חיבור Remote Control פעיל.
"command", "http", "mcp_tool", "prompt", או "agent"
if
לא
תחביר כללי הרשאה לסינון מתי ה-hook הזה רץ, למשל "Bash(git *)" או "Edit(*.ts)". פקודת ה-hook רצה רק אם קריאת הכלי תואמת לתבנית. ראו את טבלת ההתאמה של Bash לאופן שבו תבניות Bash מוערכות מול פקודות משנה, $(), וגרשיים הפוכים. מוערך רק באירועי כלי: PreToolUse, PostToolUse, PostToolUseFailure, PermissionRequest, ו-PermissionDenied. באירועים אחרים, hook עם if מוגדר אף פעם לא רץ
timeout
לא
שניות לפני ביטול. Claude Code לא אוכף אותו על hook מסוג פקודה שמריצים עם async: true. ברירות מחדל: 600 עבור command, http, ו-mcp_tool; 30 עבור prompt; 60 עבור agent. Claude Code מוריד את ברירת המחדל של command, http, ו-mcp_tool ל-30 ב-UserPromptSubmit, PreModelSwitch, ו-PostModelSwitch, ול-10 ב-MessageDisplay. hooks של SessionEnd חולקים תקציב של 1.5 שניות; אם ההגדרות קובעות timeout ארוך יותר לכל hook, Claude Code מעלה את התקציב כדי להתאים, עד 60 שניות
statusMessage
לא
הודעת ספינר מותאמת שמוצגת בזמן שה-hook רץ
once
לא
אם true, Claude Code מסיר את ה-hook אחרי הריצה המוצלחת הראשונה שלו. ריצה שנכשלת, חוסמת עם קוד יציאה 2, או מסתיימת ב-timeout משאירה את ה-hook במקום, כך שהוא רץ שוב באירוע התואם הבא. נלקח בחשבון רק עבור hooks שמוצהרים ב-frontmatter של skill; מתעלמים ממנו בקובצי הגדרות וב-frontmatter של סוכן
שדה ה-if מכיל בדיוק כלל הרשאה אחד. אין תחביר &&, ||, או רשימה לשילוב כללים; כדי להחיל כמה תנאים, הגדירו מטפל hook נפרד לכל אחד.
בתנאי if לכלי קבצים, תבנית תיקייה של מקטע יחיד כמו "Edit(src/**)" תואמת רק לתיקיית src בתיקיית העבודה ולקבצים שתחתיה. כדי להתאים לתיקייה בשם src בכל עומק, כתבו "Edit(**/src/**)".
עבור תבניות Bash בשדה ה-if, האם פקודת ה-hook רצה תלוי בצורת התבנית ובפקודת ה-Bash ש-Claude מפעיל. הצבות VAR=value מובילות מוסרות לפני ההתאמה.
תבנית if
פקודת Bash
ה-hook רץ?
למה
Bash(git *)
FOO=bar git push
כן
הצבות מובילות מוסרות; git push תואם
Bash(git *)
npm test && git push
כן
כל פקודת משנה נבדקת; git push תואם
Bash(rm *)
echo $(rm -rf /)
כן
פקודות בתוך $() וגרשיים הפוכים נבדקות; rm -rf / תואם
Bash(rm *)
echo $(date)
לא
אין פקודת משנה שתואמת ל-rm *
Bash(git push *)
echo $(date)
כן
תבניות שמציינות יותר משם הפקודה מריצות את ה-hook בכל מקרה על $(), גרשיים הפוכים, או $VAR
כש-Claude Code לא יכול לקבוע אילו פקודות קלט ה-Bash מריץ, הוא מריץ את ה-hook בלי קשר לתבנית. מכיוון שמסנן ה-if פועל כמיטב היכולת, השתמשו במערכת ההרשאות במקום ב-hook כדי לאכוף allow או deny מוחלטים.
אם true, רץ ברקע ומעיר את Claude בקוד יציאה 2. ה-stderr של ה-hook, או stdout אם stderr ריק, מוצג ל-Claude כתזכורת מערכת כדי שיוכל להגיב לכשל רקע ממושך
shell
לא
המעטפת לשימוש עבור ה-hook הזה. מקבל "bash" או "powershell". ברירת המחדל היא "bash", או "powershell" ב-Windows כש-Git Bash לא מותקן. הגדרת "powershell" מריצה את הפקודה דרך PowerShell ב-Windows. לא דורש CLAUDE_CODE_USE_POWERSHELL_TOOL כי hooks מפעילים את PowerShell ישירות. מתעלמים ממנו כש-args מוגדר
onFailure
לא
האם הפעולה שהפעילה את ה-hook ממשיכה כשה-hook נכשל: "continue" או "block". ראו חסימת הפעולה כש-hook נכשל עבור "block" ועבור השארת השדה לא מוגדר. דורש Claude Code v2.1.295 או חדש יותר
hook מסוג פקודה רץ כצורת exec כש-args מוגדר, וכצורת מעטפת כש-args מושמט. הגדירו args בכל פעם שה-hook מפנה למציין מיקום של נתיב, כי כל רכיב מועבר כארגומנט אחד בלי ציטוט. השמיטו את args כשצריך תכונות מעטפת כמו צינורות או &&, או כשאף אחד מהחששות לא חל.
צורת exec רצה כש-args קיים. Claude Code מזהה את command כקובץ הרצה ב-PATH ומפעיל אותו ישירות עם args כוקטור הארגומנטים. אין מעטפת, כך שכל רכיב ב-args הוא ארגומנט אחד בדיוק כפי שנכתב, ומצייני מיקום של נתיב כמו ${CLAUDE_PLUGIN_ROOT} מוחלפים ב-command ובכל רכיב של args כמחרוזות רגילות. תווים מיוחדים כמו אפוסטרופים, $, וגרשיים הפוכים עוברים כלשונם כי אין מעטפת שמפרשת אותם. לא מתבצע פירוק לאסימונים של מעטפת באף פלטפורמה.
צורת מעטפת רצה כש-args חסר. מחרוזת ה-command מועברת למעטפת: sh -c ב-macOS וב-Linux, Git Bash ב-Windows, או PowerShell כש-Git Bash לא מותקן. הגדירו את שדה ה-shell כדי לבחור במפורש. המעטפת מפרקת את המחרוזת לאסימונים, מרחיבה משתנים, ומפרשת צינורות, &&, הפניות, ו-globs.
[!NOTE]
ב-Windows, צורת exec דורשת ש-command יזוהה כקובץ הרצה אמיתי כמו .exe. קובצי ה-shim מסוג .cmd ו-.bat ש-npm, npx, eslint וכלים אחרים מתקינים ב-node_modules/.bin אינם קובצי הרצה ואי אפשר להפעיל אותם בלי מעטפת. כדי להריץ אותם בצורת exec, הפעילו את הסקריפט שמתחת עם node ישירות, למשל "command": "node", "args": ["${CLAUDE_PLUGIN_ROOT}/node_modules/eslint/bin/eslint.js"]. התבנית של node יחד עם נתיב הסקריפט עובדת בכל פלטפורמה כי node.exe הוא קובץ בינארי אמיתי. כדי להריץ shim של .cmd או .bat לפי שם, השתמשו בצורת מעטפת.
הדוגמה הזו מריצה סקריפט Node שמצורף לתוסף. צורת exec מעבירה את נתיב הסקריפט המזוהה כארגומנט אחד בלי ציטוט:
שתי הצורות תומכות באותם מצייני מיקום של נתיב, ושתיהן מייצאות אותם כמשתני הסביבה CLAUDE_PROJECT_DIR, CLAUDE_PLUGIN_ROOT, ו-CLAUDE_PLUGIN_DATA בתהליך שמופעל, כך שסקריפט יכול לקרוא את process.env.CLAUDE_PLUGIN_ROOT בלי קשר לאופן ההפעלה.
hooks של תוסף מחליפים בנוסף ערכי ${user_config.*}, בצורת exec בלבד: הערך מוחלף ב-command ובכל רכיב של args כמחרוזת רגילה, כך שאף מעטפת לא מנתחת אותו מחדש.
hook של תוסף בצורת מעטפת שה-command שלו מפנה ל-${user_config.*} נכשל עם שגיאה במקום לרוץ. כדי להשתמש בערך אפשרות מ-hook בצורת מעטפת, קראו את משתנה הסביבה $CLAUDE_PLUGIN_OPTION_<KEY>, למשל $CLAUDE_PLUGIN_OPTION_WEBHOOK_URL עבור אפשרות webhook_url, או הגדירו args כדי להעביר את ה-hook לצורת exec. לפני v2.1.207, גם פקודות hook של תוסף בצורת מעטפת החליפו את ${user_config.*}.
[!NOTE]
בצורת exec, command הוא שם קובץ ההרצה או הנתיב בלבד. אם command הוא שם חשוף בלי מפריד נתיב ומכיל רווח לבן לצד args, Claude Code רושם אזהרה כי ההפעלה תיכשל: אין קובץ הרצה בשם node script.js. העבירו את האסימונים הנוספים אל args. נתיבים מוחלטים עם רווחים, כמו C:\Program Files\nodejs\node.exe, הם קובץ הרצה יחיד תקין ולא מפעילים את האזהרה.
בנוסף לשדות המשותפים, hooks מסוג HTTP מקבלים את השדות האלה:
שדה
חובה
תיאור
url
כן
כתובת URL לשליחת בקשת ה-POST
headers
לא
כותרות HTTP נוספות כזוגות מפתח-ערך. הערכים תומכים באינטרפולציה של משתני סביבה בתחביר $VAR_NAME או ${VAR_NAME}. רק משתנים שרשומים ב-allowedEnvVars מזוהים
allowedEnvVars
לא
רשימת שמות משתני סביבה שאפשר לבצע להם אינטרפולציה בערכי כותרות. הפניות למשתנים שלא ברשימה מוחלפות במחרוזות ריקות. נדרש כדי שאינטרפולציה של משתנה סביבה כלשהו תעבוד
onFailure
לא
מה קורה לפעולה כשה-hook נכשל: "continue", ברירת המחדל, או "block". ראו חסימת הפעולה כש-hook נכשל. דורש Claude Code v2.1.295 או חדש יותר
Claude Code שולח את קלט ה-JSON של ה-hook כגוף בקשת ה-POST עם Content-Type: application/json. גוף התגובה משתמש באותו פורמט פלט JSON כמו hooks מסוג פקודה.
Claude Code קורא את תוכן הטקסט של הכלי באותו אופן שהוא קורא stdout של hook מסוג פקודה, לפי כלל הניתוח תחת קוד יציאה 0. אם הכלי מחזיר isError: true, ה-hook מייצר שגיאה לא חוסמת וההרצה ממשיכה.
באירועים שבהם hook יכול לחסום או לשנות את התוצאה, כמו PreToolUse או Stop, Claude Code ממתין לשרת שמתחבר לפני שהוא קורא לכלי, לכל היותר MCP_TIMEOUT ובתוך ה-timeout של ה-hook עצמו. באירועי תצפית, כמו Notification או SessionEnd, הוא לא ממתין.
שרת שמציג את סטטוס cached מתחבר כשה-hook קורא לכלי שלו. אם השרת לא מחובר בנקודה הזו, ה-hook מייצר שגיאה לא חוסמת וההרצה ממשיכה. ה-hook אף פעם לא מתחיל תהליך OAuth, לכן אמתו את השרת מ-/mcp קודם.
SessionStart בהפעלה, כולל עם --continue או --resume, וכל אירוע Setup מופעלים לפני ששרתי ה-MCP של הסשן זמינים ל-hooks. Claude Code מדלג על ה-hooks מסוג mcp_tool שלהם בלי לקרוא לכלי, ויומן הניפוי רושם mcp_tool hooks are not available for the 'SessionStart' hook event (no MCP client context), או אותה הודעה עם השם Setup. כש-SessionStart מופעל שוב מאוחר יותר בסשן, אחרי /clear או compaction, ה-hooks מסוג mcp_tool שלו רצים. לכל דבר שהסשן צריך בהפעלה, השתמשו ב-hook מסוג type: "command" על SessionStart במקום.
השתמשו במצייני המקום האלה כדי להפנות לסקריפטי hook יחסית לשורש הפרויקט או הפלאגין, בלי קשר לתיקיית העבודה בזמן שה-hook רץ:
${CLAUDE_PROJECT_DIR}: שורש הפרויקט שבו ההפעלה התחילה. Claude Code גם מגדיר את המשתנה הזה בסביבה של שרתי MCP ב-stdio ושל שרתי LSP של פלאגינים.
${CLAUDE_PLUGIN_ROOT}: תיקיית ההתקנה של הפלאגין, לסקריפטים שמגיעים עם פלאגין. ראו משתני סביבה של פלאגינים כדי להבין איך הנתיב מתנהג אחרי עדכונים.
${CLAUDE_PLUGIN_DATA}: תיקיית הנתונים המתמשכת של הפלאגין, לתלויות ולמצב שצריכים לשרוד עדכוני פלאגין.
[!NOTE]
Worktrees שונים. אם Claude נכנס ל-worktree במהלך ההפעלה, Claude Code משאיר את ${CLAUDE_PROJECT_DIR} במקום שבו היה ומעביר את נתיב ה-worktree ל-hooks שלכם בדרך אחרת:
${CLAUDE_PROJECT_DIR} נשאר במקום: הוא עדיין מצביע על שורש הפרויקט שבו ההפעלה התחילה, כך שפקודה כמו ${CLAUDE_PROJECT_DIR}/.claude/hooks/check-style.sh עדיין מריצה את הסקריפט ב-checkout הראשי.
cwd עוקב אחרי Claude: השדה cwd ב-JSON של הקלט של ה-hook הוא שורש ה-worktree אחרי ש-Claude נכנס ל-worktree, והתיקייה החדשה אחרי ש-Claude מריץ cd. קראו אותו כש-hook צריך לדעת באיזו תיקייה Claude עובד.
הגדירו hooks של פלאגין ב-hooks/hooks.json עם שדה description אופציונלי ברמה העליונה. כשפלאגין מופעל, ה-hooks שלו מתמזגים עם ה-hooks של המשתמש ושל הפרויקט.
בנוסף לקובצי הגדרות ולפלאגינים, אפשר להגדיר hooks ישירות ב-skills וב-תת-סוכנים באמצעות frontmatter, באותו פורמט הגדרה כמו hooks שמבוססים על קובצי הגדרות. כמה זמן Claude Code משאיר אותם רשומים תלוי ברכיב:
Hooks של תת-סוכן: Claude Code מריץ אותם רק בזמן שאותו תת-סוכן רץ, ומסיר אותם כשהוא מסיים. Claude Code ממיר כאן hook מסוג Stop ל-SubagentStop, האירוע שנורה כשתת-סוכן מסתיים.
Hooks של skill: Claude Code רושם אותם כשאתם או Claude מפעילים את ה-skill, וממשיך להריץ אותם עד סוף ההפעלה, גם בתורות שאחרי התור של ה-skill עצמו. כדי ש-Claude Code יסיר hook אחרי הריצה המוצלחת הראשונה שלו, הגדירו עליו once: true.
ה-skill הזה מגדיר hook מסוג PreToolUse שמריץ סקריפט אימות אבטחה לפני כל פקודת Bash:
תת-סוכנים משתמשים באותו פורמט ב-frontmatter של ה-YAML שלהם.
Hooks ב-frontmatter של skill בפרויקט פועלים לפי אותו כלל אמון בסביבת העבודה כמו hooks בקובצי הגדרות. Claude Code רושם אותם כשאתם או Claude מפעילים את ה-skill, כולל בהרצה עם -p בתיקייה שעדיין לא נתתם בה אמון.
כש-hooks ב-frontmatter של skill לא נורים אחרי שאתם או Claude מפעילים את ה-skill, הריצו /hooks באותה הפעלה. אם הם מופיעים ברשימה, ראו Hook not firing. אם אף אחד מהם לא מופיע, ייתכן שה-skill נמצא תחת נעילה לפלאגינים בלבד או שעבר מגבלת hooks, והוא רץ בלי אף אחד מ-hooks של ה-frontmatter שלו. בדקו כל מקרה:
נעילה לפלאגינים בלבד: מנהל הארגון יכול לנעול hooks לפלאגינים ולהגדרות מנוהלות באמצעות ההגדרה המנוהלת strictPluginOnlyCustomization. skill שומר על hooks של ה-frontmatter שלו תחת הנעילה הזו רק אם הוא skill של פלאגין, skill ארוז, או skill ב-תיקיית ההגדרות המנוהלות. גם ה-hooks בקובצי ההגדרות שלכם לא רצים.
בדיקה: הקלידו /status בהפעלה של Claude Code. אם שורת Setting sources כוללת Enterprise managed settings, שאלו את המנהל אם strictPluginOnlyCustomization נועל hooks.
תיקון: העבירו את ה-skill לתוך פלאגין, כי skills של פלאגין שומרים על hooks של ה-frontmatter שלהם. רשמו את הפלאגין ב-marketplace, ואז התקינו אותו משם. אם Claude Code מסרב ל-marketplace עם is blocked by enterprise policy, בקשו מהמנהל לאפשר את ה-marketplace הזה.
מגבלת hooks: ב-Claude Code גרסה v2.1.304 ואילך, לכל מקור של skills יש מגבלה משלו לכל הפעלה. הפרויקט שלכם, תיקיית ה-skills האישית שלכם, וכל פלאגין נחשבים למקורות נפרדים. ה-skills ממקור אחד יכולים לרשום לכל היותר 1,024 hooks. ה-matchers של אותם hooks יכולים להסתכם לכל היותר ב-16,384 תווים. matcher עם כמה hooks תחתיו נספר פעם אחת לכל hook.
בדיקה: חזרו על ההפעלה שבה ה-hook לא נורה, עם רישום debug מופעל:
התחילו הפעלה חדשה מה-shell עם claude --debug. אם אתם לא מתחילים הפעלות מ-shell, הקלידו קודם /debug בהפעלה החדשה.
הפעילו את אותם skills באותו סדר, כולל אלה ש-Claude הפעיל, כי שני הסיכומים נבנים skill אחרי skill. בקשו מ-Claude להפעיל כל skill שאי אפשר להקליד כפקודה.
חפשו ב-יומן ה-debug את registers none of its hooks. שורה שמכילה את הטקסט הזה מציינת את ה-skill שעבר את המגבלה.
תיקון: הגדירו פחות hooks או matchers קצרים יותר באותו skill או ב-skills האחרים מאותו מקור, ואז התחילו הפעלה חדשה. אם ה-skills האלה לא שלכם לעריכה, בקשו מהמחבר את השינוי. עד אז, התחילו הפעלה חדשה והפעילו את ה-skill שאתם צריכים לפני כל skill אחר מאותו מקור.
הקלידו /hooks ב-Claude Code כדי לפתוח דפדפן לקריאה בלבד של ה-hooks שהוגדרו. הרשימה מתייגת כל hook לפי המקור שלו, למשל הגדרות משתמש, הגדרות פרויקט, הגדרות מקומיות, פלאגין, או ההפעלה הנוכחית.
בחרו hook כדי לראות את הטקסט המלא של מה שהוא מריץ והיכן הוא מוגדר, למשל הנתיב של קובץ ההגדרות שלו או שם הפלאגין שלו.
כדי לעיין בכל אירועי ה-hook, כולל כאלה שאין להם hooks מוגדרים, בחרו All events בסוף הרשימה.
כדי להסיר hook שמוגדר בקובץ הגדרות, מחקו את הרשומה שלו מאותו קובץ.
כדי להשבית זמנית את כל ה-hooks בלי להסיר אותם, הגדירו "disableAllHooks": true בקובץ ההגדרות. Claude Code קורא את הערך שנשאר אחרי שקדימות ההגדרות חלה, כך ש-"disableAllHooks": false ב-.claude/settings.json של פרויקט גובר על true בהגדרות המשתמש. כדי לכבות hooks להרצה אחת בלי קשר למה שכתוב בהגדרות הפרויקט, העבירו --settings '{"disableAllHooks": true}', וזה גובר על הגדרות פרויקט והגדרות מקומיות. אין דרך להשבית hook בודד תוך כדי השארתו בהגדרה.
ההגדרה disableAllHooks מכבדת את היררכיית ההגדרות המנוהלות. אם מנהל הגדיר hooks דרך הגדרות מדיניות מנוהלות, disableAllHooks שמוגדר בהגדרות משתמש, פרויקט או מקומיות לא יכול להשבית את ה-hooks המנוהלים האלה. רק disableAllHooks שמוגדר ברמת ההגדרות המנוהלות יכול להשבית hooks מנוהלים. לטווח המלא של כל רמה, ראו disableAllHooks.
עריכות ישירות של hooks בקובצי הגדרות נקלטות בדרך כלל אוטומטית על ידי צופה הקבצים.
Hooks מסוג פקודה מקבלים נתוני JSON דרך stdin ומעבירים תוצאות דרך קודי יציאה, stdout ו-stderr. Hooks מסוג HTTP מקבלים את אותו JSON כגוף בקשת POST ומעבירים תוצאות דרך גוף תגובת ה-HTTP. הסעיף הזה מכסה שדות והתנהגות משותפים לכל האירועים. הסעיף של כל אירוע תחת אירועי Hook כולל את סכמת הקלט הספציפית שלו ואת אפשרויות בקרת ההחלטה.
ב-macOS וב-Linux, hooks מסוג פקודה רצים בהפעלה משלהם בלי מסוף שולט. תהליך ה-hook וכל תהליכי הבן לא יכולים לפתוח את /dev/tty או לשלוח רצפי escape ישירות לממשק של Claude Code. ב-Windows אין /dev/tty.
כדי להציג הודעה למשתמש בכל פלטפורמה, החזירו systemMessage בפלט JSON. חלק מהאירועים משליכים אותו או מעבירים אותו למקום אחר, והסעיף של כל אירוע מציין זאת. כדי להפעיל התראת שולחן עבודה, להגדיר כותרת חלון, או לצלצל בפעמון, החזירו terminalSequence במקום זאת.
אירועי hook מקבלים את השדות האלה כ-JSON, בנוסף לשדות הספציפיים לאירוע שמתועדים בסעיף של כל אירוע hook. ב-hooks מסוג פקודה, ה-JSON מגיע דרך stdin. ב-hooks מסוג HTTP, הוא מגיע כגוף בקשת POST.
שדה
תיאור
session_id
מזהה ההפעלה הנוכחית
prompt_id
UUID שמזהה את הנחיית המשתמש שמעובדת כרגע. תואם ל-מאפיין prompt.id באירועי OpenTelemetry, כך שאפשר לקשר פלט של hook לטלמטריה של הנחיה אחת. חסר עד הקלט הראשון של המשתמש
transcript_path
נתיב ל-JSON של השיחה. קובץ התמליל נכתב באופן אסינכרוני ועשוי לפגר אחרי השיחה שבזיכרון, ולכן ייתכן שעדיין לא יכלול את ההודעות האחרונות של התור הנוכחי כש-hook נורה. Hooks שצריכים את הטקסט הסופי של העוזר בתור הנוכחי צריכים להשתמש ב-last_assistant_message ב-Stop וב-SubagentStop במקום לקרוא את התמליל
cwd
תיקיית העבודה הנוכחית בזמן שה-hook מופעל
scratchpad_dir
נתיב ל-תיקיית ה-scratchpad של ההפעלה, שבה Claude שומר קבצי עבודה זמניים. חסר כשאין להפעלה scratchpad או כשתיקיית ה-temp לא זמינה. דורש Claude Code גרסה v2.1.257 ואילך
permission_mode
מצב ההרשאות הנוכחי: "default", "plan", "acceptEdits", "auto", "dontAsk", או "bypassPermissions". המצב שמסומן Manual מגיע כ-"default", אף פעם לא כ-"manual", כך שסקריפטים שמתאימים ל-"default" ממשיכים לעבוד. לא כל האירועים מקבלים את השדה הזה. בדקו את דוגמת ה-JSON בסעיף של כל אירוע hook
effort
אובייקט שה-level שלו הוא הגדרת רמת המאמץ בזמן שה-hook רץ, כולל רמה של skill, של תת-סוכן, או של ultrathink: "low", "medium", "high", "xhigh", או "max". קיים ב-PreToolUse, PostToolUse, Stop, SubagentStop, ובאירועים אחרים עם הקשר של שימוש בכלי, במודלים עם effort. אם המודל לא תומך ברמה שלכם, level הוא הרמה שרצה. רמה ששיניתם יכולה להופיע כאן לפני שהיא מתחילה. $CLAUDE_EFFORT מחזיק את אותה רמה.
hook_event_name
שם האירוע שנורה
agent_id ו-agent_type אומרים לסקריפט באיזה סוכן ה-hook נורה, למשל תת-סוכן, חבר צוות בתוך התהליך, או הסוכן שבחרתם עם --agent:
שדה
תיאור
agent_id
מזהה ייחודי לתת-הסוכן או לחבר הצוות בתוך התהליך שבו ה-hook נורה.
agent_type
שם הסוכן (למשל, "Explore" או "security-reviewer"). קיים כשההפעלה משתמשת ב---agent או כשה-hook נורה בתוך תת-סוכן. בתת-סוכנים, סוג תת-הסוכן גובר על ערך --agent של ההפעלה. ראו SubagentStart לערכים שתת-סוכנים מותאמים אישית ושל פלאגין מדווחים, ולאופן כתיבת matcher מול שם בהיקף פלאגין.
רק hooks של SessionStart יכולים לקבל שדה model, ו-Claude Code לא תמיד כולל אותו. Hooks של PreModelSwitch ו-PostModelSwitch מקבלים במקום זאת את from_model ואת to_model, אז השתמשו ב-hook מסוג PostModelSwitch כדי לעקוב אחרי המודל כשהוא משתנה במהלך הפעלה.
אין משתנה סביבה $CLAUDE_MODEL. ה-hook יכול לקרוא את $ANTHROPIC_MODEL אם הגדרתם אותו ב-shell, אבל הערך הזה לא משתנה כשעוברים בין מודלים עם /model במהלך הפעלה.
כשההרצה של ה-hook מסתיימת, Claude Code משתמש בקוד היציאה כדי להחליט אם להמשיך בפעולה שהפעילה אותו, כמו קריאת כלי או פרומפט:
הצלחה: ה-hook יוצא עם 0. Claude Code מחיל את שדות פלט JSON שה-hook הדפיס, והפעולה ממשיכה אלא אם השדות האלה חוסמים או דוחים אותה. Hooks שמתחילים תהליך רקע מכסה את החריג.
שגיאה לא חוסמת: ה-hook יוצא עם כל קוד אחר, או נכשל בדרך אחרת, כמו אי התחלה או הדפסת JSON לא תקין. הפעולה ממשיכה, למעט hooks שכשל שלהם חוסם את הפעולה, למשל hook עם onFailure שמוגדר ל-"block". באירועים כמו PreToolUse, רואים הודעת <hook name> hook error בתמליל.
מה שה-hook מדפיס ל-stdout יכול לשנות את התוצאה. למשל, כש-hook של PreToolUse יוצא עם 1 אבל מדפיס JSON שעובר ולידציה, ה-JSON הזה עדיין יכול להחליט מה קורה. כדי למצוא את התוצאה של ה-hook באירוע כמו PreToolUse, התאימו את מה שהוא הדפיס ל-stdout בעמודה הראשונה לקוד היציאה לאורך השורה העליונה:
שגיאה לא חוסמת. ההודעה נושאת את השורה הראשונה של ה-stderr שלכם
לחלק מהאירועים יש כללים משלהם:
WorktreeCreate: כל קוד יציאה שאינו אפס גורם ליצירת worktree להיכשל, בלי קשר למה שה-JSON אומר.
WorktreeRemove: כל קוד יציאה שאינו אפס גורם להסרת worktree להיכשל אם הספרייה עדיין קיימת אחר כך.
hooks של Stop, SubagentStop, TaskCompleted, ו-UserPromptSubmit של תוסף: כשה-hook יוצא עם 2 בלי כלום ב-stdout וה-stderr שלו אומר שקובץ חסר, כמו No such file or directory, Claude Code מתייחס להרצה כשגיאה לא חוסמת.
Elicitation ו-ElicitationResult: Claude Code מחיל את hookSpecificOutput כשה-hook יוצא עם 0, ומתעלם ממנו בכל קוד יציאה אחר.
אירועים שמשליכים את פלט ה-hook, כמו StopFailure: Claude Code מתעלם מה-JSON בכל קוד יציאה, חוץ משדות תופעת לוואי כמו terminalSequence, שעדיין מופעלים.
יציאה 0 פירושה הצלחה, והיא קוד היציאה המיועד כשמדפיסים JSON לבקרה מובנית. כשה-hook יוצא עם 0 אבל מדפיס JSON שלא ניתן לפרסור או נכשל בולידציית סכמה, הפעולה ממשיכה אלא אם ה-hook הוא אחד שכשל שלו חוסם את הפעולה. במקום הצלחה עם השדות שלכם מוחלים, ההרצה היא שגיאה לא חוסמת.
כדי לתקן את הפלט, השתמשו בהודעת הפרסור או הוולידציה שהודעת <hook name> hook error נושאת. עבור hook שאינו async, ה-stdout נחשב לפלט JSON רק כשמדפיסים אובייקט JSON אחד, בשורה אחת או בכמה, בלי כלום סביבו מלבד רווח לבן. Claude Code קורא כל stdout אחר כטקסט רגיל או ככשל פרסור:
פלט שלא מתחיל ב-{, או שמתחיל ב-{ ולא נגמר ב-}: טקסט רגיל. מערך JSON ומחרוזת JSON במרכאות הם טקסט רגיל לפי הכלל הזה.
שתי שורות או יותר שכל אחת מהן מפורסרת כ-JSON בפני עצמה, הראשונה מתחילה ב-{ והאחרונה נגמרת ב-}: טקסט רגיל כשאף שורה אינה אובייקט פלט JSON שמגדיר שדה. כשאחת מהשורות היא כזו, הפלט הוא כשל פרסור, אז הדפיסו את האובייקט הזה בלי שום דבר אחר ב-stdout.
כל דבר אחר שמתחיל ב-{ ונגמר ב-} אבל אינו JSON תקין: כשל פרסור.
ברוב האירועים, Claude Code כותב את stdout ללוג הדיבוג ולא מציג אותו בתמליל. החריגים הם UserPromptSubmit, UserPromptExpansion, SessionStart ו-PostModelSwitch, שבהם Claude Code מוסיף stdout בטקסט רגיל כהקשר ש-Claude יכול לראות ולפעול לפיו. באירועים האלה, Claude Code לא מוסיף stdout שהוא נכשל לפרסר.
Claude אף פעם לא רואה stderr מ-hook שיוצא עם 0. כדי לקרוא אותו בעצמכם באירועים כמו PreToolUse, הפעילו רישום דיבוג. כדי להציף אזהרה ל-Claude מ-hook של PostToolUse או PostToolUseFailure, צאו עם 2 במקום כדי שClaude יראה את ה-stderr למרות שהכלי כבר רץ.
צאו עם קוד 2 כדי לחסום את הפעולה. באירועים שיכולים לחסום, Claude Code עוצר את הפעולה: hook של PreToolUse חוסם את קריאת הכלי, למשל, ו-hook של UserPromptSubmit דוחה את הפרומפט.
ההודעה שמגיעה עם החסימה היא ה-stderr של ה-hook. אם ה-hook גם הדפיס JSON שמקבל החלטה חוסמת, Claude Code משתמש בסיבה של ההחלטה הזו במקום.
יציאה 2 חוסמת גם כשה-hook מדפיס JSON:
JSON שעובר ולידציית סכמה: Claude Code עדיין קורא את שדות פלט JSON, אבל הם לא יכולים לבטל את החסימה. אפילו permissionDecision של "allow" לא מעביר את הפעולה. ב-Elicitation וב-ElicitationResult, מתעלמים מ-hookSpecificOutput של hook עם יציאה 2.
JSON שנכשל בולידציית סכמה: ה-hook עדיין חוסם. Claude Code משתמש ב-stderr שלכם כסיבת החסימה ורושם את כשל הוולידציה בלוג הדיבוג.
הסקריפט הזה חוסם פקודות rm על ידי יציאה עם 2 ומשאיר כל פקודה אחרת לזרימת ההרשאות הרגילה:
#!/bin/bash
# Reads JSON input from stdin, checks the command
input=$(cat)
command=$(jq -r '.tool_input.command' <<<"$input")
if [[ "$command" == rm* ]]; then
echo "Blocked: rm commands are not allowed" >&2
exit 2 # Blocking error: tool call is prevented
fi
exit 0 # No decision: the normal permission flow applies
עם הסקריפט הזה רשום כ-hook של PreToolUse על Bash, פקודה שמתחילה ב-rm נחסמת, ו-Claude מקבל את ה-stderr של ה-hook כשגיאת הכלי, עם קידומת של שם האירוע, שם הכלי, ופקודת ה-hook:
PreToolUse:Bash hook error: [${CLAUDE_PROJECT_DIR}/.claude/hooks/no-rm.sh]: Blocked: rm commands are not allowed
הודעת <hook name> hook error עם Failed with non-blocking status code: פירושה שקוד היציאה של ה-hook לא היה 0 או 2 וה-stdout שלו היה טקסט רגיל או ריק. אלא אם ה-hook הוא אחד שכשל שלו חוסם את הפעולה, זו שגיאה לא חוסמת, כך שה-hook לא עצר את הפעולה. כדי ללכוד את ה-stderr המלא של ה-hook במקום השורה הראשונה שההודעה מציגה, הפעילו רישום דיבוג.
למשל, כש-hook של PreToolUse על Bash מדפיס something broke ל-stderr ויוצא עם 1, הודעת PreToolUse:Bash hook error נושאת את השורה הזו:
Failed with non-blocking status code: something broke
אם ההודעה נושאת את הודעת המעטפת No such file or directory, כמו בשורה הבאה, ה-hook אף פעם לא רץ, למשל כי נתיב הסקריפט שלו לא קיים:
Failed with non-blocking status code: /bin/sh: /path/to/hook.sh: No such file or directory
אם הנתיב שגוי, תקנו אותו במקום שבו ה-hook מוגדר. בצורת מעטפת, כשנתיב הסקריפט לא קיים או אינו ניתן להרצה, המעטפת יוצאת עם קוד כמו 127 וההודעה נושאת את הודעת המפרש. אלא אם ה-hook הוא אחד שכשל שלו חוסם את הפעולה, hook שלא יכול להתחיל הוא גם שגיאה לא חוסמת.
כשמגדירים hook מדיניות, שימו לב להודעה הזו בהרצה הראשונה שלו, כי נתיב עם שגיאת הקלדה ב-settings.json אומר שה-hook אף פעם לא רץ. כדי לחסום את הפעולה כשה-hook לא יכול להתחיל, הגדירו onFailure: "block".
[!WARNING]
קוד יציאה 1 בלי פלט JSON תקין הוא שגיאה לא חוסמת אלא אם ה-hook הוא אחד שכשל שלו חוסם את הפעולה, למרות ש-1 הוא קוד הכשל המקובל ב-Unix. אם ה-hook נועד לאכוף מדיניות, השתמשו ב-exit 2.
מלבד hook של command שרצים עם async: true, Claude Code מבטל hook מסוג command, http או mcp_tool שמגיע ל-timeout שלו, משליך את פלט ה-hook, כך שברוב האירועים hook שפג זמנו לא מפיק החלטה. ב-PreModelSwitch, hook שבוטל בפסק הזמן שלו חוסם את החלפת המודל.
אם ה-hook של command מקבל את ההחלטה שלו בתהליך רקע ויוצא, דחייה שהתהליך הזה מדפיס אחרי ש-Claude Code הפסיק לקרוא לא חוסמת את קריאת הכלי. עבור hook שאינו async, Claude Code מסיים לקרוא את פלט ה-hook זמן קצר אחרי שתהליך ה-hook עצמו יוצא.
הדפיסו את ההחלטה לפני שמתחילים תהליך רקע, והפנו את stdout ו-stderr של התהליך הזה. אם הסקריפט מדפיס allow, ואז מתחיל תהליך רקע בלי להפנות את stdout ו-stderr של התהליך הזה, Claude Code חוסם את קריאת הכלי. שגיאת ה-hook כוללת refusing to honor the suspect capture.
סקריפט ה-hook הזה של PreToolUse מדפיס את ההחלטה עם policy-check.sh, ואז מעלה מדדים ברקע:
|| exit $?: הופך את קוד היציאה של הבדיקה לקוד של ה-hook עצמו, כך שבדיקה שיוצאת עם 2 כדי לדחות עדיין חוסמת. אחרת ה-hook יוצא עם הקוד של השורה האחרונה, שהוא 0.
>/dev/null 2>&1 &: מריץ את upload-metrics.sh ברקע עם הפלט שלו מופנה, כך שהוא לא משאיר את פלט ה-hook פתוח.
כדי לבדוק את הסקריפט, גרמו ל-policy-check.sh לצאת עם 2, ואז הפעילו קריאת כלי שה-hook תואם לה. קריאת הכלי נחסמת.
ברוב האירועים, כש-hook נכשל או מגיע לפסק זמן, Claude Code עדיין מבצע את הפעולה. hook מדיניות עם נתיב שגוי או סקריפט שקורס אז מעביר הכל. כדי לחסום את הפעולה במקום זאת, הגדירו "onFailure": "block" על hook של command או http. נדרש Claude Code v2.1.295 או מאוחר יותר. עבור hooks של callback ב-Agent SDK, ראו חסימת הפעולה כש-callback נכשל.
[!NOTE]
ב-Windows בלי Git Bash, hook של command בצורת מעטפת מסוג PreToolUse או PermissionRequest שנכשל כש-onFailure לא מוגדר יכול במקום זאת לחסום את קריאת הכלי.
ה-hook הזה של PreToolUse ב-.claude/settings.json מריץ סקריפט פרויקט לפני כל פקודת Bash, וחוסם את הפקודה אם הסקריפט נכשל:
כדי לבדוק אותו, השאירו את check-command.js חסר ובקשו מ-Claude להריץ פקודת Bash כמו ls. Claude Code חוסם את הקריאה, והשגיאה כוללת failed; blocking because onFailure is "block" ואחריו פלט השגיאה של node עצמו, שקוצץ כאן לשורה אחת:
PreToolUse:Bash hook error: [node ${CLAUDE_PROJECT_DIR}/.claude/hooks/check-command.js]: failed; blocking because onFailure is "block"
Error: Cannot find module '/path/to/project/.claude/hooks/check-command.js'
אחרי פסק זמן, ההודעה אומרת timed out במקום failed. בלי onFailure מוגדר, אותו סקריפט חסר הוא שגיאה לא חוסמת ו-ls רץ.
כל אחד מאלה נחשב לכשל:
לא יכול להתחיל: hook של command נכשל להתחיל, למשל כי הסקריפט או קובץ ההרצה לא קיים
קוד יציאה שאינו 0 או 2: נחשב עבור hook של command גם אם הוא הדפיס JSON שמתיר את הפעולה, כמו permissionDecision: "allow". כדי להחזיר החלטת JSON, צאו עם 0
שגיאת HTTP: החיבור של hook מסוג HTTP נכשל, או שסטטוס התגובה אינו 2xx
פלט לא תקין: פלט ה-JSON לא ניתן לפרסור או נכשל בולידציית סכמה. עבור hook מסוג HTTP, גוף 2xx שאינו ריק ואינו אובייקט JSON גם נחשב. stdout בטקסט רגיל מ-hook של command אינו כשל
עם "block" מוגדר, כשל עושה את מה שקוד יציאה 2 עושה באירוע הזה, למעט ב-PermissionRequest, שם הוא דוחה את הבקשה. למשל, כשל של PreToolUse חוסם את קריאת הכלי וכשל של UserPromptSubmit חוסם את הפרומפט.
לשדה אין השפעה על ה-hooks האלה:
hooks של Stop, SubagentStop, TaskCompleted ו-TeammateIdle: קוד יציאה 2 באירועים האלה שולח את Claude בחזרה להמשיך לעבוד, ו-Claude לא יכול לתקן hook שלא רץ
בלי Git Bash, כל קוד יציאה שאינו 0 או 2 מה-hook הזה נחשב לכשל, גם כשהוא מדפיס JSON שלא דוחה את הקריאה. כדי לגלות למה ה-hook נכשל, בדקו את לוג הדיבוג. אחר כך בחרו את התיקון שמתאים ל-hook שלכם:
ה-hook יוצא עם 1 כדי להזהיר אבל חייב לחסום כשהוא קורס: עם "onFailure": "continue", הקריאה ממשיכה בקוד יציאה 1, באזהרה ובקריסה כאחד. הוסיפו "onFailure": "block" במקום, וגרמו לסקריפט לצאת עם 0 במקום שבו הוא מזהיר, כך שהקריאות האלה ממשיכות. כדי עדיין להציג את האזהרה ב-PreToolUse, הדפיסו אותה ל-stdout כשדה systemMessage של אובייקט JSON אחד.
ה-hook נכתב עבור Bash: בלי Git Bash, hook בצורת מעטפת בלי shell מוגדר רץ ב-PowerShell, שם הוא יכול להיכשל. התקינו Git for Windows, או הגדירו CLAUDE_CODE_GIT_BASH_PATH אם Git Bash מותקן במקום ש-Claude Code לא מוצא אותו. אחר כך התחילו סשן חדש.
ה-hook מריץ קובץ .exe אחד, לא קובץ .cmd או .bat: שימו את התוכנית ב-command ואת הארגומנטים שלה ב-args כדי להשתמש בצורת exec, והוסיפו "onFailure": "block". Claude Code אז מתחיל את התוכנית בלי מעטפת. בלי "onFailure": "block", הקריאה יכולה להמשיך כשהתוכנית נכשלת, חסרה, או מגיעה לפסק זמן
hook שמירה של PowerShell שחייב לחסום בכשל: עם onFailure לא מוגדר, הוא מפסיק לעשות זאת ברגע ש-Git for Windows מותקן ו-Claude Code מוצא את Git Bash. הוסיפו "onFailure": "block" כך שכשל או פסק זמן חוסם את הקריאה עם Git Bash או בלעדיו. גם הגדירו "shell": "powershell" כך שה-hook ממשיך לרוץ ב-PowerShell מכאן והלאה במקום ב-Git Bash
לפני v2.1.309, ההודעה הייתה blocking because Git Bash wasn't found and this hook doesn't set "shell" to "powershell", so only exit code 0 or 2 counts as its verdict.
הוק עם השגיאה הזו רץ ב-PowerShell, שמדפיסה command שהוא רק מחרוזות במרכאות, כמו "command": "\"C:\\Tools\\guard.exe\"", במקום להריץ אותו.
כדי להדפיס טקסט, כמו JSON: הגדירו "shell": "powershell", וההוק יוצא עם קוד 0
כדי להריץ קובץ .ps1, .cmd או .bat, או קובץ .exe שהנתיב שלו כולל משתנה: הגדירו "shell": "powershell" ושימו & לפני הנתיב המצוטט. השאירו את $HOME כפי שהוא כתוב, וכתבו משתני סביבה כפי שדוגמת check.ps1 כותבת את $env:CLAUDE_PROJECT_DIR
כדי להריץ קובץ .exe אחד בנתיב בלי $: הסירו את המרכאות הפנימיות מ-command, ואז החילו את התיקון להוק שמריץ קובץ .exe אחד, וכתבו "args": [] אם התוכנית לא מקבלת ארגומנטים
קוד יציאה 2 הוא הדרך שבה הוק מסמן "עצור, אל תעשה את זה." ההשפעה תלויה באירוע, כי חלק מהאירועים מייצגים פעולות שאפשר לחסום (כמו קריאת כלי שעדיין לא קרתה) ואחרים מייצגים דברים שכבר קרו או שאי אפשר למנוע.
אירוע הוק
אפשר לחסום?
מה קורה בקוד יציאה 2
PreToolUse
כן
חוסם את קריאת הכלי
PermissionRequest
לא
קוד יציאה 2 לא נאכף לאירוע הזה וזרימת ההרשאה ממשיכה ללא שינוי. סרבו דרך אובייקט decision
מונע מחבר הצוות לעבור למצב idle, כך שהוא ממשיך לעבוד
TaskCreated
כן
מחזיר לאחור את יצירת המשימה
TaskCompleted
כן
מונע סימון של המשימה כהושלמה
ConfigChange
כן
חוסם את כניסת שינוי התצורה לתוקף (מלבד policy_settings)
StopFailure
לא
מתעלמים מהפלט ומקוד היציאה, מלבד terminalSequence
PostToolUse
לא
מציג את stderr ל-Claude. הכלי כבר רץ
PostToolUseFailure
לא
מציג את stderr ל-Claude. הכלי כבר נכשל
PostToolBatch
כן
עוצר את הלולאה הסוכנית לפני קריאת המודל הבאה
PermissionDenied
לא
מתעלמים מקוד היציאה ומ-stderr כי הסירוב כבר התרחש. השתמשו ב-JSON hookSpecificOutput.retry: true כדי לומר למודל שהוא רשאי לנסות שוב. Claude Code מתעלם מ-retry: true עבור סירובים ללא הכרעה
Notification
לא
מתעלמים מקוד היציאה ומ-stderr
SubagentStart
לא
מציג את stderr למשתמש בלבד
SessionStart
לא
מציג את stderr למשתמש בלבד
Setup
לא
מתעלמים מקוד היציאה ומ-stderr
SessionEnd
לא
מציג את stderr למשתמש בלבד
CwdChanged
לא
מציג את stderr למשתמש בלבד
DirectoryAdded
לא
stderr עובר ליומן הדיבוג. הספרייה כבר נוספה
FileChanged
לא
מציג את stderr למשתמש בלבד
PreCompact
כן
חוסם את הדחיסה
PostCompact
לא
מציג את stderr למשתמש בלבד
PreModelSwitch
כן
חוסם את החלפת המודל ומציג את stderr למשתמש
PostModelSwitch
לא
מציג את stderr למשתמש בלבד. המודל כבר הוחלף
Elicitation
כן
דוחה את הבקשה, ולא מופיעה תיבת דו שיח
ElicitationResult
כן
חוסם את התגובה (הפעולה הופכת ל-decline)
WorktreeCreate
כן
כל קוד יציאה שאינו אפס גורם ליצירת worktree להיכשל
WorktreeRemove
כן
כל קוד יציאה שאינו אפס גורם להסרת worktree להיכשל אם הספרייה עדיין קיימת לאחר מכן. ראו WorktreeRemove לגבי מה שקורה לספרייה
InstructionsLoaded
לא
מתעלמים מקוד היציאה
MessageDisplay
לא
הטקסט המקורי מוצג
עבור SessionStart, SubagentStart ו-PostModelSwitch, Claude Code מציג את stderr של קוד יציאה 2 בתמליל כהודעת <hook name> hook error, באותו אופן שבו הוא מציג שגיאה לא חוסמת. Claude לא רואה אותה, והסשן או הסוכן המשנה ממשיכים. עבור SubagentStart, ההודעה מופיעה בתמליל של הסוכן המשנה עצמו, ולא בשיחת האב.
הוקי HTTP משתמשים בקודי סטטוס של HTTP ובגופי תגובה במקום בקודי יציאה וב-stdout. כדי לחסום את הפעולה כאשר הבקשה נכשלת או מחזירה סטטוס שאינו 2xx, הגדירו onFailure: "block". כדי לחסום קריאת כלי או לסרב להרשאה, החזירו תגובת 2xx עם גוף JSON שמכיל את שדות ההחלטה המתאימים.
קודי יציאה מאפשרים רק לחסום או להישאר בשתיקה, אבל פלט JSON נותן שליטה מפורטת יותר. במקום לצאת עם קוד 2 כדי לחסום, צא עם 0 והדפס אובייקט JSON ל-stdout. Claude Code קורא שדות מסוימים מאותו JSON כדי לשלוט בהתנהגות, כולל בקרת החלטה לחסימה, לאישור, או להסלמה למשתמש.
[!NOTE]
בחר גישה אחת לכל hook: או להשתמש בקודי יציאה בלבד לאיתות, או לצאת עם 0 ולהדפיס JSON לשליטה מובנית. אם מערבבים ביניהן, יציאה 2 שומרת על אפקט החסימה שלה, ו-Claude Code עדיין קורא את שדות ה-JSON, עם חריג ה-elicitation היחיד שמצוין תחת קוד יציאה 2.
הדפס ל-stdout רק את אובייקט ה-JSON. ב-hook שאינו async, טקסט אחר שם, למשל שורה שפרופיל המעטפת מהדהד בהפעלה, מונע מ-Claude Code לקרוא את האובייקט כ-JSON, ו-ל-JSON של hook אין השפעה מראה איך למצוא ולהשתיק את הטקסט הזה.
המחרוזות additionalContext, systemMessage ו-initialUserMessage של hook, וגם ה-stdout הרגיל שלו, מוגבלות ל-10,000 תווים:
היקף: Claude Code מודד כל מחרוזת בפני עצמה, גם כשכמה hooks רצים לאותו אירוע. בפלט JSON כל שדה נמדד בנפרד. stdout רגיל נמדד בשלמותו.
מעל המגבלה: Claude Code שומר את הפלט בקובץ בתיקיית הסשן ומחליף אותו בנתיב הקובץ ובתצוגה מקדימה של עד 2,000 התווים הראשונים. תוצאת Bash גדולה ותקינה מטופלת באותו אופן, כמתואר תחת מגבלות פלט. בניגוד לתקרת ה-Bash הזו, למגבלה הזו אין הגדרה או משתנה סביבה כדי להעלות אותה.
קריאת הקובץ: Claude Code לא מבקש מ-Claude לקרוא את הקובץ, לכן שמור בתוך המגבלה כל דבר ש-Claude חייב תמיד לראות.
אובייקט ה-JSON תומך בשלושה סוגי שדות:
שדות אוניברסליים כמו continue מופיעים בטבלה למטה. כל אירוע מקבל אותם, אבל חלק מהאירועים משליכים אותם או מעבירים את systemMessage למקום שאינו התמליל. הסעיף של כל אירוע מציין זאת. terminalSequence עובד גם באירועים האלה, עם החריגים שמפורטים תחת שידור התראות טרמינל.
decision ו-reason ברמה העליונה משמשים חלק מהאירועים לחסימה או למתן משוב.
hookSpecificOutput הוא אובייקט מקונן לאירועים שצריכים שליטה עשירה יותר. הוא דורש שדה hookEventName שמוגדר לשם האירוע.
שדה
ברירת מחדל
תיאור
continue
true
אם false, Claude מפסיק את העיבוד לגמרי אחרי שה-hook רץ. גובר על כל שדות החלטה שספציפיים לאירוע
stopReason
none
הודעה שמוצגת למשתמש כש-continue הוא false. היא נשארת בשיחה, ולכן Claude רואה אותה אם השיחה ממשיכה
suppressOutput
false
אין לו השפעה: Claude Code מקבל את השדה אבל לא פועל לפיו. stdout של hook שהצליח אף פעם לא מוצג בתמליל, והוא נרשם ביומן הדיבוג
רצף escape של טרמינל ש-Claude Code ישדר בשמך, למשל התראת שולחן עבודה, כותרת חלון, או פעמון. מוגבל ל-OSC 0/1/2/9/99/777 ול-BEL. אם הערך מכיל משהו מחוץ לרשימת ההיתר, מתעלמים מהשדה. השתמש בזה במקום לכתוב ל-/dev/tty, שאינו זמין ל-hooks
Hooks רצים בלי טרמינל שולט, ולכן כתיבת רצפי escape ישירות ל-/dev/tty נכשלת. במקום זאת, החזר את רצף ה-escape בשדה terminalSequence, ו-Claude Code משדר אותו עבורך דרך נתיב הכתיבה לטרמינל שלו. זה חופשי מתנאי מרוץ, עובד בתוך tmux ו-GNU screen, ועובד ב-Windows שבה אין /dev/tty.
השדה מקבל מחרוזת של רצף escape אחד או יותר מהרשימה המותרת:
OSC 0, 1, 2: כותרות חלון ואייקון
OSC 9: התראות של iTerm2, ConEmu, Windows Terminal ו-WezTerm, כולל התקדמות בשורת המשימות 9;4
OSC 99: התראות Kitty
OSC 777: התראות urxvt, Ghostty ו-Warp
BEL בלבד
רצפים יכולים להסתיים ב-BEL או ב-ST. כל דבר מחוץ לרשימת ההיתר, כולל רצפי CSI של סמן וצבע, רצפי לוח צבעים OSC, היפר-קישורים OSC 8, כתיבות ללוח OSC 52, ו-OSC 1337, נדחה, ומתעלמים מהשדה.
Claude Code כותב את הרצף בעצמו כשהוא מעבד את פלט ה-hook, ולכן השדה עובד באירועים שמשליכים את systemMessage ואת continue, כמו Notification ו-StopFailure. יש לו שתי מגבלות:
Claude Code כותב את הרצף רק בסשן אינטראקטיבי, ורק כשהממשק שלו על המסך. במצב לא אינטראקטיבי עם הדגל -p וב-Agent SDK, הוא מתעלם מהשדה.
hook פקודה של WorktreeCreate לא יכול להחזיר JSON, כי Claude Code קורא את ה-stdout שלו כנתיב ה-worktree. hook HTTP של WorktreeCreate מחזיר JSON ויכול לכלול את השדה.
הדוגמה למטה משגרת התראת שולחן עבודה מ-hook של Notification. רצף ה-escape נבנה עם escape אוקטלי של printf כדי שבתי הבקרה לעולם לא יופיעו בשורת הפקודה של המעטפת, ו-jq -n --arg בונה את פלט ה-JSON כדי שמרכאות, לוכסנים הפוכים ושורות חדשות בהודעת ההתראה יוברחו נכון:
#!/bin/bash
# Notification hook: ping the desktop when Claude Code needs attention.
input=$(cat)
title="Claude Code"
body=$(jq -r '.message // "Needs your attention"' <<<"$input")
seq=$(printf '\033]777;notify;%s;%s\007' "$title" "$body")
jq -nc --arg seq "$seq" '{terminalSequence: $seq}'
הצורה { "terminalSequence": "..." } זהה מכל מעטפת או שפה.
השדה additionalContext מעביר מחרוזת מה-hook לחלון ההקשר של Claude. Claude Code עוטף את המחרוזת ב-תזכורת מערכת ומכניס אותה לשיחה בנקודה שבה ה-hook נורה. Claude קורא את התזכורת בבקשת המודל הבאה, אבל היא לא מופיעה כהודעת צ'אט בממשק.
החזר additionalContext בתוך hookSpecificOutput לצד שם האירוע:
{
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"additionalContext": "This file is generated. Edit src/schema.ts and run `bun generate` instead."
}
}
כשכמה hooks מחזירים additionalContext לאותו אירוע, Claude מקבל את כל הערכים.
אם המחרוזת שלך מכילה תג <system-reminder> או </system-reminder>, Claude מקבל את המחרוזת כשה-< של התג הזה מוחלף ב-<.
אם ערך עובר את 10,000 התווים, Claude Code כותב את הטקסט לקובץ בתיקיית הסשן ומעביר ל-Claude את נתיב הקובץ עם תצוגה מקדימה של עד 2,000 התווים הראשונים במקום. Claude יכול לקרוא את הקובץ, אבל Claude Code לא מבקש ממנו לעשות זאת.
השתמש ב-additionalContext למידע ש-Claude צריך לדעת על המצב הנוכחי של הסביבה שלך או על הפעולה שרצה עכשיו:
מצב הסביבה: הענף הנוכחי, יעד הפריסה, או דגלי תכונה פעילים
כללי פרויקט מותנים: איזו פקודת בדיקה חלה על הקובץ שנערך עכשיו, אילו תיקיות הן לקריאה בלבד ב-worktree הזה
נתונים חיצוניים: בעיות פתוחות שמוקצות אליך, תוצאות CI אחרונות, תוכן שנשלף משירות פנימי
להוראות שלעולם לא משתנות, העדף את CLAUDE.md. הוא נטען בלי להריץ סקריפט, והוא המקום הסטנדרטי למוסכמות פרויקט סטטיות.
כתוב את הטקסט כהצהרות עובדתיות ולא כהוראות מערכת בציווי. ניסוח כמו "The deployment target is production" או "This repo uses bun test" נקרא כמידע על הפרויקט. טקסט שממוסגר כפקודות מערכת מחוץ לערוץ יכול להפעיל את הגנות הזרקת ההנחיות של Claude, וזה גורם ל-Claude להציג לך את הטקסט במקום להתייחס אליו כהקשר.
Claude Code שומר את הטקסט שהוזרק בתמליל הסשן. לאירועי אמצע סשן כמו PostToolUse או UserPromptSubmit, כשממשיכים עם --continue או --resume, Claude Code מנגן מחדש את הטקסט השמור במקום להריץ שוב את ה-hook לתורות קודמים, ולכן ערכים כמו חותמות זמן או SHA של commit מתיישנים. hooks של SessionStart רצים שוב בהמשך, עם source שמוגדר ל-"resume", או ל-"fork" אם הוספת --fork-session, כדי שיוכלו לרענן את ההקשר שלהם.
לא כל אירוע תומך בחסימה או בשליטה בהתנהגות דרך JSON. האירועים שכן תומכים משתמשים כל אחד בסט שדות שונה כדי לבטא את ההחלטה. השתמש בטבלה הזו כהפניה מהירה לפני כתיבת hook:
UserPromptSubmit: לא יכול להחליף את ההנחיה. הוא רק מזריק additionalContext לצידה
למקרי שימוש של השחרה או המרה, יירט ב-PreToolUse לקלטי כלים יוצאים וב-PostToolUse לתוצאות כלים נכנסות.
הנה דוגמאות של כל תבנית בפעולה:
החלטה ברמה העליונה
הערך היחיד של decision הוא "block". כדי לאפשר לפעולה להמשיך, השמט את decision מה-JSON, או צא עם 0 בלי JSON בכלל:
{
"decision": "block",
"reason": "Test suite must pass before proceeding"
}
PreToolUse
משתמש ב-hookSpecificOutput לשליטה עשירה יותר: לאפשר, לדחות, או להסלים למשתמש. אפשר גם לשנות קלט של כלי לפני שהוא רץ, או להזריק הקשר נוסף ל-Claude. ראה בקרת החלטה של PreToolUse לסט האפשרויות המלא.
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Database writes are not allowed"
}
}
PermissionRequest
משתמש ב-hookSpecificOutput כדי לאפשר או לדחות בקשת הרשאה בשם המשתמש. כשמאפשרים, אפשר גם לשנות את הקלט של הכלי או להחיל כללי הרשאה כדי שהמשתמש לא יתבקש שוב. ראה בקרת החלטה של PermissionRequest לסט האפשרויות המלא.
כל אירוע מתאים לנקודה במחזור החיים של Claude Code שבה hooks יכולים לרוץ. הסעיפים למטה מסודרים כך שיתאימו למחזור החיים: מהגדרת הסשן, דרך לולאת הסוכן, ועד סוף הסשן. כל סעיף מתאר מתי האירוע נורה, אילו matchers הוא תומך בהם, את קלט ה-JSON שהוא מקבל, ואיך לשלוט בהתנהגות דרך הפלט.
רץ כאשר Claude Code מתחיל סשן חדש או ממשיך סשן קיים. שימושי לטעינת הקשר פיתוח כמו בעיות קיימות או שינויים אחרונים בבסיס הקוד, או להגדרת משתני סביבה. להקשר סטטי שאינו דורש סקריפט, השתמשו ב-CLAUDE.md במקום.
SessionStart רץ בכל סשן, לכן שמרו על ההוקים האלה מהירים. נתמכים רק הוקים מסוג type: "command" ו-type: "mcp_tool". ראו שדות הוק של כלי MCP לגבי מתי הוקים מסוג mcp_tool רצים.
ערך ה-matcher תואם לאופן שבו הסשן הופעל:
Matcher
מתי הוא נורה
startup
סשן חדש
resume
--resume, --continue, או /resume
clear
/clear
compact
דחיסה אוטומטית או ידנית
fork
סשן חדש שפוצל מסשן קיים: --fork-session עם --resume או --continue, העותק ברקע של /fork, /branch, או שיחה שמעבירים לרקע
כאשר מתחילים סשן אינטראקטיבי, ממשיכים שיחה בהפעלה עם --continue או --resume, או מריצים /clear, הוקים של SessionStart רצים ברקע. אפשר להקליד מיד, ושיחה שהמשכתם מופיעה בלי להמתין להוקים. התשובה הראשונה של Claude עדיין ממתינה שההוקים יסתיימו, כדי שההקשר שלהם יגיע אל Claude.
כאשר מחליפים שיחות עם /resume בתוך סשן, ההחלפה ממתינה שההוקים יסתיימו. אם מריצים /clear או עוברים לשיחה אחרת בזמן שהוקים ברקע עדיין רצים, שום דבר שהם מחזירים לא חל על הסשן.
אותה המתנה חלה בהפעלה, כולל סשן שהומשך: פרומפט ששולחים בזמן שהוקים של SessionStart עדיין רצים לא מגיע אל Claude עד שהם מסתיימים.
במהלך כל אחת מההמתנות, לחצו Esc כדי להחזיר את הפרומפט לקלט בלי לשלוח אותו. ההוקים ממשיכים לרוץ.
בנוסף לשדות הקלט המשותפים, הוקים של SessionStart מקבלים את source ואופציונלית את model, agent_type, ו-session_title:
שדה
תיאור
source
איך הסשן התחיל: "startup" לסשנים חדשים, "resume" לסשנים שהומשכו, "clear" אחרי /clear, "compact" אחרי דחיסה, או "fork" לסשן חדש שפוצל מסשן קיים
model
מזהה המודל הפעיל. הוא יכול להיעדר, למשל אחרי /clear או כאשר סשן משוחזר דרך שחזור שיחה, לכן בדקו שהשדה קיים לפני שקוראים אותו
agent_type
שם הסוכן, נוכח כאשר מתחילים את Claude Code עם claude --agent <name>
session_title
הכותרת המותאמת של הסשן, נוכחת כאשר הוגדרה אחת, למשל עם --name, /rename, פלט sessionTitle של הוק, או renameSession() של Agent SDK. הוק שפולט sessionTitle יכול לבדוק את השדה הזה קודם כדי להימנע מדריסת כותרת מותאמת קיימת
סשן שלא נתתם לו שם עדיין יכול לכלול כותרת שנוצרה. הכותרת הזו אינה כותרת מותאמת ואינה מופיעה ב-session_title.
כאשר source הוא "resume" או "fork" והתמליל מכיל לפחות תשובה אחת מ-Claude, הוקים של SessionStart מקבלים גם את ארבעת השדות למטה. ההוק יכול להשתמש בהם כדי לדווח מה עולה המשך של שיחה ישנה לפני הבקשה הראשונה, למשל ב-systemMessage. השדות האלה דורשים Claude Code גרסה v2.1.251 או מאוחרת יותר.
שדה
תיאור
seconds_since_last_response
שניות שעון קיר מאז התשובה האחרונה בתמליל שהומשך
context_tokens
טוקנים שהבקשה הראשונה של הסשן שהומשך שולחת מחדש כפרומפט שלה
prompt_cache_likely_expired
true כאשר התשובה האחרונה ישנה יותר ממשך החיים של מטמון הפרומפט של הסשן, או שדחיסה מאוחרת יותר החליפה את השיחה שנשמרה במטמון
estimated_cache_write_usd
עלות משוערת בדולר ארה"ב של כתיבת context_tokens למטמון הפרומפט במודל של הסשן, בלי התשובה
הדוגמה הזו מציגה את הקלט לסשן שהומשך 90 דקות אחרי התשובה האחרונה שלו:
הוק של SessionStart יכול להוסיף הקשר עבור Claude, לספק את הודעת המשתמש הראשונה, להגדיר את כותרת הסשן, לעקוב אחרי קבצים, ולטעון מחדש skills. החזירו את השדה של כל אחד, בנוסף לשדות פלט JSON הזמינים לכל ההוקים:
שדה
תיאור
additionalContext
מחרוזת שמתווספת להקשר של Claude בתחילת השיחה, לפני הפרומפט הראשון. ראו הוספת הקשר עבור Claude לגבי אופן מסירת הטקסט ומה לשים בו
initialUserMessage
מחרוזת שמשמשת כהודעת המשתמש הראשונה של הסשן, במצב לא אינטראקטיבי עם הדגל -p. היא הופכת לתור הראשון גם אם לא מעבירים פרומפט. פרומפט שכן מעבירים בא אחריה כתור הבא
sessionTitle
מגדיר את כותרת הסשן, עם אותו אפקט כמו /rename. חל כאשר source הוא "startup", "resume", או "fork"
watchPaths
מערך של נתיבים מוחלטים למעקב אחרי אירועי FileChanged במהלך הסשן הזה
הוק שרק מוסיף הקשר יכול להדפיס אותו בלי לבנות JSON, כי Claude Code מוסיף את stdout בטקסט רגיל של הוק SessionStart להקשר של Claude.
אם הוק SessionStart של התוסף מספק initialUserMessage או sessionTitle, התקינו את התוסף לפני שהסשן מתחיל. Claude Code מתעלם משני השדות מתוסף שמסיים להתקין אחרי שהוקים של SessionStart כבר רצו.
כדי ש-skills שהוק SessionStart מתקין יהיו זמינים באותו סשן, החזירו reloadSkills. גילוי skills רץ בדרך כלל לפני שהוקים של SessionStart מסתיימים, ולכן בלעדיו, קבצים שהוק כותב אל ~/.claude/skills/ או .claude/skills/ עלולים להיעדר כאשר הפרומפט הראשון רץ.
הדוגמה הזו מסנכרנת מאגר skills משותף ומבקשת את הסריקה מחדש:
להוקים של SessionStart יש גישה למשתנה הסביבה CLAUDE_ENV_FILE, שמספק נתיב קובץ שבו אפשר לשמור משתני סביבה עבור פקודות המעטפת ש-Claude מריץ בהמשך הסשן.
כדי להגדיר משתני סביבה בודדים, כתבו הצהרות export אל CLAUDE_ENV_FILE. השתמשו בצירוף (>>) כדי לשמור משתנים שהוגדרו על ידי הוקים אחרים:
#!/bin/bash
if [ -n "$CLAUDE_ENV_FILE" ]; then
echo 'export NODE_ENV=production' >> "$CLAUDE_ENV_FILE"
echo 'export DEBUG_LOG=true' >> "$CLAUDE_ENV_FILE"
echo 'export PATH="$PATH:./node_modules/.bin"' >> "$CLAUDE_ENV_FILE"
fi
exit 0
כדי ללכוד את כל שינויי הסביבה מפקודות ההכנה, השוו את המשתנים המיוצאים לפני ואחרי:
#!/bin/bash
ENV_BEFORE=$(export -p | sort)
# Run your setup commands that modify the environment
source ~/.nvm/nvm.sh
nvm use 20
if [ -n "$CLAUDE_ENV_FILE" ]; then
ENV_AFTER=$(export -p | sort)
comm -13 <(echo "$ENV_BEFORE") <(echo "$ENV_AFTER") >> "$CLAUDE_ENV_FILE"
fi
exit 0
כל פקודת Bash מריצה את תוכן הקובץ כקוד מעטפת לפני הפקודה עצמה, ולכן שורה שם יכולה להשתמש בכל דבר ש-Bash מעריך, כמו ההפניה ל-$PATH ב-export PATH="$PATH:./node_modules/.bin".
פקודות PowerShell מקבלות גם הן את המשתנים מ-CLAUDE_ENV_FILE, ב-Claude Code גרסה v2.1.296 או מאוחרת יותר, אבל PowerShell אף פעם לא מריץ את הקובץ. Claude Code קורא מתוכו את ההשמות ומעתיק אותן לסביבה של פקודת PowerShell במקום זאת. הוא עושה זאת רק כאשר כל שורה היא אחת מהבאות, על פני מה שכל הוק בסשן הזה כתב וכל סקריפט שהגדרתם אליו את CLAUDE_ENV_FILE לפני ההפעלה:
שורה ריקה או הערת #
השמה אחת בתחילת השורה, כתובה export NAME=value, declare -x NAME=value, או NAME=value, עם ערך ש-Bash היה משתמש בו בדיוק כפי שנכתב, המורכב מכל שילוב של החלקים האלה: טקסט בלי מרכאות שמשתמש רק באותיות, ספרות, והתווים _ @ % + = : , . / -, טקסט במרכאות בודדות, וטקסט במרכאות כפולות שבו כל $, backtick, או " בפנים מוברח עם לוכסן הפוך
אם שורה כלשהי היא מסוג אחר, כמו export PATH="$PATH:./node_modules/.bin" עם $PATH הלא מוברח שלו, פקודת source, או מחרוזות $'...' ש-direnv export bash מדפיס, פקודות PowerShell לא מקבלות אף אחד מהמשתנים, ו-claude --debug רושם Session environment is not all plain assignments. פקודות Bash עדיין מקבלות את כולם. ב-Windows, פקודות PowerShell גם לא מקבלות משתנה שהערך שלו מכיל / או \, כי Git Bash ו-Windows כותבים נתיבים אחרת. פקודת PowerShell בארגז חול לא מקבלת אף אחד מהמשתנים.
[!NOTE]
CLAUDE_ENV_FILE זמין להוקים של SessionStart, Setup, CwdChanged, ו-FileChanged. לאירועי הוק אחרים אין גישה למשתנה הזה, וגם לא להוק שרץ ב-PowerShell, בין אם דרך "shell": "powershell" או כברירת מחדל ב-Windows בלי Git Bash.
נורה רק כאשר מפעילים את Claude Code עם --init-only, או עם --init או --maintenance במצב לא אינטראקטיבי עם הדגל -p. הוא לא נורה בהפעלה רגילה. השתמשו בו להתקנת תלות חד פעמית או לניקוי מתוזמן שמפעילים במפורש מ-CI או מסקריפטים, בנפרד מהפעלת סשן רגילה. לאתחול לכל סשן, השתמשו ב-SessionStart במקום.
ערך ה-matcher תואם לדגל ה-CLI שהפעיל את ההוק:
Matcher
מתי הוא נורה
init
claude --init-only או claude -p --init
maintenance
claude -p --maintenance
כאשר מריצים claude --init-only, Claude Code מריץ הוקים של Setup והוקים של SessionStart עם ה-matcher startup, ואז יוצא בלי להתחיל שיחה.
כאשר מתחילים או ממשיכים שיחה עם -p, צריך גם לספק פרומפט, כארגומנט או מוזרם ב-stdin. אפשר לדלג על הפרומפט כאשר הוק SessionStart מספק initialUserMessage או כאשר ממשיכים סשן עם קריאת כלי דחויה.
בהצלחה, --init-only לא מדפיס כלום לטרמינל. כדי לאשר שההוקים רצו, התחילו עם claude --debug-file <path> --init-only, כשמחליפים את <path> במיקום קובץ לוג, ובדקו בלוג את רשומות ההוק של Setup ושל SessionStart.
מכיוון ש-Setup לא נורה בכל הפעלה, תוסף שזקוק לתלות מותקנת לא יכול להסתמך על Setup לבד. הדפוס המעשי הוא לבדוק את התלות בשימוש הראשון ולהתקין כשהיא חסרה, למשל הוק או skill שבודק את ${CLAUDE_PLUGIN_DATA}/node_modules ומריץ npm install אם הוא נעדר. ראו את ספריית הנתונים המתמידה לגבי איפה לאחסן תלויות מותקנות. אם מפיצים את התוסף דרך marketplace, ייתכן שלא תצטרכו את הדפוס הזה: Claude Code מתקין אוטומטית תלויות חבילות Node.js זכאיות כאשר הוא שומר את התוסף במטמון.
הוקים של Setup לא יכולים לחסום. הביצוע ממשיך בכל קוד יציאה. בכל קוד יציאה, Claude Code משליך את שדות פלט ה-JSON של הוק Setup, כמו systemMessage, continue, ו-hookSpecificOutput.additionalContext. עם -p, stdout, stderr, וקוד היציאה של הוק Setup מופיעים בפלט הריצה רק כאירועי hook_response כאשר מפעילים עם --output-format stream-json --verbose.
להוקים של Setup יש גישה ל-CLAUDE_ENV_FILE. אם ההוק כותב משתנים לקובץ הזה, הם נשמרים לפקודות Bash הבאות של הסשן, כמו ב-הוקים של SessionStart. רק הוקים מסוג type: "command" רצים ב-Setup. הוק מסוג type: "mcp_tool" על Setup תמיד מדולג, כמתואר תחת שדות הוק של כלי MCP.
נורה כאשר קובץ CLAUDE.md או .claude/rules/*.md נטען להקשר. האירוע הזה נורה בתחילת הסשן עבור קבצים שנטענים מיד, ושוב מאוחר יותר כאשר קבצים נטענים בעצלתיים, למשל כאשר Claude ניגש לתת ספרייה שמכילה CLAUDE.md מקונן או כאשר כללים מותנים עם frontmatter של paths: תואמים. ההוק לא תומך בחסימה או בבקרת החלטה. הוא רץ באופן אסינכרוני למטרות תצפית.
האירוע הזה לא נורה כאשר Claude קורא את AGENTS.md ישירות דרך ההגדרה הוראות הפרויקט. הוא כן נורה כאשר CLAUDE.md מייבא את AGENTS.md, עם load_reason שמוגדר ל-include כמו לכל קובץ מיובא אחר, וכאשר CLAUDE.md הוא symlink אליו, כטעינה רגילה של CLAUDE.md.
ה-matcher רץ מול load_reason. למשל, השתמשו ב-"matcher": "session_start" כדי להיירות רק עבור קבצים שנטענו בתחילת הסשן, או ב-"matcher": "path_glob_match|nested_traversal" כדי להיירות רק עבור טעינות עצלות.
בנוסף לשדות הקלט המשותפים, הוקים של InstructionsLoaded מקבלים את השדות האלה:
שדה
תיאור
file_path
נתיב מוחלט לקובץ ההוראות שנטען
memory_type
היקף הקובץ: "User", "Project", "Local", או "Managed"
load_reason
למה הקובץ נטען: "session_start", "nested_traversal", "path_glob_match", "include", או "compact". הערך "compact" נורה כאשר קובצי הוראות נטענים מחדש אחרי אירוע דחיסה
globs
תבניות glob של נתיבים מ-frontmatter של paths: בקובץ, אם יש. נוכח רק עבור טעינות path_glob_match
trigger_file_path
נתיב לקובץ שהגישה אליו הפעילה את הטעינה הזו, עבור טעינות עצלות
parent_file_path
נתיב לקובץ ההוראות ההורה שכלל את זה, עבור טעינות include
להוקים של InstructionsLoaded אין בקרת החלטה. הם לא יכולים לחסום או לשנות טעינת הוראות. Claude Code משליך את שדות פלט ה-JSON שלהם, כמו systemMessage ו-continue. השתמשו באירוע הזה לרישום ביקורת, מעקב תאימות, או תצפית.
להוקי UserPromptSubmit יש timeout ברירת מחדל של 30 שניות לסוגים command, http ו-mcp_tool, קצר יותר מברירת המחדל של 600 שניות לסוגים האלה ברוב האירועים האחרים. מכיוון שההוק הזה רץ לפני כל פרומפט וחוסם את עיבוד המודל עד שהוא מסתיים, הוק תקוע עוצר את הסשן. אם ההוק שלך צריך יותר זמן, הגדר את השדה timeout ברשומת ההוק.
מלבד הוק פקודה שאתה מריץ עם async: true, הוק UserPromptSubmit מסוג command, HTTP או כלי MCP שמגיע ל-timeout שלו מבוטל, והפלט שלו, כולל כל additionalContext, נזרק. הפרומפט עדיין מגיע ל-Claude בלי ההקשר הזה. כדי לחסום את הפרומפט במקום זה, הגדר onFailure: "block" על הוק command או HTTP. התמליל מציג הודעה שמציינת את ההוק, את ה-timeout שהופעל, ושהפלט נזרק.
הוק callback של Agent SDK על UserPromptSubmit שמגיע ל-timeout שלו חוסם את הפרומפט עם הודעה שמציינת את ההוק ואת ה-timeout, כי callback שם יכול לפעול כשער מדיניות שאסור שייכשל פתוח. הסשן ממשיך.
אם אתה לוחץ על Esc או קוטע את הסשן בזמן שהוקים עדיין בודקים פרומפט, הבדיקה נעצרת והפרומפט לא מגיע ל-Claude. טקסט שהקלדת בטרמינל חוזר לשדה קלט הפרומפט, והוקים בודקים אותו שוב כשאתה שולח אותו מחדש.
הוק יכול לחסום את הפרומפט באותו רגע שבו אתה קוטע. הפרומפט נשאר חסום: אתה רואה את הודעת החסימה של ההוק הזה, והטקסט לא חוזר לקלט.
בנוסף לשדות הקלט המשותפים, הוקי UserPromptSubmit מקבלים את השדה prompt שמכיל את הטקסט שנשלח. תוכן שהודבק וכווץ למציין מיקום [Pasted text #N] מגיע מורחב במקום. בסשנים שבהם Claude Code מסמן טקסט שהודבק עבור Claude, התוכן המורחב יושב בין שורה <pasted_content id="…"> לשורה </pasted_content id="…">, אז התחשב בשורות האלה אם ההוק שלך מנתח את הפרומפט.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"permission_mode": "default",
"hook_event_name": "UserPromptSubmit",
"prompt": "Write a function to calculate the factorial of a number"
}
כאשר הפרומפט הוא skill או פקודה מותאמת שהקלדת, כמו /deploy staging, ההוק מקבל את השורה כפי שהקלדת אותה ולא את תוכן ה-skill המורחב. אם ההוק חוסם את הפרומפט, הפקודה לא רצה, ולכן גם פקודות מעטפת שה-skill מזריק עם !`<command>` לא רצות. כדי להתאים לפי שם הפקודה או הארגומנטים במקום זה, השתמש ב-UserPromptExpansion.
JSON עם additionalContext: השתמש בפורמט ה-JSON למטה לשליטה רבה יותר. השדה additionalContext מתווסף כהקשר
אף אחד מהערוצים לא מייצר רשומת תמליל גלויה. stdout רגיל וערך additionalContext מוזרקים כל אחד כתזכורת מערכת שמתחילה בשם ההוק. Claude קורא את שניהם. כדי לאשר מסירה, בדוק את יומן הדיבוג.
כדי לחסום פרומפט, החזר אובייקט JSON עם decision שמוגדר ל-"block":
שדה
תיאור
decision
"block" עוצר את הפרומפט לפני שהוא מגיע ל-Claude. השמט כדי לאפשר לפרומפט להמשיך
reason
מוצג למשתמש כאשר decision הוא "block". לא מתווסף להקשר
פרומפט חסום אף פעם לא מגיע ל-Claude, אבל הטקסט שלו לא מוסר מכל מקום. כברירת מחדל הודעת החסימה שמוצגת למשתמש מסתיימת ב-Original prompt: ואחריו הטקסט שנשלח, ו-Claude Code כותב את ההודעה הזו לקובץ התמליל של הסשן בדיסק. כדי להשאיר את הטקסט מחוץ להודעה, הדפס JSON עם "suppressOriginalPrompt": true בתוך hookSpecificOutput. זה עובד בין אם ההוק חוסם עם decision: "block" ובין אם על ידי יציאה 2.
suppressOriginalPrompt משנה רק את הודעת החסימה. הטקסט שנשלח עדיין יכול להופיע בקבצים מקומיים כמו תמליל הסשן והיסטוריית הפרומפטים שלך, אז הוק חוסם אינו דרך לשמור סוד מחוץ לדיסק. כדי להגביל או להסיר את הקבצים האלה, ראה אחסון בטקסט גלוי ו-ניקוי נתונים מקומיים.
רץ כאשר פקודה שהמשתמש הקליד מתרחבת לפרומפט לפני שהיא מגיעה ל-Claude. השתמש בזה כדי לחסום פקודות מסוימות מהפעלה ישירה, להזריק הקשר ל-skill מסוים, או לרשום אילו פקודות משתמשים מפעילים. לדוגמה, הוק שמתאים ל-deploy יכול לחסום את /deploy אלא אם קיים קובץ אישור, או הוק שמתאים ל-skill של סקירה יכול לצרף את רשימת הבדיקה של הצוות כ-additionalContext.
האירוע הזה מכסה את הנתיב ש-PreToolUse לא מכסה: הוק PreToolUse שמתאים לכלי Skill מופעל רק כאשר Claude קורא לכלי, אבל הקלדת /skillname ישירות עוקפת את PreToolUse. UserPromptExpansion מופעל בנתיב הישיר הזה.
מתאים לפי command_name. השאר את ה-matcher ריק כדי להפעיל על כל פקודה מסוג פרומפט.
בנוסף לשדות הקלט המשותפים, הוקי UserPromptExpansion מקבלים את expansion_type, command_name, command_args, command_source, ואת מחרוזת ה-prompt המקורית. השדה expansion_type הוא slash_command עבור skill ופקודות מותאמות, או mcp_prompt עבור פרומפטים של שרת MCP.
רץ בזמן שהודעת assistant מוזרמת למסך. Claude Code מציג את ההודעה במנות: בכל פעם שאצווה של שורות שהושלמו מוכנה לעיבוד, ההוק רץ פעם אחת עם השורות האלה ו-Claude Code מציג במקומן את טקסט ההחלפה של ההוק. הודעה ארוכה מייצרת כמה קריאות. הודעה קצרה עשויה לייצר רק אחת.
השתמש ב-MessageDisplay כדי:
להסיר markdown לתצוגה מינימלית
לשנות את הטקסט שאפליקציית Agent SDK מציגה למשתמשים שלה
להסתיר מפתחות API או שמות מארחים פנימיים מתשובות של Claude
Claude Code מחזיק כל אצווה עד שההוק שלך חוזר, אז שמור על ההוק מהיר. אם ההוק נכשל או מגיע ל-timeout, Claude Code מציג את הטקסט המקורי. ה-timeout ברירת המחדל לאירוע הזה הוא 10 שניות. אם ההוק שלך צריך יותר זמן, הגדר את השדה timeout ברשומת ההוק.
MessageDisplay הוא לתצוגה בלבד: טקסט ההחלפה משנה רק את מה שמוצג על המסך. התמליל ומה ש-Claude רואה שומרים את הטקסט המקורי, כך ש-Claude אף פעם לא רואה את ההחלפה, ומצב verbose מציג את המקור. ההוק מקבל רק טקסט של הודעת assistant, כך שתוצאות כלים והטקסט שאתה מקליד מוצגים ללא שינוי.
MessageDisplay לא תומך ב-matchers ומופעל על כל הודעת assistant שמזרימה טקסט. הודעות בלי טקסט, כמו תשובות של קריאת כלי בלבד, לא מפעילות אותו.
בהרצות לא אינטראקטיביות, כולל שאילתות Agent SDK ו-claude -p, MessageDisplay רץ פעם אחת לכל הודעת assistant במקום פעם אחת לכל אצוות שורות. הקריאה היחידה מגיעה אחרי שההודעה הושלמה ונושאת את טקסט ההודעה המלא: index הוא 0, final הוא true, ו-delta מחזיק את כל ההודעה. הוק שאוסף את טקסט ה-delta לכל הודעה מקבל את אותו סך טקסט בשני המצבים.
בנוסף לשדות הקלט המשותפים, הוקי MessageDisplay מקבלים מזהים לתור ולהודעה, את מיקום הקריאה הזו בתוך ההודעה, ואת הטקסט החדש ב-delta. גבולות האצווה תלויים באופן שבו הטקסט מוזרם, אז השתמש ב-index וב-final כדי לעקוב אחרי ההתקדמות בהודעה במקום לצפות שהשורות יקובצו בצורה מסוימת.
שדה
תיאור
turn_id
UUID של התור הנוכחי
message_id
UUID של הודעת ה-assistant שמוצגת. יציב בכל אצווה של אותה הודעה. זה אינו מזהה ה-API msg_…, ולכן אי אפשר לקשר אותו למזהי הודעות בתמליל
index
אינדקס מבוסס אפס של האצווה הזו בתוך ההודעה
final
true באצווה האחרונה של ההודעה. לכל הודעה יש בדיוק אצווה סופית אחת
delta
השורות שהושלמו מאז האצווה הקודמת, כולל ירידות שורה מסיימות. תמיד שורות שלמות, מלבד האצווה הסופית שעשויה להסתיים באמצע שורה. בהרצות אינטראקטיביות, ה-delta של האצווה הסופית ריק כאשר ההודעה מסתיימת בירידת שורה, אז התייחס ל-final, ולא ל-delta לא ריק, כאות לסיום ההודעה. בהרצות Agent SDK ו-claude -p, הקריאה היחידה נושאת את כל ההודעה
בנוסף לשדות הפלט ב-JSON הזמינים לכל ההוקים, הוקי MessageDisplay יכולים להחזיר displayContent כדי להחליף את ה-delta על המסך:
שדה
תיאור
displayContent
טקסט שמוצג במקום ה-delta. השמט אותו כדי להציג את המקור
להוקי MessageDisplay אין בקרת החלטה. הם לא יכולים לחסום את ההודעה או לשנות את מה שנשמר בתמליל או נשלח ל-Claude. Claude Code פועל לפי displayContent מפלט ה-JSON שלהם וזורק את systemMessage ואת continue.
הדוגמה הזו מסירה עיצוב markdown מתשובות של Claude לתצוגת טקסט רגיל. הסקריפט קורא כל אצווה מ-stdin, מסיר סמני הדגשה וגרשיים הפוכים של קוד בתוך השורה מ-delta, ומחזיר את התוצאה כ-displayContent.
רץ אחרי ש-Claude יוצר פרמטרים של כלי ולפני עיבוד קריאת הכלי. מתאים לכל שם כלי מלבד EndConversation: כלים מובנים כמו Bash, PowerShell, Edit, Write, Read, Glob, Grep, Agent, Workflow, WebFetch, WebSearch, AskUserQuestion ו-ExitPlanMode, וכל שמות כלי MCP.
כדי להריץ הוק כאשר קובץ מסוים משתנה בדיסק, לא משנה מי כתב אותו, השתמש ב-FileChanged במקום להתאים כלי עריכת קבצים לפי שם. בניגוד ל-PreToolUse, Claude Code מריץ הוקי FileChanged אחרי השינוי, ואין להם בקרת החלטה, אז הם לא יכולים לחסום את הכתיבה.
[!WARNING]
PreToolUse רץ רק כאשר Claude קורא לכלי. כברירת מחדל, קבצים שאתה מפנה אליהם עם @ בפרומפט מתווספים בלי שום קריאת כלי. Claude Code מכניס את התוכן שלהם בזמן בניית הפרומפט, אז שום הוק PreToolUse לא מופעל עבורם, כולל הוקים שמתאימים ל-Read. PreToolUse גם לא מופעל עבור EndConversation.
אתה יכול לחסום נתיבים מסוימים מהפניות @, או לכבות את ההכנסה:
כיבוי ההכנסה: הגדר CLAUDE_CODE_DISABLE_FILE_MENTIONS=1 במעטפת, בהגדרות המשתמש, או בהגדרות מנוהלות. אז Claude מקבל את הנתיבים שצוינו עם הערה לקרוא אותם באמצעות כלי הקבצים שלו. אם הוא עושה זאת, הוקי PreToolUse המתאימים שלך רצים. המשתנה דורש Claude Code v2.1.299 או חדש יותר, ו-Claude Code מתעלם ממנו בהגדרות פרויקט והגדרות מקומיות.
השתמש ב-בקרת החלטה של PreToolUse כדי לאפשר, לדחות, לשאול, או לדחות לזמן מאוחר יותר את קריאת הכלי.
בנוסף לשדות הקלט המשותפים, הוקים של PreToolUse מקבלים את tool_name, tool_input ואת tool_use_id.
עבור כלי MCP, הקלט נושא גם את mcp_server, אובייקט עם name של השרת וsource שאומר מאיפה הגיעה הגדרת השרת. ערכי source כוללים את plugin, sdk והיקפי תצורה כגון user וproject. McpServerProvenance במדריך Agent SDK מפרט את כולם ואומר איך להתייחס לערך שלא מזהים. בססו החלטות אמון על source ולא על name או על קידומת שם הכלי mcp__<server>__. השדה mcp_server דורש Claude Code בגרסה v2.1.274 או חדשה יותר.
עבור כלי הקבצים Write, Edit וRead, tool_input.file_path תמיד מוחלט:
Claude Code מרחיב את ~ ונתיבים יחסיים לפני שההוקים רצים, כך שהוק שמתאים לפי נתיבים לא ניתן לעקיפה דרך ~ או איות יחסי של אותו נתיב
ב-Windows הנתיב מגיע עם מפרידי לוכסן הפוך, גם כשההוק רץ תחת Git Bash שבו $PWD נראה כמו /c/project
השוואה שנכתבה עם לוכסנים קדמיים, כגון בדיקת /src/, לעולם לא מתאימה לנתיב עם לוכסן הפוך, וקריאת הכלי ממשיכה כאילו להוק לא היה מה לחסום
נרמלו מפרידים לפני ההשוואה: FILE_PATH="${FILE_PATH//\\//}" ב-Bash, או file_path.replace("\\", "/") ב-Python, ואז התאימו מקטע נתיב כגון /src/ ולא עגינה עם ^, כי הנתיב מוחלט
פסק זמן אופציונלי באלפיות שנייה. ערכים מעל המקסימום מופחתים למקסימום ולא נדחים
run_in_background
boolean
false
האם להריץ את הפקודה ברקע
כשפקודת Bash משנה קבצים במאגר Git, Claude Code יכול לתעד מה השתנה. הוא מתעד את השינויים בכל מצב הרשאה כשההגדרה bashEditDiffEnabled מפעילה את התיעוד. הרשומה של ההגדרה אומרת אילו קבצים יכולים להגדיר אותה. אחרת הוא מתעד אותם רק במצב auto ובמצב bypassPermissions, ורק כש-Claude Code מכוון את Claude לערוך קבצים דרך Bash. הגדירו את bashEditDiffEnabled לfalse כדי לכבות את התיעוד. פקודות רקע ופקודות לקריאה בלבד לא נושאות diff.
הוק PostToolUse שלכם מקבל אז את הקבצים שהשתנו בtool_response.bashEditDiff. הרשימה מכסה מה השתנה תחת המאגר בזמן שהפקודה רצה. קבצים ש-Git מתעלם מהם וקבצים בתת מודולים לא מופיעים ברשימה. דורש Claude Code בגרסה v2.1.269 או חדשה יותר.
[!NOTE]
הרשימה היא best effort ובבטא ציבורית. Claude Code יכול לפספס שינוי, לכלול קובץ שתהליך אחר שינה באותו זמן, או לעצור במגבלות הגודל שלו. צורת השדה עשויה להשתנות. השתמשו ברשימה כדי למצוא מה לבדוק, לא כדי לאכוף מדיניות.
changedFiles וfiles מפרטים מה הפקודה שינתה. שאר השדות אומרים עד כמה הרשימה מלאה ועד כמה היא אמינה.
שדה
סוג
דוגמה
תיאור
changedFiles
array
["/path/to/src/app.ts"]
נתיבים מוחלטים של הקבצים שהפקודה שינתה, לכל היותר 200. נוכח בכל פעם שfiles מחזיק diff או שmoreFiles מעל אפס
אופציונלי: סוג החיפוש. "standard" מבקש חיפוש קל יותר ו"extended" את החיפוש המלא. חלק מההפעלות לא שולחות mode, וקריאה בלעדיו מריצה את החיפוש המלא. דורש Claude Code בגרסה v2.1.282 או חדשה יותר
כשקריאת Agent בחזית מסתיימת, הוק PostToolUse שלכם מקבל את תוצאת ה-subagent ואת טלמטריית הריצה בtool_response. קראו את השדות האלה כדי לבדוק את הריצה. עבור סיכומי טוקנים ועלות בין subagents, השתמשו במוני הטוקנים והעלות מסוננים לquery_source"subagent", כי totalTokens וusage מכסים רק את הבקשה הסופית:
בלוקי הטקסט הסופיים של ה-subagent, או, עבור subagent שהדוח שלו עובר דרך SubagentHandback, הערה קצרה על המסירה הזו במקומם
resolvedModel
string
"claude-sonnet-4-5"
המודל שה-subagent התחיל עליו, שעשוי להיות שונה מהמודל שהתבקש
modelsUsed
array
["claude-sonnet-4-5", "claude-haiku-4-5"]
מודלים ששימשו לפי הסדר, כשחזרות רצופות מכווצות. מוגדר רק כשהמודל הוחלף באמצע הריצה
totalTokens
number
12450
ספירת טוקנים מבקשת ה-API הסופית של ה-subagent: קלט, פלט וטוקני מטמון יחד. זה לא סך הכל על פני כל הריצה
totalDurationMs
number
48211
משך שעון הקיר של ריצת ה-subagent
totalToolUseCount
number
7
מספר קריאות הכלים שה-subagent ביצע
usage
object
{"input_tokens": 8320, ...}
פירוט טוקנים לפי סוג של בקשת ה-API הסופית: input_tokens, output_tokens, cache_creation_input_tokens, cache_read_input_tokens
ב-Claude Code בגרסה v2.1.271 או חדשה יותר, subagent שרץ עם הכלי SubagentHandback, ש-Claude Code מספק במצב auto, מעביר את הדוח שלו דרך הכלי הזה ולא מחזיר אותו כטקסט. שדה content של תוצאת completed שלו נושא אז הערה קצרה על המסירה הזו ולא את הדוח עצמו. כדי לקרוא את הדוח, התאימו הוק PreToolUse או PostToolUse על SubagentHandback וקראו את tool_input.message.
עבור subagents ברקע, הכלי חוזר כשהמשימה עוברת לרקע, כך שtool_response לא נושא שדות שימוש: הפעלה ברקע חוזרת מיד, ומשימה בחזית ש-Claude Code מעביר לרקע באמצע הריצה חוזרת במעבר הזה. יש לו status: "async_launched", agentId, description, prompt, outputFile וresolvedModel.
בתגובת completed, resolvedModel מציין את המודל שה-subagent התחיל עליו, שעשוי להיות שונה מערך model בtool_input, למשל כשavailableModels או דריסה אחרת חלים. בתגובת async_launched, resolvedModel מציין את המודל שבשימוש כשהסוכן עבר לרקע, כך שהחלפה שקרתה לפני המעבר לרקע משתקפת שם.
שאלות להצגה, כל אחת עם מחרוזת question, header קצר, מערך options ודגל multiSelect אופציונלי
answers
object
{"Which framework?": "React"}
אופציונלי. ממפה טקסט שאלה לתווית האפשרות שנבחרה. תשובות רב בחירה מחברות תוויות בפסיקים. Claude לא מגדיר את השדה הזה. ספקו אותו דרך updatedInput כדי לענות באופן תכנותי
מציג תוכנית ומבקש מהמשתמש לאשר אותה לפני ש-Claude יוצא ממצב plan. Claude כותב את התוכנית לקובץ בדיסק לפני שהוא קורא לכלי, כך שtool_input המילולי מהמודל בדרך כלל ריק. Claude Code מזריק את תוכן התוכנית ואת נתיב הקובץ לפני שהוא מעביר את הקלט להוקים.
שדה
סוג
דוגמה
תיאור
plan
string
"## Refactor auth\n1. Extract..."
תוכן התוכנית ב-Markdown. מוזרק מקובץ התוכנית בדיסק
planFilePath
string
"/Users/.../plans/refactor-auth.md"
נתיב לקובץ התוכנית. מוזרק
allowedPrompts
array
[{"tool": "Bash", "prompt": "run tests"}]
Deprecated. Claude Code מקבל את השדה אבל מתעלם ממנו. לפני v2.1.205 הוא נשא הרשאות מבוססות הנחיה ש-Claude ביקש כדי ליישם את התוכנית
בPostToolUse, tool_response הוא אובייקט עם שדות plan וfilePath שמחזיקים את התוכנית שאושרה, ועם דגלי סטטוס פנימיים. קראו את tool_response.plan עבור תוכן התוכנית ולא את הקובץ מחדש מהדיסק.
הוקי PreToolUse יכולים לקבוע אם קריאת כלי תמשיך. בניגוד להוקים אחרים שמשתמשים בשדה decision ברמה העליונה, PreToolUse מחזיר את ההחלטה שלו בתוך אובייקט hookSpecificOutput. זה נותן לו שליטה עשירה יותר: ארבע תוצאות (allow, deny, ask או defer) וגם היכולת לשנות את קלט הכלי לפני הביצוע.
עבור "ask", מוצג למשתמש בבקשת ההרשאה. כש-Claude Code דוחה את הקריאה בהרצה עם -p שבה אף אחד לא יכול לענות לבקשה הזו, Claude קורא את הסיבה בתוצאת הכלי במקום זאת. עבור "deny", מוצג ל-Claude. עבור "allow" ו-"defer", נכתב רק ליומן הניפוי
updatedInput
משנה את פרמטרי הקלט של הכלי לפני הביצוע. מחליף את כל אובייקט הקלט, לכן יש לכלול שדות שלא השתנו לצד השדות ששונו. Claude Code מעריך כללי הרשאה ואת הזכאות להעברה אוטומטית לרקע של פקודת Bash מול הקלט שההוק שלך מחזיר, לא מול הקלט ש-Claude שלח. שלבו עם "allow" לאישור אוטומטי, או עם "ask" כדי להציג את הקלט ששונה למשתמש. עבור "defer", מתעלמים ממנו. בלי permissionDecision, מצב אוטומטי יכול לדחות את הקריאה ששונתה
additionalContext
מחרוזת שנוספת להקשר של Claude לצד תוצאת הכלי. מתעלמים ממנה כש-permissionDecision הוא "defer". ראו הוספת הקשר ל-Claude
כמה הוקי PreToolUse מחזירים החלטות שונות, סדר העדיפות הוא deny > defer > ask > allow.
הוק שחוסם על ידי יציאה עם קוד 2 מנותב באותו אופן כמו "deny": Claude רואה את הודעת stderr כסיבת הדחייה.
כשהוק מחזיר "ask", בקשת ההרשאה שמוצגת למשתמש כוללת תווית שמזהה מאיפה ההוק הגיע: [settings] להוק מכל קובץ הגדרות או מ-frontmatter של סוכן, [plugin:<name>] להוק של תוסף, או [skill] להוק מ-frontmatter של skill. זה עוזר למשתמשים להבין איזה מקור הגדרה מבקש אישור.
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "allow",
"permissionDecisionReason": "My reason here",
"updatedInput": {
"field_to_modify": "new value"
},
"additionalContext": "Current environment: production. Proceed with caution."
}
}
[!NOTE]
PreToolUse השתמש בעבר בשדות decision ו-reason ברמה העליונה, אבל הם deprecated עבור האירוע הזה. השתמשו ב-hookSpecificOutput.permissionDecision וב-hookSpecificOutput.permissionDecisionReason במקום. הערכים שיצאו משימוש "approve" ו-"block" ממופים ל-"allow" ול-"deny" בהתאמה. אירועים אחרים כמו PostToolUse ו-Stop ממשיכים להשתמש ב-decision וב-reason ברמה העליונה כפורמט הנוכחי שלהם.
כשההוק שלך מחזיר updatedInput בלי permissionDecision במצב אוטומטי, Claude Code יכול לדחות את הקריאה ששונתה. השרת בדק את הקלט ש-Claude כתב, לא את הקלט שההוק שלך החזיר. בסשנים אינטראקטיביים בטרמינל ובסשנים של VS Code בחיבור ישיר ל-API של Anthropic, הדחייה כוללת את הטקסט הזה:
a hook changed this call's input after auto mode reviewed it
אחרי דחייה עם הטקסט הזה, Claude יכול להוציא את הקריאה ששונתה שוב כדי שהשרת יבדוק אותה. אם Claude חוזר על הקלט ששונה בדיוק בתגובה הבאה שלו, ההוק שלך עדיין רץ:
הוא יכול לדחות את הקריאה או לשלוח אותה לבקשת ההרשאה
כל updatedInput שהוא מחזיר נזרק, כך שמה שרץ הוא מה שהשרת בדק
בסשנים שמציגים את הטקסט הזה, הוק command בהגדרות או בקובץ ההוקים של תוסף יכול לשנות קריאות Bash, PowerShell, Monitor, Edit, Write ו-NotebookEdit בלי הדחייה הזו. הדחייה עדיין יכולה להופיע, למשל כשהוק כלשהו שינה קריאה קודמת באותה תגובה של Claude, או כשפקודת Bash מבקשת לרוץ מחוץ לארגז החול.
במצב אוטומטי, "ask" של הוק PreToolUse בדרך כלל שולח את קריאת הכלי לבקשת ההרשאה, והמסווג לא מחליט אותה. חלק מהקריאות הולכות במסלול אחר:
קריאות שגם הבדיקות של Claude Code עצמו מסמנות: אלה כוללות כתיבה לנתיבים מוגנים ופקודות שמבקשות לרוץ מחוץ לארגז החול. המסווג יכול לדחות אחת מהקריאות האלה לפני שמופיעה בקשה כלשהי. אם הוא מאשר, הקריאה בדרך כלל עדיין הולכת לבקשה.
קריאות SubagentHandback: הכלי הזה מוסר את הדוח של תת-סוכן. לא מופיעה בקשה עבורו, והקריאה רצה גם אם המסווג מתנגד.
כדי לעצור קריאת SubagentHandback, החזירו "deny". Claude Code אז אומר לתת-הסוכן, עד שלוש פעמים, שהדוח שלו לא נמסר ושיקרא לכלי שוב. אם ההוק שלך ממשיך לדחות, תת-הסוכן מסתיים בלי למסור דוח דרך הכלי הזה, והשיחה שממתינה לו מקבלת הערה שאומרת זאת.
AskUserQuestion ו-ExitPlanMode דורשים אינטראקציה עם המשתמש. במצב לא אינטראקטיבי עם הדגל -p, Claude Code מציע אותם רק כשיש להרצה מארח הרשאות שיקבל את הבקשה, כמו callback canUseTool של Agent SDK.
הוק PreToolUse עומד בדרישה הזו כשהוא עושה את הדברים הבאים:
קורא את קלט הכלי מ-stdin
אוסף את התשובה דרך ממשק המשתמש שלך
מחזיר permissionDecision: "allow" יחד עם updatedInput שמחזיק את התשובה, כדי שהכלי ירוץ בלי בקשה
החזרת "allow" לבד אינה מספיקה לכלים האלה.
עבור AskUserQuestion, החזירו את מערך questions המקורי והוסיפו אובייקט answers שממפה את הטקסט של כל שאלה לתשובה שנבחרה. הפלט הזה עונה על שאלה אחת עם React:
כלי MCP שהשרת שלו מסמן אותו עם _meta["anthropic/requiresUserInteraction"] מחמיר יותר: הוק לא יכול לדלג על בקשת האישור שלו עם "allow", עם updatedInput או בלעדיו, כי Claude Code לא יכול לאשר שההוק אסף את האינטראקציה שהכלי צריך.
"defer" מיועד לאינטגרציות שמריצות claude -p כתהליך בן וקוראות את פלט ה-JSON שלו, כמו אפליקציית Agent SDK או ממשק מותאם שנבנה מעל Claude Code. זה מאפשר לתהליך הקורא להשהות את Claude בקריאת כלי, לאסוף קלט דרך הממשק שלו, ולחדש מהמקום שבו הוא עצר. Claude Code מכבד את הערך הזה רק במצב לא אינטראקטיבי עם הדגל -p. בסשנים אינטראקטיביים הוא רושם אזהרה ומתעלם מתוצאת ההוק.
הכלי AskUserQuestion הוא המקרה הטיפוסי: Claude רוצה לשאול את המשתמש משהו, אבל אין טרמינל לענות בו. הרצת -p מציעה את AskUserQuestion רק כשיש לה מארח הרשאות, כמו כלי MCP שמעבירים עם --permission-prompt-tool, לכן התחילו את ההרצה עם אחד כזה. הסבב עובד כך:
Claude קורא ל-AskUserQuestion. הוק PreToolUse מופעל.
ההוק מחזיר permissionDecision: "defer". הכלי לא מבוצע. התור מסתיים עם תוצאה שנושאת stop_reason: "tool_deferred", וקריאת הכלי הממתינה נשארת בתמליל.
התהליך הקורא קורא את deferred_tool_use מתוצאת ה-SDK, מציג את השאלה בממשק שלו, ומחכה לתשובה.
התהליך הקורא מריץ claude -p --resume <session-id> עם אותו מארח הרשאות. אותה קריאת כלי מפעילה שוב את PreToolUse.
אין timeout ואין מגבלת ניסיונות חוזרים. הסשן נשאר על הדיסק עד שמחדשים אותו, בכפוף לסריקת השימור של cleanupPeriodDays, שמוחקת קבצי סשן אחרי 30 יום כברירת מחדל, לפי כללי סריקת השימור.
אם הכלי שנדחה כבר לא זמין כשמחדשים, לתוצאה הראשונה של החידוש יש stop_reason: "tool_deferred_unavailable" ו-is_error: true, וההוק לא מופעל. זה קורה כששרת MCP שסיפק את הכלי לא מחובר לסשן המחודש. מטען deferred_tool_use עדיין כלול כדי שאפשר יהיה לזהות איזה כלי נעלם.
אם לא שלחתם פרומפט, עם החידוש או אחריו, הקריאה עדיין ממתינה. חדשו שוב כשהכלי זמין והיא רצה ראשונה.
אם שלחתם פרומפט, עם החידוש או אחריו, Claude Code עונה עליו בלי תוצאת הכלי וזורק את הקריאה שנדחתה. שלחו פרומפט חדש ברגע שהכלי זמין אם עדיין צריך לקרוא לו.
אם התשובה שמחכים לה לא מוכנה כשמחדשים בלי פרומפט, ההוק יכול להחזיר "defer" שוב. אם שלחתם פרומפט וההוק דוחה שוב, Claude Code מתייחס לפרומפט באותו אופן: הוא עונה בלי תוצאת הכלי וזורק את הקריאה. חדשו בלי פרומפט עד שההוק מחזיר "allow" או "deny", וכך התהליך הקורא שובר את הלולאה.
"defer" עובד רק כש-Claude מבצע קריאת כלי אחת בתור. אם Claude מבצע כמה קריאות כלי בבת אחת, מתעלמים מ-"defer" עם אזהרה והכלי ממשיך בזרימת ההרשאה הרגילה. האילוץ קיים כי חידוש יכול להריץ מחדש רק כלי אחד: אין דרך לדחות קריאה אחת מאצווה בלי להשאיר את האחרות לא פתורות.
[!NOTE]
כדי לחדש סשן שנדחה במצב תוכנית, העבירו --permission-prompt-tool יחד עם --resume כדי ש-Claude Code יוכל להציג את התוכנית לאישור. לשאר התנאים, ראו חידוש במצב תוכנית עם -p. דורש Claude Code v2.1.246 או חדש יותר.
כשמחדשים עם -p, Claude Code לא משחזר שום מצב הרשאה שמור אחר. הוא מתחיל את ההרצה במצב ההרשאה שבו הרצת claude -p חדשה הייתה מתחילה, לכן העבירו שוב --permission-mode או --dangerously-skip-permissions אם הסשן שנדחה השתמש באחד מהם. כשמחדשים עם claude --resume <session-id> בלי -p, Claude Code משחזר את מצב ההרשאה השמור, עם החריגים שמפורטים במצב הרשאה בחידוש.
רץ כאשר Claude Code עומד לבקש ממך הרשאה להשתמש בכלי. בסשנים שאינם יכולים להציג הנחיה, כגון subagents ברקע במצב לא אינטראקטיבי, Claude Code עדיין מריץ את ה-hooks האלה, ואם אף hook לא מחזיר החלטה, הוא דוחה את קריאת הכלי. עבור קריאה שמגיעה ל---permission-prompt-tool או ל-callback canUseTool של Agent SDK, ה-hooks רצים לצד ה-host שלך, וההחלטה שמתקבלת ראשונה היא זו שחלה.
השתמש בבקרת החלטה של PermissionRequest כדי לאפשר או לדחות בשם המשתמש.
השתמש באירוע הזה כאשר אתה צריך אות ברגע ש-Claude מבקש הרשאה להשתמש בכלי. Claude Code מריץ hook של Notification עם הסוג permission_prompt רק אחרי שההנחיה המתינה כשש שניות.
Claude Code לא מריץ hooks של PermissionRequest עבור בקשת רשת של פקודה ב-sandbox. כדי לקבל אות עבור ההנחיה הזו, השתמש בסוג ההתראה permission_prompt.
ההתאמה היא לפי שם הכלי, אותם ערכים כמו ב-PreToolUse.
hooks של PermissionRequest מקבלים את השדות tool_name ו-tool_input כמו hooks של PreToolUse, אבל בלי tool_use_id. עבור כלי MCP, הם מקבלים גם את האובייקט mcp_server. מערך אופציונלי permission_suggestions מכיל את עדכוני ההרשאה ש-Claude Code מציע עבור הבקשה הזו, כגון הוספת כלל allow או שינוי מצב ההרשאה.
המערך permission_suggestions אינו רשימה מדויקת של האפשרויות שאתה רואה, כי כל דיאלוג הרשאה בונה את האפשרויות שלו. חלק מהדיאלוגים, כגון זה של עריכות קבצים, לא קוראים את המערך כלל וגוזרים את האפשרויות שלהם מהבקשה עצמה. דיאלוג שכן קורא אותו עדיין יכול להסתיר אפשרות שההצעה שלה נשארת במערך, לדוגמה כאשר allowManagedPermissionRulesOnly מסתיר אפשרויות שמירת כללים. הוא יכול גם להציע אפשרויות שאין להן רשומת הצעה, כגון כן, ועבור למצב auto, שמשנה את מצב ההרשאה ישירות ולא דרך עדכון הרשאה.
hooks של PreToolUse רצים לפני כל קריאת כלי, בין אם היא צריכה הרשאה ובין אם לא. hooks של PermissionRequest רצים רק כאשר Claude Code עומד לבקש ממך הרשאה, או כאשר הוא היה דוחה אוטומטית קריאה שאינה יכולה להציג הנחיה. אף אחד משני האירועים לא מופעל עבור EndConversation.
hooks של PermissionRequest יכולים לאפשר או לדחות בקשות הרשאה. בנוסף לשדות פלט JSON הזמינים לכל ה-hooks, סקריפט ה-hook שלך יכול להחזיר אובייקט decision עם השדות הספציפיים לאירוע האלה:
שדה
תיאור
behavior
"allow" מעניק את ההרשאה, "deny" דוחה אותה. כללי deny ו-ask עדיין מוערכים, כך ש-hook שמחזיר "allow" לא עוקף כלל deny תואם
updatedInput
עבור "allow" בלבד: משנה את פרמטרי הקלט של הכלי לפני הביצוע. מחליף את אובייקט הקלט כולו, לכן כלול שדות שלא השתנו לצד אלה ששונו. הקלט ששונה מוערך מחדש מול כללי deny ו-ask
updatedPermissions
עבור "allow" בלבד: מערך של רשומות עדכון הרשאה להחלה, כגון הוספת כלל allow או שינוי מצב ההרשאה של הסשן
message
עבור "deny" בלבד: אומר ל-Claude מדוע ההרשאה נדחתה
interrupt
עבור "deny" בלבד: אם true, עוצר את Claude
hook שיוצא עם קוד 2 בלי אובייקט decision משאיר את זרימת ההרשאה ללא שינוי, וה-stderr שלו נזרק. כדי להעניק או לדחות את הבקשה, החזר את אובייקט decision.
שדה הפלט updatedPermissions ושדה הקלט permission_suggestions שניהם משתמשים באותו מערך של אובייקטי רשומה. לכל רשומה יש type שקובע את שאר השדות שלה, ו-destination ששולט לאן השינוי נכתב.
type
שדות
השפעה
addRules
rules, behavior, destination
מוסיף כללי הרשאה. rules הוא מערך של אובייקטים {toolName, ruleContent?}. השמט את ruleContent כדי להתאים לכלי כולו. behavior הוא "allow", "deny", או "ask"
replaceRules
rules, behavior, destination
מחליף את כל הכללים של ה-behavior הנתון ב-destination ב-rules שסופקו
removeRules
rules, behavior, destination
מסיר כללים תואמים של ה-behavior הנתון
setMode
mode, destination
משנה את מצב ההרשאה. מצבים תקפים הם default, auto, acceptEdits, dontAsk, bypassPermissions, plan, ו-manual ככינוי ל-default
addDirectories
directories, destination
מוסיף ספריות עבודה. directories הוא מערך של מחרוזות נתיב
removeDirectories
directories, destination
מסיר ספריות עבודה
[!NOTE]
setMode עם bypassPermissions נכנס לתוקף רק אם הפעלת את הסשן כאשר מצב bypass כבר זמין: --dangerously-skip-permissions, --permission-mode bypassPermissions, --allow-dangerously-skip-permissions, או permissions.defaultMode: "bypassPermissions" בהגדרות משתמש, --settings, או הגדרות מנוהלות. אחרת העדכון הוא no-op. העדכון הוא גם no-op כאשר permissions.disableBypassPermissionsMode משבית את המצב, או כאשר הסשן מתחיל במצב מוגבל.
bypassPermissions לעולם לא נשמר כ-defaultMode ללא קשר ל-destination.
שדה destination בכל רשומה קובע אם השינוי נשאר בזיכרון או נשמר לקובץ הגדרות.
destination
נכתב אל
session
בזיכרון בלבד, נזרק כאשר הסשן מסתיים
localSettings
.claude/settings.local.json
projectSettings
.claude/settings.json
userSettings
~/.claude/settings.json
hook יכול להדהד אחת מ-permission_suggestions שקיבל כפלט updatedPermissions שלו.
ההתאמה היא לפי שם הכלי, אותם ערכים כמו ב-PreToolUse.
התאם באופן רחב יותר כאשר שם הכלי אינו המסנן הנכון:
כדי להריץ hook אחרי שכל כלי מסתיים בהצלחה, השמט את matcher או הגדר אותו ל-"*" . ה-hook שלך יכול אז לגלות בעצמו מה השתנה, לדוגמה על ידי הרצת git status --porcelain, שגם מציג קבצים לא במעקב ש-git diff מפספס. עבור קריאות כלי שנכשלות, הוסף את אותו hook תחת PostToolUseFailure.
כדי להריץ hook כאשר קובץ מסוים משתנה בדיסק, לא משנה מי כתב אותו, השתמש ב-FileChanged. Claude Code לא מריץ hook של PostToolUse שתואם ל-Edit|Write כאשר פקודת Bash או תהליך מחוץ ל-Claude Code כותב מחדש את אותו קובץ.
hooks של PostToolUse מופעלים אחרי שכלי כבר רץ בהצלחה. הקלט כולל גם את tool_input, הארגומנטים שנשלחו לכלי, וגם את tool_response, התוצאה שהוא החזיר. הסכמה המדויקת של שניהם תלויה בכלי. נתיבי tool_input של כלי קבצים מגיעים באותו פורמט כמו ב-PreToolUse: תמיד מוחלטים, עם המפרידים המקומיים של הפלטפורמה, כך ש-backslashes ב-Windows. עבור כלי MCP, הקלט נושא גם את האובייקט mcp_server.
hooks של PostToolUse יכולים לספק משוב ל-Claude אחרי ביצוע הכלי. בנוסף לשדות פלט JSON הזמינים לכל ה-hooks, סקריפט ה-hook שלך יכול להחזיר את השדות הספציפיים לאירוע האלה:
שדה
תיאור
decision
"block" מוסיף את reason ליד תוצאת הכלי. Claude עדיין רואה את הפלט המקורי. כדי להחליף אותו, השתמש ב-updatedToolOutput
updatedToolOutput משנה רק את מה ש-Claude רואה. הכלי כבר רץ עד שה-hook מופעל, כך שכל קבצים שנכתבו, פקודות שבוצעו, או בקשות רשת שנשלחו כבר נכנסו לתוקף. טלמטריה כגון tool spans של OpenTelemetry ואירועי analytics גם לוכדת את הפלט המקורי לפני שה-hook רץ. כדי למנוע או לשנות קריאת כלי לפני שהיא רצה, השתמש ב-hook של PreToolUse.
ערך ההחלפה חייב להתאים לצורת הפלט של הכלי. כלים מובנים מחזירים אובייקטים מובנים ולא מחרוזות פשוטות. לדוגמה, Bash מחזיר אובייקט עם השדות stdout, stderr, interrupted, ו-isImage. עבור כלים מובנים, ערך שלא תואם לסכמת הפלט של הכלי מתעלמים ממנו והפלט המקורי משמש. פלט של כלי MCP מועבר בלי אימות סכמה. הסרת פרטי שגיאה ש-Claude צריך יכולה לגרום לו להמשיך על סמך הנחה שגויה.
החזר classifierContext כדי לשלוח הערה קצרה על התוצאה של קריאת הכלי למסווג של מצב auto ולא ל-Claude. המסווג לעולם לא מקבל את תוצאות הכלים עצמן, כך שהשדה הזה הוא הדרך הנתמכת לספר לו משהו על מה שקריאה החזירה לפני שהוא סוקר פעולות מאוחרות יותר. השדה דורש Claude Code v2.1.236 או מאוחר יותר.
הדוגמה למטה אומרת למסווג מאיפה הגיע הפלט של שאילתה:
{
"hookSpecificOutput": {
"hookEventName": "PostToolUse",
"classifierContext": "This query ran against the staging database, not production."
}
}
כמה משקל המסווג נותן להערה תלוי במקום שבו הגדרת את ה-hook:
Hooks שהוגדרו ב-Claude Code: עבור hooks מקובצי הגדרות, plugins, skills, ו-frontmatter של agent, המסווג מתייחס להערה כהקשר לא מאומת שסופק על ידי האפליקציה. ההערה לעולם לא מבססת כוונת משתמש, ואם היא טוענת שאישרת או ביקשת משהו, המסווג בודק את הטענה הזו מול ההודעות שלך בשיחה
Callbacks של Agent SDK בתוך התהליך: כאשר אפליקציה שמטמיעה את Claude Code רושמת את ה-hook כ-callback של TypeScript SDK ומחזירה את ההערה במהלך הסשן החי, המסווג עשוי לשקול אמירת משתמש שמועברת בהערה ככוונת משתמש. אמירה כזו יכולה לספק דרישת הסכמה שהמסווג היה מקבל מהודעה שאתה שולח, אבל היא לעולם לא מסירה חסימה שההודעה שלך עצמה לא הייתה יכולה להסיר. אחרי שסשן מתחדש, Claude Code מתייחס להערות ששוחזרו כהקשר לא מאומת. כאשר hooks משתי הקבוצות מוסיפים הערה לאותה קריאה, המסווג מתייחס להערה המשולבת כלא מאומתת
Claude Code מחיל את המגבלות האלה בעת מסירת ההערה:
אורך: Claude Code מגביל את ההערות עבור קריאת כלי אחת ל-2,000 תווים וחותך את השאר. התקרה משותפת לכל hook שמגיב לקריאה הזו
תגובות סינכרוניות בלבד: Claude Code מתעלם מהשדה בתגובה של hook שרץ ברקע, כי התגובה הזו מגיעה אחרי ש-Claude Code רושם את תוצאת הכלי
קריאות שהמסווג לא רושם: התמליל של המסווג משמיט חיפושים לקריאה בלבד כגון קריאות קבצים וחיפושים. Claude Code זורק הערה שמצורפת לאחת מהקריאות האלה
אינטראקציה עם שכתובים: כאשר ההערה מתארת פלט שאתה מחליף באמצעות updatedToolOutput, החזר את שני השדות באותה תגובת hook. Claude Code משמיט את ההערה אם השכתוב הזה נדחה או אם שכתוב של hook אחר מחליף אותו. Claude Code מוסר הערה שאתה מחזיר בלי שכתוב גם כאשר hook אחר משכתב את הפלט
[!WARNING]
המסווג קורא תוכן שאתה שם ב-classifierContext כמידע מהאפליקציה שמארחת את הסשן, לכן אל תעתיק לתוכו פלט כלי לא מהימן או טקסט של צד שלישי. הגבל את ההערה לטענה קצרה על הקריאה הזו, כגון עובדה על המקור שלה או אמירת משתמש לגביה. אל תשתמש בשדה כדי למסור הודעות לא קשורות או זרם של אירועים.
רץ כאשר כלי שהתחיל לבצע נכשל: הכלי זרק שגיאה, או שכלי MCP החזיר תוצאת שגיאה. השתמשו בזה כדי לרשום כשלים, לשלוח התראות, או לספק משוב מתקן ל-Claude.
מתאים לפי שם הכלי, אותם ערכים כמו ב-PreToolUse.
[!NOTE]
האירוע הזה לא נורה עבור קריאות כלים שנדחו לפני הביצוע: שם כלי לא ידוע, קלט שנכשל בולידציית סכמה או בולידציה ייחודית לכלי, או דחיית הרשאה. דחיות ולידציה מוחזרות כתוצאות tool_use_error ומתרחשות לפני שה-hooks רצים, ולכן הן לא מפעילות לא את PreToolUse ולא את PostToolUseFailure. דחיות הרשאה מפעילות את PreToolUse אבל לא את האירוע הזה. ראו PermissionDenied.
hooks של PostToolUseFailure מקבלים את אותם שדות tool_name ו-tool_input כמו PostToolUse, יחד עם מידע על השגיאה כשדות ברמה העליונה. עבור כלי MCP, הם מקבלים גם את האובייקט mcp_server. לדוגמה, פקודת npm test שנכשלה עשויה לספק:
בוליאני אופציונלי. True כאשר הכשל הגיע ל-Claude Code כביטול ולא כשגיאה שהכלי דיווח. ביטול של כלי שרץ לא מפעיל את ה-hook הזה. תוצאת הכלי נושאת במקום זאת את הודעת ההפרעה
duration_ms
אופציונלי. זמן ביצוע הכלי באלפיות שנייה. לא כולל זמן שהושקע בהנחיות הרשאה וב-hooks של PreToolUse
מחרוזת error היא בדרך כלל אותו טקסט ש-Claude מקבל כתוצאת הכלי שנכשל. הפורמט שלה משתנה לפי כלי ולפי כשל. בסיסו את ה-hook על tool_name, על is_interrupt ועל שורת הפתיחה Exit code N. התייחסו לשאר המחרוזת כטקסט תצוגה, לא כפורמט יציב.
עבור Bash ו-PowerShell, פקודה שרצה ויצאה מייצרת שורה ראשונה Exit code N, ואז כל פלט שהפקודה ייצרה כבלוק אחד שבו stdout ו-stderr משולבים
מטען עשוי לשאת גם הודעת כשל חשופה בלי שורת קוד יציאה, כאשר Claude Code לא הצליח להפעיל את תהליך המעטפת עצמו
Claude Code חותך באמצע מחרוזות ארוכות סביב סמן ... [N characters truncated] ..., ויכול להוסיף שורות משלו, כמו Command timed out after 2m 0s
hooks של PostToolUseFailure יכולים לספק הקשר ל-Claude אחרי כשל של כלי. בנוסף לשדות פלט JSON הזמינים לכל ה-hooks, סקריפט ה-hook יכול להחזיר את השדות הייחודיים לאירוע האלה:
רץ פעם אחת אחרי שכל קריאת כלי באצווה נפתרה, לפני ש-Claude Code שולח את הבקשה הבאה למודל. PostToolUse נורה פעם אחת לכל כלי, וזה אומר שהוא נורה במקביל כאשר Claude מבצע קריאות כלים מקבילות. PostToolBatch נורה בדיוק פעם אחת עם האצווה המלאה, ולכן זה המקום הנכון להזריק הקשר שתלוי בקבוצת הכלים שרצו ולא בכלי יחיד. אין matcher לאירוע הזה.
tool_response מכיל את אותו תוכן שהמודל מקבל בבלוק tool_result המתאים. הערך הוא מחרוזת סריאלית או מערך בלוקי תוכן, בדיוק כפי שהכלי פלט אותו. עבור Read, זה אומר טקסט עם קידומת מספר שורה ולא תוכן קובץ גולמי. תגובות יכולות להיות גדולות, ולכן נתחו רק את השדות שאתם צריכים.
[!NOTE]
צורת tool_response שונה מזו של PostToolUse. PostToolUse מעביר את אובייקט ה-Output המובנה של הכלי, כמו {filePath: "...", type: "create"} עבור Write. PostToolBatch מעביר את תוכן tool_result הסריאלי שהמודל רואה.
hooks של PostToolBatch יכולים להזריק הקשר ל-Claude. בנוסף לשדות פלט JSON הזמינים לכל ה-hooks, סקריפט ה-hook יכול להחזיר את השדות הייחודיים לאירוע האלה:
שדה
תיאור
additionalContext
מחרוזת הקשר שמוזרקת פעם אחת לפני קריאת המודל הבאה. ראו הוספת הקשר ל-Claude לפרטי המסירה, מה לשים בה, ואיך הפעלות שהתחדשו מטפלות בערכים קודמים
{
"hookSpecificOutput": {
"hookEventName": "PostToolBatch",
"additionalContext": "These files are part of the ledger module. Run pytest before marking the task complete."
}
}
החזרת decision: "block" או continue: false עוצרת את לולאת הסוכן לפני קריאת המודל הבאה. הודעת החסימה מגיעה מ-reason או מ-stopReason ב-JSON, או מ-stderr ביציאה 2. אתם רואים אותה כאזהרה בתמליל, והיא נשארת בשיחה, כך ש-Claude רואה אותה כשהשיחה ממשיכה.
רץ כאשר מצב אוטומטי דוחה קריאת כלי, כולל כאשר הוא דוחה בלי פסק דין של מסווג כי בדיקת בטיחות נפרדת ממצב אוטומטי סירבה לבקשה של המסווג עצמו או שהתגובה שלו לא נותחה. ה-hook הזה נורה רק במצב אוטומטי: הוא לא רץ כאשר אתם דוחים ידנית תיבת הרשאה, כאשר hook של PreToolUse חוסם קריאה, או כאשר כלל deny תואם. השתמשו בו כדי לרשום דחיות, להתאים תצורה, או לומר למודל שהוא רשאי לנסות שוב את קריאת הכלי.
בנוסף לשדות הקלט המשותפים, hooks של PermissionDenied מקבלים את tool_name, את tool_input, את tool_use_id ואת reason. עבור כלי MCP, הם מקבלים גם את האובייקט mcp_server.
סיבת הדחייה. עבור פסק דין של מסווג, ברוב ההפעלות הוא מציין את הכלל שתאם בסוגריים מרובעים, כמו [Data Exfiltration]. ראו סקירת דחיות לצורות האחרות. עבור דחייה בלי פסק דין, הוא מתחיל ב-Auto mode could not evaluate this action and is blocking it for safety. עבור דחייה כי מודל המסווג לא היה זמין, זה הטקסט הקבוע Classifier unavailable
כאשר retry הוא true, Claude Code מוסיף הודעה לשיחה שאומרת למודל שהוא רשאי לנסות שוב את קריאת הכלי. Claude Code לא מבטל את הדחייה בעצמו. אם ה-hook לא מחזיר JSON, או מחזיר retry: false, הדחייה נשארת והמודל מקבל את הודעת הדחייה המקורית.
Claude Code מתעלם מ-retry: true כאשר המסווג הפיק אין פסק דין על הפעולה: התגובה שלו לא נותחה, או שבדיקת בטיחות נפרדת ממצב אוטומטי סירבה לבקשה של המסווג עצמו. עבור הדחיות האלה, Claude Code כבר אומר למודל בהודעת הדחייה אם לנסות שוב מאוחר יותר או להמשיך הלאה.
רץ כאשר Claude Code שולח התראות. מתאים לפי סוג ההתראה. השמיטו את ה-matcher כדי להריץ hooks לכל סוגי ההתראות.
אתם מקבלים את אירועי ה-hook האלה גם כשהתראות שולחן העבודה כבויות: ההגדרה preferredNotifChannel, כולל notifications_disabled, משנה רק את אופן ההתראה, לא את השאלה אם ה-hook רץ.
Matcher
מתי הוא נורה
permission_prompt
Claude צריך שתאשרו שימוש בכלי או בקשת רשת של פקודה בארגז חול, וההנחיה המתינה כשש שניות
idle_prompt
Claude סיים להגיב לפני כ-60 שניות ולא הקלדתם מאז
auth_success
האימות מסתיים
elicitation_dialog
שרת MCP פותח טופס elicitation ולא הקלדתם כשש שניות
elicitation_url_dialog
שרת MCP מבקש שתפתחו כתובת URL בדפדפן ולא הקלדתם כשש שניות
הפעלת רקע מסתיימת או נכשלת. נורה רק בזמן ש-תצוגת סוכן פתוחה בטרמינל
quota_auto_resume_fired
Claude Code ממשיך את המשימה אחרי שמגבלת שימוש של claude.ai עצרה אותה: באיפוס, או מוקדם יותר כאשר משהו שאתם עושים ב-Claude Code במהלך ההמתנה, כמו הוספת קרדיטי שימוש, שדרוג התוכנית, או החלפת מודלים, מחזיר את השימוש לזמין, עם חריגת הגדרת המודל
quota_auto_resume_stale
איפוס של מגבלת שימוש ב-claude.ai התרחש בזמן שהמחשב ישן יותר מכ-30 דקות. Claude Code ממתין שתלחצו על Enter במקום להמשיך. אחרי שינה קצרה יותר הוא ממשיך ומפעיל את quota_auto_resume_fired במקום זאת
quota_auto_resume_disabled
Claude Code מסיים את ההמתנה למגבלת שימוש של claude.ai בלי להמשיך את המשימה: autoContinueAtUsageLimit כובה או שהאיפוס זז יותר מ-24 שעות קדימה במהלך המתנה ש-Claude Code התחיל בעצמו, המשימה שהמשיכה המשיכה לפגוע במגבלה, או שההמשך נחסם לפני שהגיע למודל. לא נורה כאשר אתם לוחצים על Esc או על Ctrl+C, או בוחרים Don't continue automatically
plugin_notification
מוד מעלה התראה עם $.ui.notify. ה-title של ה-hook הוא שם המוד אלא אם המוד הגדיר אחד
הסוגים quota_auto_resume_fired, quota_auto_resume_stale ו-quota_auto_resume_disabled דורשים Claude Code בגרסה v2.1.234 או מאוחרת יותר.
בהפעלות טרמינל, permission_prompt עבור בקשת רשת של פקודה בארגז חול דורש Claude Code בגרסה v2.1.246 או מאוחרת יותר.
agent_needs_input עבור שאלת הגדרת טרמינל של חבר צוות דורש Claude Code בגרסה v2.1.248 או מאוחרת יותר.
[!NOTE]
הסוגים permission_prompt, idle_prompt, elicitation_dialog ו-elicitation_url_dialog חולקים את התזמון שלהם עם התראות שולחן העבודה, ולכן בהפעלות טרמינל אתם רואים אותם רק כאשר נראה שאתם רחוקים מהטרמינל:
צפו ל-permission_prompt אחרי שלא הקלדתם כשש שניות. הטיימר מתחיל כאשר הנחיית ההרשאה מופיעה, וכל הקשה דוחה אותו. כדי להריץ hook מיד כאשר Claude מבקש הרשאה להשתמש בכלי, השתמשו ב-PermissionRequest במקום זאת.
צפו ל-idle_prompt כ-60 שניות אחרי ש-Claude מסיים להגיב, ורק אם לא הקלדתם מאז ואין סוכן רקע, כמו תת-סוכן ברקע, שעדיין רץ. Claude Code לא שולח idle_prompt בזמן שהוא ממתין לאיפוס של מגבלת שימוש ב-claude.ai. כאשר ההמתנה מסתיימת מעצמה, אחד מסוגי quota_auto_resume_* נורה במקום זאת.
צפו ל-elicitation_dialog עבור טופס elicitation, או ל-elicitation_url_dialog עבור בקשת כתובת URL בדפדפן, אחרי שלא הקלדתם כשש שניות. שניהם חולקים את אותו שער של שש שניות כמו permission_prompt: הטיימר מתחיל כאשר התיבה מופיעה, וכל הקשה דוחה אותו.
בקשת הרשאה או elicitation שמגיעה בזמן שתיבה אחרת על המסך שומרת על אותו שער של שש שניות, שנמדד מהרגע שהבקשה מגיעה. ההתראה שלה יכולה להגיע אליכם בזמן שהבקשה עדיין ממתינה מאחורי התיבה הפתוחה.
Claude Code מתזמן את permission_prompt אחרת בהפעלות שבהן הוא שולח בקשות הרשאה ל-callback של canUseTool של Agent SDK, וכך Claude Desktop והרחבת VS Code מארחים את Claude Code:
צפו ל-permission_prompt כשש שניות אחרי ש-Claude מבקש הרשאה. Claude Code לא דוחה אותו בזמן שאתם מקלידים.
אם אתם או hook של PermissionRequest עונים מוקדם יותר, Claude Code לא מריץ את permission_prompt.
לפני v2.1.233, permission_prompt לא נורה בהפעלות האלה.
השתמשו ב-matchers נפרדים כדי להריץ מטפלים שונים לפי סוג ההתראה. התצורה הזו מפעילה סקריפט התראה ייחודי להרשאה כאשר Claude צריך אישור הרשאה, והתראה אחרת כאשר Claude היה לא פעיל:
hooks של Notification לא יכולים לחסום או לשנות התראות. Claude Code משליך את השדות systemMessage ו-continue שלהם אבל עדיין פולט את terminalSequence, ועל זה נשענת דוגמת התראת שולחן העבודה. hooks של Notification מיועדים לתופעות לוואי כמו העברת ההתראה לשירות חיצוני.
רץ כאשר קלוד מפעיל subagent עם כלי ה-Agent, כאשר קלוד מחדש subagent, ובכל פעם שחבר צוות agent team בתוך התהליך מטפל בהודעה חדשה. תומך ב-matchers לסינון לפי שם סוג הסוכן. עבור סוכנים מובנים, זה שם הסוכן כמו general-purpose, Explore או Plan. עבור subagents מותאמים, זה שדה ה-name מה-frontmatter של הסוכן, לא שם הקובץ.
עבור subagents שמגיעים מ-plugin, סוג הסוכן הוא המזהה בטווח התוסף, כגון my-plugin:reviewer, ולא שם ה-frontmatter החשוף. הנקודתיים מציבות שם בטווח תוסף על נתיב הביטוי הרגולרי, לכן עגנו את ה-matcher עם ^ ו-$ להתאמה מדויקת: ^my-plugin:reviewer$.
הוקי SubagentStart לא יכולים לחסום יצירת subagent, אבל הם יכולים להזריק הקשר לתוך ה-subagent. בנוסף ל-שדות פלט JSON הזמינים לכל ההוקים, אפשר להחזיר:
שדה
תיאור
additionalContext
מחרוזת שמתווספת להקשר של ה-subagent בתחילת השיחה שלו, לפני הפרומפט הראשון שלו. ראו הוספת הקשר לקלוד
{
"hookSpecificOutput": {
"hookEventName": "SubagentStart",
"additionalContext": "Follow security guidelines for this task"
}
}
כאשר ההוק רץ שוב עבור אותו subagent, Claude Code מזריק את ההקשר שהוחזר רק כאשר ההקשר של ה-subagent עדיין לא מחזיק את העותק מהרצה קודמת. העותק שהוזרק בהפעלה נשאר במקום, ומשאיר את מטמון הפרומפט של ה-subagent שלם. אחרי ש-auto-compaction משליך את העותק הזה, Claude Code מזריק שוב את ההקשר של ההרצה הבאה.
בנוסף ל-שדות הקלט המשותפים, הוקי SubagentStop מקבלים stop_hook_active, agent_id, agent_type, agent_transcript_path ו-last_assistant_message. השדה agent_type הוא הערך שמשמש לסינון matcher. ה-transcript_path הוא התמליל של הסשן הראשי, בעוד agent_transcript_path הוא התמליל של ה-subagent עצמו, שמאוחסן בתיקיית subagents/ מקוננת. השדה last_assistant_message מכיל את תוכן הטקסט של התגובה הסופית של ה-subagent, כך שהוקים יכולים לגשת אליו בלי לנתח את קובץ התמליל.
לא כל אירוע SubagentStop מגיע מ-subagent שקלוד הפעיל. Claude Code גם מריץ סוכנים פנימיים עבור חלק מהתכונות שלו, כגון הצעות פרומפט ו-שאלות צד /btw, ו-SubagentStop נורה גם כאשר אחד מאלה מסתיים. באירועים האלה, agent_type הוא שם הסוכן שהסשן עצמו רץ בו, כגון שם שהוגדר עם --agent או הגדרת agent, ומחרוזת ריקה כאשר הסשן רץ בלי אחד.
matcher שמציין סוגי סוכן לא מתאים ל-agent_type ריק. הוק שה-matcher שלו הושמט, "" או "*", או שהוא ביטוי רגולרי שמתאים למחרוזת ריקה, רץ גם עבור אירועים עם agent_type ריק.
ב-Claude Code v2.1.271 ואילך, subagent שרץ עם כלי SubagentHandback מוסר את הדוח שלו דרך הכלי הזה לפני שהוא עוצר. השדה last_assistant_message מחזיק אז את טקסט הסיום של ה-subagent, אם יש, וזה אינו הדוח שנמסר. הדוח הוא קלט ה-message של הקריאה הזו, שהוק PreToolUse או PostToolUse שהותאם על SubagentHandback מקבל כ-tool_input.message.
הוקי SubagentStop מקבלים גם את המערכים background_tasks ו-session_crons שמתוארים תחת קלט Stop. שני המערכים מוגבלים לסשן האב, לא ל-subagent.
הוקי SubagentStop משתמשים באותו פורמט בקרת החלטה כמו הוקי Stop, כולל hookSpecificOutput.additionalContext עם hookEventName שמוגדר ל-"SubagentStop", למשוב שאינו שגיאה ומשאיר את ה-subagent רץ. החזרת decision: "block" עם reason משאירה את ה-subagent רץ ומוסרת את reason ל-subagent כהוראה הבאה שלו. הוק שחוסם על ידי יציאה עם קוד 2 מוסר את הודעת stderr שלו באותו אופן. כדי להזריק הקשר לסשן האב אחרי ש-subagent חוזר, השתמשו בהוק PostToolUse על כלי ה-Agent במקום זאת.
רץ כאשר משימה נוצרת דרך כלי TaskCreate. השתמשו בזה כדי לאכוף מוסכמות שמות, לדרוש תיאורי משימות, או למנוע יצירת משימות מסוימות. ב-סשן בלי כלי Task, האירוע הזה לא נורה.
הוקי TaskCreated לא תומכים ב-matchers ונורים בכל מופע.
הוק TaskCreated יכול לחסום את היצירה עם קוד יציאה 2 או עם החלטת JSON. בכל אחת מהדרכים, Claude Code מוחק את המשימה ומחזיר את ההודעה שלכם לקלוד כשגיאת הכלי. Claude Code מתעלם מ-continue: false מהאירוע הזה, וקלוד ממשיך לעבוד.
קוד יציאה 2: Claude Code מחזיר את טקסט stderr כהודעה.
JSON {"decision": "block", "reason": "..."}: Claude Code מחזיר את reason כהודעה.
הדוגמה הזו חוסמת משימות שה-subject שלהן לא עוקב אחרי הפורמט הנדרש:
#!/bin/bash
INPUT=$(cat)
TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')
if [[ ! "$TASK_SUBJECT" =~ ^\[TICKET-[0-9]+\] ]]; then
echo "Task subject must start with a ticket number, e.g. '[TICKET-123] Add feature'" >&2
exit 2
fi
exit 0
רץ כאשר משימה מסומנת כמושלמת. זה נורה בשני מצבים: כאשר כל סוכן מסמן במפורש משימה כמושלמת דרך כלי TaskUpdate, או כאשר חבר צוות agent team מסיים את התור שלו עם משימות בסטטוס in-progress. השתמשו בזה כדי לאכוף קריטריוני השלמה כמו מעבר בדיקות או בדיקות lint לפני שמשימה יכולה להיסגר.
הוקי TaskCompleted לא תומכים ב-matchers ונורים בכל מופע.
הוקי TaskCompleted תומכים בשתי דרכים לשלוט בהשלמת משימה:
קוד יציאה 2: המשימה לא מסומנת כמושלמת, והודעת stderr מוחזרת למודל כמשוב.
JSON {"continue": false, "stopReason": "..."}: כאשר חבר צוות שמסיים את התור שלו הפעיל את האירוע, עוצר את חבר הצוות לגמרי, בהתאמה להתנהגות הוק Stop. ה-stopReason מוצג למשתמש. כאשר כלי TaskUpdate הפעיל את האירוע, Claude Code מתעלם מ-continue: false. קוד יציאה 2 עדיין חוסם את ההשלמה.
הדוגמה הזו מריצה בדיקות וחוסמת השלמת משימה אם הן נכשלות:
#!/bin/bash
INPUT=$(cat)
TASK_SUBJECT=$(echo "$INPUT" | jq -r '.task_subject')
# Run the test suite
if ! npm test 2>&1; then
echo "Tests not passing. Fix failing tests before completing: $TASK_SUBJECT" >&2
exit 2
fi
exit 0
בנוסף ל-שדות הקלט המשותפים, הוקי Stop מקבלים stop_hook_active, last_assistant_message, background_tasks ו-session_crons. השדה stop_hook_active הוא true כאשר Claude Code כבר ממשיך כתוצאה מהוק stop. בדקו את הערך הזה או עבדו את התמליל כדי להימנע מחסימה על תנאי שלעולם לא ייפתר.
Claude Code מחיל תקרת 8 המשכים רצופים: אחרי שהוקי stop המשיכו את התור שמונה פעמים ברצף, Claude Code דורס את החסימה הבאה ומסיים את התור. ספירת ההמשכים הרצופים מתאפסת בכל פעם שקלוד קורא לכלי. כדי להעלות את התקרה, הגדירו CLAUDE_CODE_STOP_HOOK_BLOCK_CAP.
השדה last_assistant_message מכיל את תוכן הטקסט של התגובה הסופית של קלוד, כך שהוקים יכולים לגשת אליו בלי לנתח את קובץ התמליל. עבור הוקים שפועלים על התור שזה עתה הושלם, כגון הוקי הקראה בקול או התראה, השתמשו בשדה הזה במקום לקרוא את transcript_path: קובץ התמליל לא מובטח שיכלול את ההודעה הסופית בזמן Stop בכל הגרסאות.
המערכים background_tasks ו-session_crons מאפשרים להוקים להבחין בין "הסשן הסתיים" לבין "הסשן מושהה ומחכה שעבודה ברקע תעיר אותו בחזרה". שני המערכים נוכחים כאשר מרשם המשימות נגיש, והם ריקים כאשר שום דבר לא בביצוע או מתוזמן.
כל רשומה ב-background_tasks מתארת משימה אחת בביצוע ומשתמשת בשדות האלה:
שדה
תיאור
id
מזהה משימה
type
תווית ידידותית של סוג משימה כגון shell, subagent, monitor, workflow, teammate, cloud session או MCP task. כל תווית מזהה איזו תכונה של Claude Code יצרה את המשימה. נופל חזרה ל-discriminant הגולמי עבור סוגים לא מזוהים
status
סטטוס המשימה הנוכחי
description
תיאור טקסט חופשי, מוגבל ל-1000 תווים עם סמן … [+N chars] בתוך המחרוזת כאשר נחתך
command
שורת פקודת shell, מוגבלת ל-1000 תווים. נוכחת רק עבור משימות shell
agent_type
שם סוג subagent. נוכח רק עבור משימות subagent
server
שם שרת MCP. נוכח רק עבור משימות monitor ו-MCP task
tool
שם כלי MCP. נוכח רק עבור משימות monitor ו-MCP task
name
שם workflow. נוכח רק עבור משימות workflow
כל רשומה ב-session_crons מתארת התעוררות מתוזמנת אחת בטווח הסשן, שמקורה ב-CronCreate, ScheduleWakeup ו-/loop:
שדה
תיאור
id
מזהה משימת cron
schedule
ביטוי cron, לדוגמה 0 9 * * 1-5
recurring
false עבור התעוררויות חד פעמיות שה-schedule שלהן מקודד זמן ירייה יחיד, true עבור משימות שנורות מחדש בכל התאמה
prompt
הפרומפט שנשלח כאשר ה-cron נורה, מוגבל ל-1000 תווים עם אותו סמן … [+N chars]
הדוגמה הזו מציגה קלט Stop עם משימת shell אחת בביצוע ו-cron חוזר אחד:
הוקי Stop ו-SubagentStop יכולים לשלוט אם קלוד ממשיך. בנוסף ל-שדות פלט JSON הזמינים לכל ההוקים, סקריפט ההוק שלכם יכול להחזיר את השדות הספציפיים לאירוע האלה:
שדה
תיאור
decision
"block" מונע מקלוד לעצור. השמיטו כדי לאפשר לקלוד לעצור
reason
נדרש כאשר decision הוא "block". אומר לקלוד למה הוא צריך להמשיך
hookSpecificOutput.additionalContext
משוב שאינו שגיאה לקלוד. השיחה ממשיכה כדי שקלוד יוכל לפעול לפיו, אבל בניגוד ל-decision: "block" הוא מוצג בתמליל כמשוב הוק ולא כשגיאת הוק
הוק שחוסם על ידי יציאה עם קוד 2 מנותב באותו אופן כמו reason: קלוד מקבל את הודעת stderr כהסבר למה הוא צריך להמשיך.
{
"decision": "block",
"reason": "Must be provided when Claude is blocked from stopping"
}
השתמשו ב-additionalContext כאשר ההוק עובד כמתוכנן ונותן לקלוד הנחיה, כגון "run the test suite before finishing". זה משאיר את השיחה פעילה דרך אותן הגנות לולאה כמו decision: "block", כלומר קלט stop_hook_active ותקרת 8 ההמשכים הרצופים, אבל התמליל מתייג אותו Stop hook feedback ולא מוצגת התראת שגיאת הוק:
{
"hookSpecificOutput": {
"hookEventName": "Stop",
"additionalContext": "Please run the test suite before finishing"
}
}
רץ במקום Stop כשהתור מסתיים בגלל שגיאת API. Claude Code מתעלם מפלט ה-hook ומקוד היציאה, מלבד terminalSequence. השתמשו בזה כדי לרשום כשלים, לשלוח התראות, או לבצע פעולות התאוששות כש-Claude לא יכול להשלים תגובה בגלל מגבלות קצב, בעיות אימות, או שגיאות API אחרות.
בנוסף לשדות הקלט המשותפים, הוקים של StopFailure מקבלים את error, את error_details האופציונלי, ואת last_assistant_message האופציונלי. השדה error מזהה את סוג השגיאה ומשמש לסינון matcher.
שדה
תיאור
error
סוג השגיאה: rate_limit, overloaded, authentication_failed, oauth_org_not_allowed, account_on_hold, billing_error, invalid_request, model_not_found, server_error, max_output_tokens, cloud_credential_error, או unknown
error_details
פרטים נוספים על השגיאה, כשהם זמינים
last_assistant_message
טקסט השגיאה המוצג בשיחה. בניגוד ל-Stop ול-SubagentStop, שבהם השדה מחזיק את הפלט השיחתי של Claude, עבור StopFailure הוא מכיל את מחרוזת שגיאת ה-API עצמה, כמו "API Error: Rate limit reached"
רץ כשחבר צוות בצוות סוכנים עומד לעבור למצב סרק אחרי שסיים את התור שלו. השתמשו בזה כדי לאכוף שערי איכות לפני שחבר צוות מפסיק לעבוד, למשל לדרוש בדיקות lint שעוברות או לוודא שקבצי פלט קיימים.
הוקים של TeammateIdle לא תומכים ב-matchers ורצים בכל התרחשות.
רץ כשקובץ תצורה משתנה במהלך סשן. השתמשו בזה כדי לבקר שינויי הגדרות, לאכוף מדיניות אבטחה, או לחסום שינויים לא מורשים בקבצי תצורה.
Claude Code מריץ הוקים של ConfigChange כשקובץ settings, קובץ מדיניות מנוהלת, או קובץ skill משתנים. עבור מדיניות מנוהלת, הוא מריץ אותם רק כש-managed-settings.json או קובץ ב-managed-settings.d/ משתנים. הוא מחיל הגדרות מנוהלות בשרת ושינויים בהעדפות מנוהלות של macOS או במדיניות הרישום של Windows בלי להריץ אותם. ב-WSL עם wslInheritsWindowsSettings, הוא גם מחיל קובץ הגדרות מנוהלות מצד Windows שהשתנה בסקר המדיניות שלו בלי להריץ אותם.
ה-matcher מסנן לפי מקור התצורה:
Matcher
מתי הוא רץ
user_settings
~/.claude/settings.json משתנה
project_settings
.claude/settings.json משתנה
local_settings
.claude/settings.local.json משתנה
policy_settings
managed-settings.json או קובץ ב-managed-settings.d/ משתנים
skills
קובץ skill ב-.claude/skills/ משתנה
הדוגמה הזו רושמת את כל שינויי התצורה לביקורת אבטחה:
בנוסף לשדות הקלט המשותפים, הוקים של ConfigChange מקבלים את source ובאופן אופציונלי את file_path. השדה source מציין איזה סוג תצורה השתנה, ו-file_path מספק את הנתיב לקובץ הספציפי ששונה.
הוקים של ConfigChange יכולים לחסום שינויי תצורה כך שלא ייכנסו לתוקף. השתמשו בקוד יציאה 2 או ב-JSON עם decision כדי למנוע את השינוי. כשנחסם, ההגדרות החדשות לא מוחלות על הסשן הרץ.
שדה
תיאור
decision
"block" מונע את החלת שינוי התצורה. השמיטו כדי לאפשר את השינוי
שינויי policy_settings לא ניתנים לחסימה. הוקים עדיין רצים עבור מקורות policy_settings כשקובץ הגדרות מנוהלות במכונה משתנה, כך שאפשר להשתמש בהם כדי לרשום את העריכות האלה, אבל כל החלטת חסימה מתעלמים ממנה. זה מבטיח שהגדרות מנוהלות בארגון תמיד ייכנסו לתוקף. Claude Code לא מריץ הוקים של ConfigChange כשהגדרות מנוהלות בשרת מגיעות או מתרעננות.
Claude Code פועל לפי החלטת החסימה מפלט ה-JSON של hook מסוג ConfigChange ומשליך את systemMessage ואת continue. שינוי שנחסם לא מציג שום הודעה לכם או ל-Claude, בין אם חסמתם עם reason ובין אם עם stderr בקוד יציאה 2. Claude Code כותב רק שורה ללוג הדיבוג.
רץ כשפקודת shell בשיחה הראשית משנה את ספריית העבודה, למשל כש-Claude מריץ פקודת cd. השתמשו בזה כדי להגיב לשינויי ספרייה: לטעון מחדש משתני סביבה, להפעיל toolchains ספציפיים לפרויקט, או להריץ סקריפטי setup אוטומטית. משתלב עם FileChanged עבור כלים כמו direnv שמנהלים סביבה לפי ספרייה.
להוקים של CwdChanged יש גישה ל-CLAUDE_ENV_FILE. אם ה-hook כותב משתנים לקובץ הזה, הם נשמרים לפקודות Bash הבאות עד אירוע CwdChanged הבא, ואז Claude Code מנקה אותם.
בנוסף לשדות פלט JSON הזמינים לכל ההוקים, הוקים של CwdChanged יכולים להחזיר watchPaths כדי להגדיר באופן דינמי אילו נתיבי קבצים FileChanged צופה בהם:
שדה
תיאור
watchPaths
מערך של נתיבים מוחלטים. מחליף את רשימת הצפייה הדינמית הנוכחית. נתיבים מתצורת ה-matcher שלכם תמיד נצפים. החזרת מערך ריק מנקה את הרשימה הדינמית, וזה אופייני בכניסה לספרייה חדשה
להוקים של CwdChanged אין בקרת החלטה. הם לא יכולים לחסום את שינוי הספרייה.
Claude Code קורא את watchPaths ואת systemMessage מפלט ה-JSON שלהם ומשליך את continue. בסשנים אינטראקטיביים, הוא מציג את ה-systemMessage כהתראת טרמינל קצרה. ההודעה לא מגיעה לזרם ההודעות של ה-SDK.
רץ אחרי שמוסיפים ספריית עבודה באמצע הסשן עם הפקודה /add-dir, או אחרי שלקוח SDK מוסיף אחת עם בקשת הבקרה register_repo_root. השתמשו בזה כדי להכין מאגר שנוסף זה עתה, למשל על ידי התקנת התלויות שלו.
Claude Code לא מפעיל את האירוע הזה כש:
מעבירים ספרייה עם דגל ההפעלה --add-dir. SessionStart מכסה את הספריות האלה
מוסיפים ספרייה בלשונית Workspace של /permissions
מוסיפים ספרייה שכבר היא ספריית עבודה או נמצאת בתוך אחת
Claude Code מפעיל את DirectoryAdded אחרי רענון מצב ה-sandbox וההרשאות, כך שכלים בתוך sandbox כבר רואים את הספרייה החדשה כשה-hook רץ. פקודות ה-hook עצמן רצות בלי sandbox.
Claude Code לא מחכה ל-hook: ההוספה מסתיימת מיד, וה-hook רץ ברקע עם פסק הזמן ברירת המחדל של 600 שניות.
ה-matcher מסנן לפי האופן שבו הספרייה נוספה:
Matcher
מתי הוא רץ
slash_command
מוסיפים ספרייה עם /add-dir
register_repo_root
לקוח SDK מוסיף ספרייה עם בקשת הבקרה register_repo_root
להוקים של DirectoryAdded אין בקרת החלטה. הם לא יכולים לחסום את ההוספה, שכבר הושלמה כשה-hook רץ. Claude Code משליך את השדה continue מפלט ה-JSON שלהם ומציג את השאר אחרת לפי המקור:
slash_command: Claude Code מעביר את ה-systemMessage של ה-hook ל-Claude כהקשר בתור השיחה הבא, במקום להציג אותו לכם. ספירה של הוקים שנכשלו מופיעה בתמליל. פלט כשל מלא הולך ללוג הדיבוג
register_repo_root: Claude Code כותב את פלט systemMessage ואת פלט הכשל ללוג הדיבוג בלבד
רץ כשקובץ נצפה משתנה בדיסק. Claude Code מזהה שינויים עם filesystem watcher, לא על ידי בדיקת קריאות כלים, כך שהוא מריץ את ה-hook בלי קשר למה ששינה את הקובץ: קריאת כלי Edit או Write, סקריפט ש-Claude מריץ עם Bash, או תהליך מחוץ ל-Claude Code לגמרי. שימוש נפוץ הוא טעינה מחדש של משתני סביבה כשקובצי תצורת פרויקט משתנים.
ה-matcher לאירוע הזה ממלא שני תפקידים:
בניית רשימת הצפייה: הערך מפוצל על | וכל מקטע נרשם כשם קובץ מילולי בספריית העבודה, כך ש-".envrc|.env" צופה בדיוק בשני הקבצים האלה. תבניות regex לא שימושיות כאן: ערך כמו ^\.env יצפה בקובץ ששמו המילולי הוא ^\.env.
סינון אילו הוקים רצים: כשקובץ נצפה משתנה, אותו ערך מסנן אילו קבוצות הוקים רצות לפי כללי ה-matcher הרגילים מול שם הבסיס של הקובץ שהשתנה.
הדוגמה הזו מנרמלת סיומי שורות ב-data.csv אחרי כל שינוי, כולל פקודת Bash או סקריפט חיצוני שכותב מחדש את הקובץ:
ה-hook קורא את הנתיב המוחלט של הקובץ שהשתנה מהשדה file_path של קלט ה-JSON ב-stdin. מגן ה-grep שלו בודק את אותו דבר ש-perl מסיר, CR בסוף שורה, כך שההרצה אחרי נרמול יוצאת בלי לגעת בקובץ. מגן רופף יותר נכנס ללולאה אינסופית, כי perl -i כותב מחדש את הקובץ גם כשהוא לא מחליף כלום ו-Claude Code מריץ את ה-hook שוב אחרי כל כתיבה מחדש. שמרו את הסקריפט הזה ב-/path/to/normalize-line-endings.sh והפכו אותו לניתן להרצה:
#!/bin/bash
FILE=$(jq -r .file_path)
if grep -q $'\r$' "$FILE"; then
perl -pi -e 's/\r$//' "$FILE"
fi
כדי לאשר שה-hook עובד, בקשו מ-Claude לצרף שורת CRLF ל-data.csv עם פקודת Bash. Claude Code מריץ את ה-hook והקובץ מסתיים עם סיומי LF.
כדי לצפות בקבצים שאי אפשר לנקוב בשמם מראש, החזירו watchPaths מ-hook כדי לעדכן את רשימת הצפייה באופן דינמי. Claude Code מפעיל את ה-watcher רק כשמשהו מנקב בשם קובץ לצפייה, אז זרעו את הרשימה עם קבוצת FileChanged שה-matcher שלה מנקב בשם של לפחות קובץ אחד, או עם hook של SessionStart או CwdChanged שמחזיר watchPaths. ה-matcher עדיין מסנן אילו קבוצות הוקים רצות כשקובץ נצפה משתנה, אז תנו לקבוצה שמטפלת בנתיבים דינמיים matcher שהושמט, שמתאים לכל קובץ נצפה ולא מוסיף כלום לרשימת הצפייה. matcher של "*" גם מתאים לכל קובץ, אבל Claude Code רושם אותו ברשימת הצפייה כמו כל ערך אחר, כקובץ מילולי בשם *.
להוקים של FileChanged יש גישה ל-CLAUDE_ENV_FILE. משתנים שנכתבים לקובץ הזה נשמרים לפקודות Bash הבאות עד אירוע CwdChanged הבא, ואז Claude Code מנקה אותם.
בנוסף לשדות פלט JSON הזמינים לכל ההוקים, הוקים של FileChanged יכולים להחזיר watchPaths כדי לעדכן באופן דינמי אילו נתיבי קבצים נצפים:
שדה
תיאור
watchPaths
מערך של נתיבים מוחלטים. מחליף את רשימת הצפייה הדינמית הנוכחית. נתיבים מתצורת ה-matcher שלכם תמיד נצפים. השתמשו בזה כשסקריפט ה-hook מגלה קבצים נוספים לצפייה על סמך הקובץ שהשתנה
להוקים של FileChanged אין בקרת החלטה. הם לא יכולים לחסום את שינוי הקובץ מלהתרחש.
Claude Code קורא את watchPaths ואת systemMessage מפלט ה-JSON שלהם ומשליך את continue. בסשנים אינטראקטיביים, הוא מציג את ה-systemMessage כהתראת טרמינל קצרה. ההודעה לא מגיעה לזרם ההודעות של ה-SDK.
הוק WorktreeCreate לא רץ עבור worktree ש-Claude מוסיף דרך Bash, והוק של תוסף לא רץ עבור זה שנוצר כשאתה מפעיל עם --worktree ועם --tmux:
git worktree add דרך Bash: כדי לבדוק או לחסום את הפקודה הזו, הוסף הוק PreToolUse עם ה-matcher Bash.
--worktree עם --tmux: Claude Code יוצר את ה-worktree לפני שהוא טוען תוספים, ולכן הוק WorktreeCreate מתוסף לא רץ. כדי שההוק שלך ירוץ עם שני הדגלים, הגדר אותו בקובץ הגדרות במקום זאת. לפני v2.1.300, הוק WorktreeCreate של תוסף לא רץ גם עם --worktree לבד.
כברירת מחדל Claude Code יוצר את עותק העבודה המבודד עם git worktree. הגדרת הוק WorktreeCreate מחליפה את התנהגות ה-git ברירת המחדל הזו, ומאפשרת לך להשתמש במערכת בקרת גרסאות אחרת כמו SVN, Perforce, או Mercurial.
מכיוון שההוק מחליף את התנהגות ברירת המחדל במלואה, .worktreeinclude לא מעובד. אם אתה צריך להעתיק קבצי הגדרות מקומיים כמו .env אל ה-worktree החדש, עשה זאת בתוך סקריפט ההוק שלך.
ההוק חייב להחזיר את הנתיב לתיקיית ה-worktree שנוצרה. Claude Code משתמש בנתיב הזה כתיקיית העבודה של הסשן המבודד. ראה פלט WorktreeCreate לאופן שבו כל סוג הוק מחזיר את הנתיב.
Claude Code פועל לפי הצלחת ההוק ולפי הנתיב שהוחזר, ומשליך את systemMessage ואת continue.
הדוגמה הזו יוצרת עותק עבודה של SVN ומדפיסה את הנתיב כדי ש-Claude Code ישתמש בו. החלף את כתובת ה-URL של המאגר בזו שלך:
ההוק קורא את name של ה-worktree מקלט ה-JSON ב-stdin, מבצע checkout לעותק חדש לתוך תיקייה חדשה, ומדפיס את נתיב התיקייה. ה-echo בשורה האחרונה הוא מה ש-Claude Code קורא כנתיב ה-worktree. הפנה כל פלט אחר אל stderr כדי שהוא לא יפריע לנתיב.
בנוסף לשדות הקלט המשותפים, הוקי WorktreeCreate מקבלים את השדה name. זהו מזהה slug עבור ה-worktree החדש, שצוין על ידי המשתמש או שנוצר אוטומטית, לדוגמה bold-oak-a3f2.
הוקי WorktreeCreate לא משתמשים במודל ההחלטה הרגיל של allow/block. במקום זאת, הצלחה או כישלון של ההוק קובעים את התוצאה. ההוק חייב להחזיר את הנתיב לתיקיית ה-worktree שנוצרה:
הוקי command (type: "command"): הדפס את הנתיב כשורה האחרונה שאינה ריקה ב-stdout. Claude Code מסיר קודי מילוט של ANSI לפני שהוא קורא את השורה הזו, כך שבאנרים של הפעלת מעטפת שהודפסו לפני ה-echo שלך מתעלמים מהם. הפנה כל פלט אחר של ההוק אל stderr.
אם ההוק נכשל או לא מייצר נתיב, יצירת ה-worktree נכשלת עם שגיאה. Claude Code פותר נתיב יחסי ביחס לתיקייה שבה ההוק רץ, ומצמצם כל מקטעי . או .. בתוכו. אם הנתיב שמתקבל אינו תיקייה ש-Claude Code יכול להיכנס אליה, הסשן מדפיס שגיאה שמציינת את הנתיב ויוצא עם קוד 1.
Claude Code מסרב לנתיב מוחלט שמכיל מקטעי . או .., ולכל נתיב שעובר דרך symlink מתחת לשורש המאגר. השגיאה מציינת את הרכיב שנדחה. symlink ש-commit שלו נמצא במאגר יכול להפנות את ה-worktree אל מחוץ לו. החזר נתיב מנורמל שלא עובר דרך symlink בתוך המאגר.
אתה מבקש מ-Claude לצאת ולהסיר את ה-worktree במהלך סשן, ו-Claude מסיר אותו עם הכלי ExitWorktree
סשן ש-claude remote-control התחיל במצב worktree מסתיים בלי לקרוס, ו-Claude Code לא מוצא קבצים שהשתנו או קבצים שלא במעקב ואין קומיטים חדשים ב-worktree שלו
אתה עוצר את claude remote-control בזמן שסשנים שהוא התחיל במצב worktree עדיין רצים, ו-Claude Code לא מוצא קבצים שהשתנו או קבצים שלא במעקב ואין קומיטים חדשים ב-worktrees שלהם
כאשר סוכן משנה או סוכן workflow מסיים, Claude Code שומר את ה-worktree שההוק WorktreeCreate שלך יצר עבורו ולא מריץ את ההוק WorktreeRemove שלך. הסר את ה-worktrees האלה בעצמך כשהעבודה הסתיימה.
Claude Code לא מבקש ממך לפני שההוק שלך רץ עבור קריאה ל-ExitWorktree או עבור ניקוי של claude remote-control. ExitWorktree מסרב להסיר worktree שנוצר על ידי הוק אלא אם הקריאה מעבירה discard_changes: true, מה שהופך את ההוק שלך לבדיקה האחרונה במסלול הזה.
Claude Code משתמש ב-git כדי לחפש קבצים שהשתנו או קבצים שלא במעקב, ולכן הוא לא מוצא כאלה ב-worktree שאינו checkout של git או בתוך אחד כזה, גם כאשר התיקייה מכילה עבודה שלא עברה commit. בדוק את העבודה הזו בהוק WorktreeRemove שלך לפני שהוא מוחק משהו.
עבור worktrees מבוססי git, Claude Code מטפל בניקוי אוטומטית עם git worktree remove. אם הגדרת הוק WorktreeCreate, צמד אותו עם הוק WorktreeRemove כדי לשלוט בניקוי:
אין הוק WorktreeRemove: Claude Code חוזר ל-git עבור הסרה ביציאה או דרך ExitWorktree, ושומר את ה-worktree כאשר claude remote-control מנקה:
אתה יוצא מסשן worktree, או Claude קורא ל-ExitWorktree: Claude Code מסיר את הנתיב שההוק WorktreeCreate שלך החזיר כפי ש-git worktree remove --force היה עושה, כך ש-worktree ש-git מזהה מוסר. worktree ש-git לא מזהה, לדוגמה אחד שההוק שלך יצר עם מערכת בקרת גרסאות שאינה git, נשאר על הדיסק.
claude remote-control מנקה את ה-worktree של סשן: ה-worktree נשאר על הדיסק, והטרמינל שמריץ את claude remote-control מציג worktree removal failed, kept: <path>.
ההוק יוצא עם 0: ה-worktree נחשב כמוסר. Claude Code לא קורא שום דבר אחר מההוק, אז ודא שההוק שלך מחק את התיקייה.
ההוק יוצא עם קוד שאינו אפס: ההסרה נכשלת אם התיקייה ב-worktree_path עדיין קיימת אחר כך, וה-worktree נשאר על הדיסק בלי חזרה ל-git. הוק שמחק את התיקייה לפני יציאה עם קוד שאינו אפס נחשב כמוסר. לאופן הדיווח על הכישלון, ראה קלט WorktreeRemove.
Claude Code לעולם לא מוחק ענף ששייך ל-worktree שנוצר על ידי הוק, כי הוא יודע רק את הנתיב שההוק WorktreeCreate שלך החזיר. אם ההוק WorktreeCreate שלך יוצר ענף, מחק אותו בהוק WorktreeRemove שלך. Claude Code משליך שדות פלט JSON של הוק WorktreeRemove, כמו systemMessage ו-continue.
עבור מחיקת סשן רקע, Claude Code מאמת את נתיב ה-worktree השמור לפני הרצת ההוק, ומסרב לנתיב שהוא symlink או שעובר דרך אחד מתחת לשורש המאגר. במסלול הזה, ההוק רץ עבור worktree שעדיין מכיל קבצים רק כאשר אתה מאשר את המחיקה בתצוגת הסוכן. עבור worktree כזה, claude rm שומר את הסשן ואת ה-worktree במקום זאת.
Claude Code מעביר את הנתיב שהחזיר WorktreeCreate כ-worktree_path בקלט ההוק. הדוגמה הזו קוראת את הנתיב הזה ומסירה את התיקייה:
קוד היציאה של הוק WorktreeRemove קובע את התוצאה. כאשר הוק יוצא עם קוד שאינו אפס והתיקייה ב-worktree_path עדיין קיימת אחר כך, ההסרה נכשלת:
ה-worktree נשאר על הדיסק, והפקודה וה-stderr של ההוק הולכים אל יומן הדיבאג.
אם מחקת סשן רקע, גם הסשן נשאר. הודעת הסירוב בתצוגת הסוכן מדווחת איך ההוק הסתיים, כמו exited 1, מצטטת את תחילת ה-stderr שלו, ואומרת אם מחיקת הסשן שוב מסירה את התיקייה בכל זאת.
אם claude remote-control ניקה את ה-worktree של סשן, הטרמינל שמריץ אותו מציג worktree removal failed, kept: <path>.
צא עם קוד 2 כדי לחסום compaction. עבור /compact ידני, הודעת ה-stderr מוצגת למשתמש. אפשר גם לחסום על ידי החזרת JSON עם "decision": "block".
לחסימת compaction אוטומטי יש השפעות שונות בהתאם למועד שבו הוא נורה. אם ה-compaction הופעל באופן יזום לפני מגבלת ההקשר, Claude Code מדלג עליו והשיחה ממשיכה בלי compaction. אם ה-compaction הופעל כדי להתאושש משגיאת מגבלת הקשר שכבר הוחזרה על ידי ה-API, השגיאה הבסיסית מופיעה והבקשה הנוכחית נכשלת.
Claude Code משליך את השדות systemMessage ו-continue של הוק PreCompact.
בנוסף לשדות הקלט המשותפים, הוקי PreCompact מקבלים את trigger ואת custom_instructions. עבור manual, custom_instructions מכיל את מה שהמשתמש מעביר אל /compact והוא null כאשר הם לא מעבירים כלום. עבור auto, custom_instructions הוא null.
רץ אחרי ש-Claude Code משלים פעולת compact. השתמש באירוע הזה כדי להגיב למצב ה-compacted החדש, לדוגמה כדי לרשום ביומן את הסיכום שנוצר או לעדכן מצב חיצוני. Claude Code משליך את השדות systemMessage ו-continue של הוק PostCompact.
בנוסף לשדות הקלט המשותפים, הוקי PostCompact מקבלים את trigger ואת compact_summary. השדה compact_summary מכיל את סיכום השיחה שנוצר על ידי פעולת ה-compact.
{
"session_id": "abc123",
"transcript_path": "/Users/.../.claude/projects/.../00893aaf-19fa-41d2-8238-13269b9b3ca0.jsonl",
"cwd": "/Users/...",
"hook_event_name": "PostCompact",
"trigger": "manual",
"compact_summary": "Summary of the compacted conversation..."
}
להוקי PostCompact אין שליטה בהחלטה. הם לא יכולים להשפיע על תוצאת ה-compaction אבל יכולים לבצע משימות המשך.
בקשת set_model, או שינוי מודל בבקשת apply_flag_settings, ממארח Agent SDK או מ-Remote Control
קלוד קוד לא מריץ הוקים של PreModelSwitch עבור החלפות שהוא מבצע בעצמו, כמו נפילה אוטומטית למודל או שחזור המודל כשאתם ממשיכים סשן. השינויים האלה מגיעים רק אל PostModelSwitch.
קלוד קוד משווה את ה-matcher מול השם הקנוני של המודל שאליו הסשן עובר, ומתעלם מסיומת [1m] כלשהי. כינוי כמו opus, מזהה מודל עם תאריך, ומזהה ספציפי לספק כמו מזהה מודל של Amazon Bedrock, כולם תואמים את השם הקנוני האחד שאליו הם נפתרים, ולכן claude-opus-5 מכסה כל כתיב של Opus 5.
כשקלוד קוד לא יכול לקבוע שם קנוני ליעד, למשל מזהה מודל מותאם שרק שער ה-LLM שלכם מכיר, הוא מריץ כל הוק PreModelSwitch בלי תלות ב-matcher. הוק שחוסם צריך לכן לבדוק את to_model מהקלט שלו, ולא להסתמך על ה-matcher לבדו.
כתבו את ה-matcher כשם מדויק, כרשימה מופרדת ב-| כמו claude-opus-4-6|claude-opus-5, או כביטוי רגולרי כמו .*opus.*. הדוגמה הזו משתמשת ב-matcher של שם מדויק וגם בודקת את to_model מקלט ההוק, כך שהיא מסרבת להחלפה אל Opus 4.6 על ידי יציאה עם קוד 2 ומעבירה כל יעד אחר:
[tab] macOS/Linux
הפקודה בודקת את to_model עם jq:
{
"hooks": {
"PreModelSwitch": [
{
"matcher": "claude-opus-4-6",
"hooks": [
{
"type": "command",
"command": "jq -e '.to_model | test(\"opus-4-6\")' > /dev/null && { echo 'Opus 4.6 is retired for this project. Use a newer model.' >&2; exit 2; }; exit 0"
}
]
}
]
}
}
שמרו את הסקריפט הזה אל .claude/hooks/block-opus-46.ps1 בפרויקט שלכם:
$hookInput = [Console]::In.ReadToEnd() | ConvertFrom-Json
if ($hookInput.to_model -match 'opus-4-6') {
[Console]::Error.WriteLine('Opus 4.6 is retired for this project. Use a newer model.')
exit 2
}
exit 0
כדי לוודא שההוק עובד, הריצו /model claude-opus-4-6 מסשן שרץ על מודל אחר. קלוד קוד שומר את המודל הנוכחי ומדווח שהוק PreModelSwitch חסם את ההחלפה, עם ההודעה שלכם כסיבה.
בנוסף לשדות הקלט המשותפים, הוקים של PreModelSwitch מקבלים את השדות בטבלה הזו. חמשת האחרונים מתארים כמה עולה לשלוח מחדש את השיחה אל המודל החדש, כך שהוק יכול להציג את הנתון הזה לפני שההחלפה מתרחשת.
שדה
סוג
תיאור
from_model
string
מזהה המודל שממנו ההחלפה משנה
to_model
string
מזהה המודל שאליו ההחלפה משנה. ה-matcher מושווה מול השם הקנוני של המודל הזה
requested_model
string או null
המודל שהבקשה נקבה בשמו: כינוי כמו opus, מזהה מודל מלא, או null כשהבקשה הייתה למודל ברירת המחדל
source
string
מאיפה הבקשה הגיעה: "command" עבור /model <name>, הגדרת Model בתוך /config, או הפעלת מצב מהיר; "picker" עבור בורר מודל; "sdk" עבור בקשת set_model, או שינוי מודל בבקשת apply_flag_settings, ממארח Agent SDK או מ-Remote Control
context_tokens
number
טוקנים שהבקשה הבאה שולחת מחדש כפרומפט שלה: הטוקנים של הקלט, קריאת המטמון, יצירת המטמון והפלט של התשובה האחרונה בשיחה הראשית, יחד. 0 לפני התשובה הראשונה
prompt_cache_warm
boolean
האם מטמון הפרומפט של המודל הנוכחי כנראה עדיין חם, כלומר ההחלפה מוותרת עליו
עלות משוערת בדולר אמריקאי של כתיבת context_tokens אל מטמון הפרומפט על to_model בתעריף cache_ttl, בלי התשובה הבאה. השרת אולי לא צריך לשמור מחדש במטמון את כל ההקשר, ולכן התייחסו לזה כהערכה
pricing
string
איך קלוד קוד תמחר את estimated_cache_write_usd: "configured" בתעריפים של הארגון שלכם כשהוא הגדיר אותם, "catalog" במחיר מחירון, או "default" כשל-to_model אין מחיר ידוע וקלוד קוד הניח תעריף ברירת מחדל
הדוגמה הזו מציגה את הקלט עבור /model opus בסשן שרץ על Sonnet 5:
הוקים של PreModelSwitch יכולים לבטל את ההחלפה, לבקש מהמשתמש לאשר אותה, או לתת לה להמשיך. קוד יציאה 2 או decision: "block" ברמה העליונה מבטל את ההחלפה.
לשליטה עדינה יותר, החזירו permissionDecision ו-permissionDecisionReason באובייקט hookSpecificOutput, כמו ב-PreToolUse. PreModelSwitch מקבל "allow", "deny" ו-"ask". הוא לא מקבל "defer", updatedInput או additionalContext. הטבלה למטה מתארת את שני השדות:
עבור "deny", מוצג למשתמש כסיבה שההחלפה נחסמה, או מוחזר כשגיאה עבור בקשת set_model. עבור "ask", מוצג בהנחיית האישור. מתעלמים ממנו עבור "allow"
רק /model בסשן אינטראקטיבי יכול להציג את הנחיית "ask". בכל משטח אחר, כולל מצב לא אינטראקטיבי עם הדגל -p, /config ובקשות set_model, קלוד קוד מתייחס אל "ask" כסירוב.
הדוגמה הזו מבקשת מהמשתמש לאשר ומצטטת את ספירת הטוקנים מ-context_tokens:
{
"hookSpecificOutput": {
"hookEventName": "PreModelSwitch",
"permissionDecision": "ask",
"permissionDecisionReason": "Switching now re-sends about 180k tokens to the new model. Continue?"
}
}
כשכמה הוקים של PreModelSwitch מחזירים החלטות שונות, סדר העדיפות הוא deny > ask > allow.
קלוד קוד מציג למשתמש כל systemMessage שההוק שלכם מחזיר בלי תלות בהחלטה, כך שהוק לדיווח עלות יכול להחזיר {"systemMessage": "..."} ולצאת עם 0.
רץ אחרי שמודל הסשן משתנה. השתמשו בו כדי לתת לקלוד הנחיה ספציפית למודל בלי לערוך כל CLAUDE.md, למשל הוראה כלל ארגונית שחלה על מודלים מסוימים.
PostModelSwitch דורש את קלוד קוד בגרסה v2.1.251 ומעלה. הוא לא יכול לחסום, כי המודל כבר השתנה. קלוד קוד מריץ הוקים של PostModelSwitch אחרי כל אחד מהשינויים האלה:
הוקים של PostModelSwitch מקבלים את אותם שדות כמו PreModelSwitch, עם hook_event_name שמוגדר ל-"PostModelSwitch" ושני ערכי source נוספים: "auto" עבור נפילה אוטומטית או שינוי אחר שקלוד קוד ביצע בעצמו, ו-"resume" עבור המודל ששוחזר כשאתם ממשיכים סשן.
requested_model הוא null כש-source הוא "auto". כש-source הוא "resume", זהו הגדרת המודל השמורה שקלוד קוד שחזר.
קלוד קוד לוקח את stdout בטקסט רגיל של ההוק שלכם ביציאה 0, או את additionalContext מפלט JSON, ומעביר אותו לקלוד עם הבקשה הבאה אחרי ההחלפה. בנוסף לשדות פלט ה-JSON שזמינים לכל ההוקים, אפשר להחזיר:
אם ההוק לא הסתיים תוך חמש שניות אחרי ששלחתם את הפרומפט הבא, קלוד קוד שולח את הבקשה הזו בלי הפלט ומצרף אותו לבקשה שאחריה במקום זאת. אם המודל משתנה כמה פעמים לפני הבקשה הבאה, קלוד קוד מעביר רק את הפלט עבור מודל היעד של ההחלפה האחרונה.
להוקים של SessionEnd אין בקרת החלטה. הם לא יכולים לחסום סיום סשן, אבל יכולים לבצע משימות ניקוי. קלוד קוד משליך את שדות פלט ה-JSON שלהם, כמו systemMessage.
להוקים של SessionEnd יש פסק זמן ברירת מחדל של 1.5 שניות. הוא חל כשאתם יוצאים, מריצים /clear, או מחליפים סשנים עם /resume אינטראקטיבי. אפשר לתת להוק יותר זמן בשתי דרכים:
timeout לכל הוק: הגדירו timeout בהגדרות של אותו הוק. התקציב הכולל עולה אוטומטית כדי להתאים ל-timeout הגבוה ביותר לכל הוק בקבצי ההגדרות שלכם, עד 60 שניות. אם מעלים את התקציב כך, הוק בלי timeout משלו עדיין שומר את ברירת המחדל. פסקי זמן שמוגדרים על הוקים שמגיעים מתוסף לא מעלים את התקציב.
CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS: הגדירו את משתנה הסביבה הזה באלפיות שנייה כדי לדרוס את התקציב במפורש. הערך שאתם מגדירים גם הופך לפסק הזמן של כל הוק בלי timeout משלו.
הדוגמה הזו מגדירה את התקציב ל-5 שניות:
CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=5000 claude
לפני v2.1.268, CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS העלה רק את התקציב הכולל, והוק בלי timeout משלו עדיין בוטל אחרי 1.5 שניות.
רץ כששרת MCP מבקש קלט מהמשתמש באמצע משימה. כברירת מחדל, Claude Code מציג דיאלוג אינטראקטיבי כדי שהמשתמש יגיב. Hooks יכולים ליירט את הבקשה ולהגיב באופן תכנותי, ולדלג על הדיאלוג לגמרי.
hook של Elicitation יכול לענות על הבקשה בשם המשתמש, לדחות אותה או לבטל אותה, או להשאיר אותה לדיאלוג. כדי לענות, לדחות או לבטל, צאו עם קוד 0 והדפיסו אובייקט hookSpecificOutput עם action. השרת מקבל את התשובה שלכם ולא מופיע דיאלוג. כל שורה בטבלה הזו מראה מה להחזיר עבור תוצאה אחת ומה שרת ה-MCP מקבל:
הדוגמה הזו עונה על שאלה חוזרת אחת בשם המשתמש. שרת MCP בשם issue-tracker מבקש מפתח פרויקט בטופס, וה-hook ממלא DOCS. הסקריפט מקבל כש-project_key הוא השדה היחיד של הטופס. לכל בקשה אחרת הוא לא מדפיס כלום, ולכן הדיאלוג מופיע.
[tab] macOS/Linux
רשמו command hook לאירוע בקובץ ההגדרות שלכם, עם שם השרת כ-matcher:
כדי לאשר שה-hook עובד, הפעילו את Claude Code עם claude --debug ותנו ל-Claude משימה שגורמת לשרת לבקש את מפתח הפרויקט. לא מופיע דיאלוג, וביומן הדיבוג יש שורה שמסתיימת ב-Elicitation resolved by hook: {"action":"accept","content":{"project_key":"DOCS"}}.
hook של ElicitationResult יכול להעביר את תגובת המשתמש, לשנות את הערכים שלה, או לחסום אותה. כדי לשנות או לחסום את התגובה, צאו עם קוד 0 והדפיסו אובייקט hookSpecificOutput עם action. כל שורה בטבלה הזו מראה מה להחזיר עבור תוצאה אחת ומה שרת ה-MCP מקבל:
כדי
החזרה
השרת מקבל
העברת התגובה
בלי פלט, עם קוד יציאה 0
תגובת המשתמש, בלי שינוי
שינוי הערכים שנשלחו
"action": "accept", עם הערכים החדשים ב-content
accept עם ה-content שלכם במקום ערכי המשתמש
חסימת התגובה
"action": "decline"
decline, בלי ערכי המשתמש
ביטול הבקשה
"action": "cancel"
cancel, יחד עם הערכים שהמשתמש שלח. כדי למנוע את שליחתם, החזירו "decline"
ה-content שלכם מחליף את כל אובייקט ה-content של המשתמש, ולכן כללו את השדות שאתם לא משנים. החזירו action יחד איתו, כי Claude Code מתעלם מ-hookSpecificOutput שאין בו action.
hooks של ElicitationResult רצים גם כשהמשתמש דוחה או מבטל, וה-action שלכם מחליף את שלהם. בדקו שה-action של הקלט הוא accept לפני שאתם מחזירים accept, אחרת ה-hook שלכם הופך בקשה שנדחתה לבקשה שהתקבלה. הסקריפט הזה מבצע את אותו שינוי כשהמשתמש קיבל, שומר את שאר השדות, ולא מדפיס כלום אחרת:
#!/bin/bash
input=$(cat)
if [ "$(jq -r '.action' <<<"$input")" = "accept" ]; then
jq '{hookSpecificOutput: {hookEventName: "ElicitationResult", action: "accept", content: (.content + {username: (.content.username + "@example.com")})}}' <<<"$input"
fi
קוד יציאה 2 ו-"decision": "block" ברמה העליונה גם חוסמים את התגובה. דרכים נוספות לדחות elicitation מכסה איזה מהם נכנס לתוקף כש-hook משלב אותם, מה המשתמש רואה, ואילו גרסאות התעלמו מ-decision.
Claude Code משליך את reason, systemMessage ו-continue מפלט ה-JSON של hook של ElicitationResult, בכל action שאתם מחזירים.
בנוסף ל-hooks מסוג command, HTTP ו-MCP tool, Claude Code תומך ב-hooks מבוססי prompt (type: "prompt") שמשתמשים ב-LLM כדי להעריך אם לאפשר או לחסום פעולה, וב-agent hooks (type: "agent") שמפעילים מאמת סוכני עם גישה לכלים. לא כל האירועים תומכים בכל סוג hook.
אירועים שתומכים בכל חמשת סוגי ה-hook (command, http, mcp_tool, prompt ו-agent):
PermissionDenied
PostToolBatch
PostToolUse
PostToolUseFailure
PreToolUse
Stop
SubagentStop
TaskCompleted
TaskCreated
TeammateIdle
UserPromptExpansion
UserPromptSubmit
PermissionRequest תומך ב-hooks מסוג command, http, mcp_tool ו-prompt אבל לא ב-hooks מסוג agent. אם תגדירו agent hook על האירוע הזה, Claude Code מדלג עליו וזרימת ההרשאה ממשיכה בלי שינוי. כדי לאפשר או למנוע מתוך hook, החזירו את אובייקט ההחלטה מ-hook מסוג command או HTTP.
אירועים שתומכים ב-hooks מסוג command, http ו-mcp_tool אבל לא ב-prompt או agent:
ConfigChange
CwdChanged
DirectoryAdded
Elicitation
ElicitationResult
FileChanged
InstructionsLoaded
MessageDisplay
Notification
PostCompact
PostModelSwitch
PreCompact
PreModelSwitch
SessionEnd
StopFailure
SubagentStart
WorktreeCreate
WorktreeRemove
SessionStart ו-Setup תומכים ב-hooks מסוג command ו-mcp_tool, ושדות MCP tool hook מתארים מתי ה-hooks מסוג mcp_tool שלהם רצים. הם לא תומכים ב-hooks מסוג http, prompt או agent.
הגדירו את type ל-"prompt" וספקו מחרוזת prompt במקום command. השתמשו במציין המיקום $ARGUMENTS כדי להזריק את נתוני קלט ה-JSON של ה-hook לטקסט ה-prompt שלכם.
ב-prompt או ב-agent hook, אפשר לכתוב את ה-prompt ככלל על מה לחסום או לאפשר, למשל "Block any Bash command that reads .env files", או כתנאי שחייב להתקיים, למשל "All unit tests pass".
ה-hook הזה של Stop מבקש מה-LLM להעריך אם כל המשימות הושלמו לפני שמאפשרים ל-Claude לסיים:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "Evaluate if Claude should stop: $ARGUMENTS. Check if all tasks are complete."
}
]
}
]
}
}
שדה
נדרש
תיאור
type
כן
חייב להיות "prompt"
prompt
כן
טקסט ה-prompt לשליחה ל-LLM. השתמשו ב-$ARGUMENTS כמציין מיקום ל-JSON של קלט ה-hook. אם $ARGUMENTS לא קיים, JSON הקלט מצורף ל-prompt
model
לא
המודל לשימוש בהערכה. ברירת המחדל היא המודל ש-Claude Code משתמש בו עבור פונקציונליות רקע
timeout
לא
זמן קצוב בשניות. ברירת מחדל: 30
continueOnBlock
לא
באירועים שהוא חל עליהם, true מחזיר ל-Claude סיבה של ok: false וממשיך במקום לסיים את התור. ברירת מחדל: false. ראו סכמת תגובה להתנהגות לפי אירוע
{
"ok": true | false,
"reason": "Explanation for the decision",
"impossible": true | false
}
שדה
תיאור
ok
true כדי לאפשר. עבור false, ראו את ההתנהגות לפי אירוע למטה
reason
נדרש כש-ok הוא false
impossible
אופציונלי. המודל מחזיר אותו עם ok: false כשהוא שופט שהתנאי לא יכול להתקיים לעולם. ב-Stop וב-SubagentStop, Claude Code אז מאפשר לתור להסתיים במקום להחזיר את הסיבה. agent hooks ואירועים אחרים מתעלמים ממנו
מה שקורה ב-ok: false תלוי באירוע:
Stop ו-SubagentStop: הסיבה מוחזרת ל-Claude כהוראה הבאה שלו והתור ממשיך, אלא אם התגובה גם מגדירה impossible: true, ובמקרה הזה Claude Code מאפשר את העצירה והתור מסתיים
PreToolUse: קריאת הכלי נדחית. כברירת מחדל התור מסתיים וסיבת הדחייה מופיעה בצ'אט כשורת אזהרה. הגדירו continueOnBlock: true כדי במקום זאת להחזיר את הסיבה ל-Claude כשגיאת הכלי כך שיוכל להתאים ולהמשיך, שווה ערך ל-permissionDecision: "deny" של command hook
PostToolUse: כברירת מחדל התור מסתיים והסיבה מופיעה בצ'אט כשורת אזהרה. הגדירו continueOnBlock: true כדי להחזיר את הסיבה ל-Claude ולהמשיך את התור
PostToolBatch, UserPromptSubmit ו-UserPromptExpansion: התור מסתיים והסיבה מופיעה כשורת אזהרה. האירועים האלה מסיימים את התור ב-decision: "block" בלי קשר ל-continue
PostToolUseFailure ו-TaskCreated: הסיבה מוחזרת ל-Claude כשגיאת כלי והתור ממשיך, בלי קשר ל-continueOnBlock
TaskCompleted: כשהוא נורה כי משימה סומנה כהושלמה במהלך תור, הסיבה מוחזרת ל-Claude כשגיאת כלי והתור ממשיך, בלי קשר ל-continueOnBlock. כשהוא נורה כי teammate עוצר, הוא מתנהג כמו TeammateIdle ועוצר את ה-teammate כברירת מחדל
TeammateIdle: כברירת מחדל ה-teammate עוצר והסיבה מופיעה כשורת אזהרה. הגדירו continueOnBlock: true כדי להחזיר את הסיבה ל-teammate ולהשאיר אותו בעבודה
PermissionRequest: ל-ok: false אין השפעה. כדי לדחות אישור מתוך hook, השתמשו ב-command hook שמחזיר hookSpecificOutput.decision.behavior: "deny"
PermissionDenied: ל-ok: false אין השפעה כי הדחייה כבר קרתה. הפלט היחיד שהאירוע הזה קורא הוא hookSpecificOutput.retry, ש-prompt hooks ו-agent hooks לא יכולים להגדיר. הם רצים על האירוע הזה, אבל הפלט שלהם מושלך. השתמשו ב-command hook כדי להחזיר retry
אם אתם צריכים שליטה עדינה יותר על אירוע כלשהו, השתמשו ב-command hook עם השדות לפי אירוע שמתוארים בבקרת החלטה.
ה-hook הזה של Stop משתמש ב-prompt מפורט כדי לבדוק שלושה תנאים לפני שמאפשרים ל-Claude לעצור. hooks של SubagentStop משתמשים באותו פורמט כדי להעריך אם subagent צריך לעצור. אם המודל מחזיר "ok": false כי התנאי עדיין לא מתקיים, Claude ממשיך לעבוד עם הסיבה שסופקה כהוראה הבאה שלו:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "prompt",
"prompt": "You are evaluating whether Claude should stop working. Context: $ARGUMENTS\n\nAnalyze the conversation and determine if:\n1. All user-requested tasks are complete\n2. Any errors need to be addressed\n3. Follow-up work is needed\n\nRespond with JSON: {\"ok\": true} to allow stopping, or {\"ok\": false, \"reason\": \"your explanation\"} to continue working.",
"timeout": 30
}
]
}
]
}
}
הוקי סוכן הם ניסיוניים. ההתנהגות וההגדרות עשויות להשתנות במהדורות עתידיות. לתהליכי עבודה בייצור, העדיפו הוקי command.
הוקים מבוססי סוכן (type: "agent") דומים להוקים מבוססי prompt, אבל עם גישה לכלים לאורך כמה תורות. במקום קריאה אחת ל-LLM, הוק סוכן מפעיל תת-סוכן שיכול לקרוא קבצים, לחפש בקוד ולבדוק את בסיס הקוד כדי לאמת תנאים. הוקי סוכן תומכים באותם אירועים כמו הוקים מבוססי prompt, חוץ מ-PermissionRequest.
Claude Code מפעיל תת-סוכן עם ה-prompt שלכם ועם קלט ה-JSON של ההוק
תת-הסוכן יכול להשתמש בכלים כמו Read, Grep ו-Glob כדי לחקור
אחרי עד 50 תורות, תת-הסוכן מחזיר החלטה מובנית { "ok": true/false }
Claude Code מתיר את הפעולה אם ok הוא true. אם ok הוא false, Claude Code מטפל בחסימה באותו אופן כמו הוק prompt עם continueOnBlock: true באותו אירוע, כפי שמפורט תחת סכמת תגובה
הוקי סוכן שימושיים כשהאימות דורש בדיקה של קבצים בפועל או של פלט בדיקות, ולא רק הערכה של נתוני הקלט של ההוק לבדם.
הגדירו את type ל-"agent" וספקו מחרוזת prompt, תוך שימוש ב-$ARGUMENTS כמציין מקום לקלט ה-JSON של ההוק. שדות ההגדרה זהים לאלה של הוקי prompt, חוץ מזה שלהוקי סוכן יש timeout ברירת מחדל ארוך יותר של 60 שניות ואין שדה continueOnBlock.
סכמת התגובה היא { "ok": true } כדי להתיר, או { "ok": false, "reason": "..." } כדי לחסום. כש-ok: false, Claude Code מטפל בהוק סוכן כמו שהוא מטפל ב-הוק prompt עם continueOnBlock: true באותו אירוע. להוקי סוכן אין שדה continueOnBlock, והם לא תומכים בשדה impossible של הוק prompt.
הוק Stop זה מאמת שכל בדיקות היחידה עוברות לפני שהוא מאפשר ל-Claude לסיים:
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "agent",
"prompt": "Verify that all unit tests pass. Run the test suite and check the results. $ARGUMENTS",
"timeout": 120
}
]
}
]
}
}
כברירת מחדל, הוקים חוסמים את הביצוע של Claude עד שהם מסתיימים. למשימות ארוכות כמו פריסות, חבילות בדיקות או קריאות ל-API חיצוני, הגדירו "async": true כדי להריץ את ההוק ברקע בזמן ש-Claude ממשיך לעבוד. הוקים אסינכרוניים לא יכולים לחסום או לשלוט בהתנהגות של Claude: שדות תגובה כמו decision, permissionDecision ו-continue לא משפיעים, כי הפעולה שהם היו אמורים לשלוט בה כבר הושלמה.
כשהוק אסינכרוני מופעל, Claude Code מתחיל את תהליך ההוק וממשיך מיד בלי לחכות שהוא יסתיים. ההוק מקבל את אותו קלט JSON דרך stdin כמו הוק סינכרוני.
אחרי שתהליך הרקע יוצא, Claude Code מוסר את השדות additionalContext ו-systemMessage מתגובת ה-JSON של ההוק אל Claude בתור השיחה הבא, חוץ מפלט SessionStart חוזר. בניגוד ל-systemMessage של הוק סינכרוני, אף אחד משני השדות לא מוצג לכם.
הדפיסו את תגובת ה-JSON לבדה ב-stdout או בשורה משלה:
לבד ב-stdout: כשהתגובה היא הטקסט היחיד ב-stdout, היא יכולה להשתרע על כמה שורות, למשל פלט jq מודפס בפורמט קריא. פריסה על כמה שורות דורשת Claude Code v2.1.295 או חדש יותר.
בשורה אחת משלה: הוק אסינכרוני יכול להדפיס טקסט אחר ל-stdout כשהתגובה נכנסת בשורה אחת בפני עצמה, למשל עם jq -c.
Claude Code מאמת את תגובת ה-JSON מול אותה סכמת פלט כמו הוקים סינכרוניים, ומשמיט כל שדה שהערך שלו מסוג שגוי, למשל systemMessage שאינו מחרוזת, במקום למסור אותו. הריצו עם --debug כדי לראות אזהרה שמציינת כל שדה שהושמט.
התראות על סיום הוק אסינכרוני מוסתרות כברירת מחדל. כדי לראות אותן, הפעילו מצב verbose עם Ctrl+O או הפעילו את Claude Code עם --verbose.
ההוק הזה מתחיל חבילת בדיקות ברקע בכל פעם ש-Claude כותב קובץ, ואז מדווח את התוצאות חזרה ל-Claude כשהבדיקות מסתיימות. שמרו את הסקריפט הזה ב-.claude/hooks/run-tests-async.sh בפרויקט שלכם והפכו אותו לבר-הרצה עם chmod +x:
#!/bin/bash
# run-tests-async.sh
# Read hook input from stdin
INPUT=$(cat)
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
# Only run tests for source files
if [[ "$FILE_PATH" != *.ts && "$FILE_PATH" != *.js ]]; then
exit 0
fi
# Run tests and report results to Claude via additionalContext
RESULT=$(npm test 2>&1)
EXIT_CODE=$?
if [ $EXIT_CODE -eq 0 ]; then
MSG="Tests passed after editing $FILE_PATH"
else
MSG="Tests failed after editing $FILE_PATH: $RESULT"
fi
jq -nc --arg msg "$MSG" '{hookSpecificOutput: {hookEventName: "PostToolUse", additionalContext: $msg}}'
ואז הוסיפו את ההגדרה הזו ל-.claude/settings.json בשורש הפרויקט. הדגל async: true מאפשר ל-Claude להמשיך לעבוד בזמן שהבדיקות רצות:
להוקים אסינכרוניים יש אילוצים נוספים בהשוואה להוקים סינכרוניים:
פלט ההוק נמסר בתור השיחה הבא. אם הסשן לא פעיל, התגובה ממתינה עד האינטראקציה הבאה של המשתמש. חריג: הוק asyncRewake שיוצא עם קוד 2 מעיר את Claude מיד גם כשהסשן לא פעיל.
כל הרצה יוצרת תהליך רקע נפרד.
הוק SessionStart אסינכרוני רץ בכל פעם שהאירוע מופעל. Claude Code מדלג על פלט ההוק כשהטקסט של additionalContext ו-systemMessage תואם למה ש-Claude קיבל לאחרונה מאותו הוק, אלא אם הוק SessionStart סינכרוני הוסיף טקסט אחר מאז. Claude Code מוסר את הטקסט כשהוא משתנה, ושוב בפעם הבאה שההוק רץ אחרי compaction או /clear. לפני v2.1.295, Claude Code הוסיף את אותו טקסט לשיחה שוב בכל resume.
הוקי command מריצים פקודות shell עם הרשאות המשתמש המלאות שלכם. הם יכולים לשנות, למחוק או לגשת לכל קובץ שחשבון המשתמש שלכם יכול לגשת אליו. בדקו ובחנו את כל פקודות ההוק לפני שאתם מוסיפים אותן להגדרות.
Claude Code בודק אמון בסביבת העבודה לפני שהוא מריץ הוק כלשהו מקובץ הגדרות. מה שנחשב מהימן תלוי בסוג הסשן:
סשן אינטראקטיבי: Claude Code מעכב הוקים מכל קובץ הגדרות, כולל ~/.claude/settings.json שלכם, עד שתקבלו את תיבת הדו-שיח של אמון בסביבת העבודה עבור התיקייה, או עבור תיקיית אב שהאמון בה משתרע עליה
סשן -p או SDK: Claude Code אף פעם לא מציג את תיבת הדו-שיח ומתייחס לתיקייה כמהימנה, ולכן הוקים שנשמרו ב-.claude/settings.json של מאגר רצים בתיקייה שמעולם לא סימנתם כמהימנה
לפני שאתם מריצים בסקריפט את claude -p על מאגר שלא כתבתם, בדקו את קובצי ההגדרות ב-.claude/, התחילו עם --bare, או כבו הוקים להרצה הזו עם --settings '{"disableAllHooks": true}'. הוקי frontmatter בתת-סוכן של פרויקט פועלים לפי כלל מחמיר יותר מהוקים בקובץ הגדרות. מה רץ לפני שאתם סומכים על תיקייה מפרט כל סוג של תוכן מאגר לפי סוג סשן.
אמתו ונקו קלטים: אף פעם אל תסמכו על נתוני קלט בעיוורון
תמיד צטטו משתני shell: השתמשו ב-"$VAR" ולא ב-$VAR
חסמו path traversal: בדקו אם יש .. בנתיבי קבצים
השתמשו בנתיבים מוחלטים: ציינו נתיבים מלאים לסקריפטים. בצורת exec, השתמשו ב-${CLAUDE_PROJECT_DIR} והנתיב לא צריך ציטוט. בצורת shell, עטפו אותו במירכאות כפולות
דלגו על קבצים רגישים: הימנעו מ-.env, .git/, מפתחות וכן הלאה.
ב-Windows אפשר להריץ הוקים בודדים ב-PowerShell על ידי הגדרת "shell": "powershell" בהוק command. Claude Code מזהה אוטומטית את pwsh.exe, קובץ ההרצה של PowerShell 7 ומעלה, ונופל חזרה ל-powershell.exe עבור Windows PowerShell 5.1.
כדי להפנות לשורש הפרויקט מפקודת צורת shell של PowerShell, כתבו ${CLAUDE_PROJECT_DIR} או $env:CLAUDE_PROJECT_DIR. Claude Code משכתב את מצייני המקום ${CLAUDE_PROJECT_DIR}, ${CLAUDE_PLUGIN_ROOT} ו-${CLAUDE_PLUGIN_DATA} בפקודת צורת shell של PowerShell לצורה ${env:NAME} של PowerShell, בין אם ההוק מוגדר ב-settings.json, בתוסף או ב-skill. PowerShell אז פותר את הערך מהסביבה המיוצאת אחרי הניתוח, ולכן מציין המקום עובד בתוך מחרוזות במירכאות כפולות אבל לא בתוך מחרוזות במירכאות בודדות, שבהן PowerShell אף פעם לא מרחיב משתנים.
אל תכתבו את האיות החשוף $CLAUDE_PROJECT_DIR בהוק PowerShell. PowerShell מנתח אותו כמשתנה מקומי לא מוגדר ופותר אותו ל-$null, מה שמשאיר את נתיב הסקריפט בלי קידומת שורש הפרויקט. Claude Code לא משכתב את הצורה הזו. הוא רושם אזהרה ב-יומן הדיבוג במקום.
הדוגמה למטה מציגה הוק settings.json שמריץ סקריפט פרויקט עם הצורה $env::
פרטי הרצת הוקים נכתבים לקובץ יומן הדיבוג. הפעילו את Claude Code עם claude --debug-file <path> כדי לכתוב את היומן למיקום ידוע, או הריצו claude --debug וקראו את היומן ב-~/.claude/debug/<session-id>.txt. הדגל --debug לא מדפיס לטרמינל.
לדוגמה, הוק PostToolUse על Write שהפקודה שלו מדפיסה hook-ran מייצר רשומות כמו:
2026-07-19T02:03:24.382Z [DEBUG] Hook output does not start with {, treating as plain text
2026-07-19T02:03:24.382Z [DEBUG] "Hook PostToolUse:Write (PostToolUse) success:\nhook-ran"
כדי למצוא הוק איטי, חפשו ביומן שורות Hooks: שמסתיימות במשך זמן. ב-Claude Code v2.1.296 או חדש יותר, כל הוק command על אירוע כלי, UserPromptSubmit, SessionStart, Stop ועוד כמה אירועים משאיר אחת כשהוא מסתיים, בלי קשר למה שהדפיס. השורה נותנת את שם האירוע, מחובר בנקודתיים לשם הכלי או לערך אחר שההוק התאים אליו, ואז את פקודת ההוק בסוגריים מרובעים, התוסף שממנו הגיע אם יש, איך ההרצה הסתיימה, וכמה זמן היא לקחה, כמו ב-Hooks: PostToolUse:Write [.claude/hooks/log-write.sh] finished with status 0 (31ms). הרצה יכולה להסתיים גם כ-timed out after <N>ms, cancelled, moved to the background, או failed to start. בחלק מהאירועים, כמו Notification, SessionEnd ו-PreCompact, הוק command משאיר שורת completed with status בלי משך זמן במקום.
לפרטי התאמת הוקים מפורטים יותר, הגדירו CLAUDE_CODE_DEBUG_LOG_LEVEL=verbose כדי לראות שורות יומן נוספות כמו ספירות matcher של הוקים והתאמת שאילתות.
לפתרון בעיות נפוצות כמו הוקים שלא מופעלים, הוקי Stop שממשיכים לחסום, או שגיאות הגדרה, ראו מגבלות ופתרון בעיות במדריך. לסקירת אבחון רחבה יותר שמכסה את /context, /doctor וקדימות הגדרות, ראו דיבוג ההגדרות שלכם.