Hooks ב-Claude Code 2026: הגדרה שלב אחר שלב ו-7 דוגמאות מוכנות לשימוש
Markdown7 hooks מוכנים לשימוש עבור .claude/settings.json, מוכנים להעתקה ולהדבקה: הגנה על .env, prettier, force-push אל main, em dashes ושרת פיתוח. 4 סוגי handlers ו-31 אירועים.
קריאת המאמר המלא
Hooks ב-Claude Code הם פקודות shell, קריאות HTTP או בדיקות LLM קצרות שרצות אוטומטית לפני פעולה של Claude או אחריה. הן מוסיפות בדיקות לאירועי כלים מסוימים, מעצבות קוד אחרי עריכה ומזריקות הקשר עדכני בתחילת סשן. hook תואם של PreToolUse יכול לדחות את הקריאה הזאת; דוגמאות ה-regex הן אמצעי הגנה נוחים, ולא גבול אבטחה בכל נתיב גישה לקבצים או ל-Git. בהמשך מפורטים 4 סוגי handlers, 31 אירועי מחזור חיים, מבחן לשאלה ״מתי כלל שייך ל-hook״, 7 hooks מוכנים להעתקה אל .claude/settings.json ו-3 מלכודות שנתקלתי בהן בעצמי.
תיעוד Ailoot: API, מפתחות והגדרה.
מהם hooks ב-Claude Code?
הנקודה המרכזית
Hook הוא פקודת shell, קריאת HTTP, הנחיית LLM קצרה או subagent ש-Claude Code מריץ בתגובה לאירוע ספציפי במחזור החיים. בשונה מהוראות ב-CLAUDE.md, שהמודל עשוי להתעלם מהן או לשכוח אותן, hook רץ באותו אופן בכל פעם: הוא קוד, לא הצעה.
במשך חצי שנה השארתי את הכלל ״לעולם לא לערוך את .env ישירות״ ב-CLAUDE.md. Claude הפר אותו פעם בחודש. לא בזדון; הוא פשוט שכח בסוף סשן ארוך. פעם אחת התווסף טוקן נוסף ל-.env; בפעם אחרת משתנה עם שם כפול דרס את המשתנה שהיה בשימוש.
העברתי את הכלל ל-hook, וכך נעשה בלתי אפשרי לשכוח אותו. כאשר כלי עריכה ישיר תואם מספק נתיב של .env, ה-hook המוגדר דוחה את הקריאה הזאת. הפניה מחדש ב-Bash, סקריפטים, כלי MCP ונתיבי גישה אחרים דורשים בקרות נפרדות; הדוגמה אינה הופכת את הקובץ לבלתי ניתן לשינוי.
Hooks הם פקודות shell, נקודות קצה של HTTP או הנחיות LLM שאתם מגדירים, והן רצות אוטומטית בנקודות מסוימות במחזור החיים של Claude Code.
במילים אחרות, hook הוא פקודה שלכם ש-Claude Code מריץ באירוע מסוים. כל עריכת קובץ, הפעלה של Bash, התחלת סשן או השלמה של subagent הם אירועים שאפשר להצמיד אליהם hook.
למה זה חשוב למי שמתכנתים עם vibe coding:
- הגנו על קבצים שמכילים סודות מפני עריכות מקריות.
- הריצו prettier/eslint אוטומטית אחרי כל יצירת קוד.
- חסמו
git push --forceאל main בלי אישור מפורש. - הזריקו הקשר עדכני בתחילת כל סשן.
- תעדו את הפעולות של Claude לצורכי ביקורת.
CLAUDE.md מטפל בהקשר. Hooks מטפלים בפעולות. אלה שני דברים שונים, והבלבול ביניהם הוא הטעות העיקרית של מתחילים.
במה hooks שונים מ-CLAUDE.md ומ-skills?
הנקודה המרכזית
CLAUDE.md הוא טקסט שהמודל קורא בתחילת סשן ומנסה לפעול לפיו. Hook הוא פקודת shell שתהליך Claude Code מריץ בתגובה לאירוע, בלי תלות במודל. Skill הוא חבילת הוראות בעלת שם, ש-Claude יכול להפעיל באמצעות כלי Skill, כמו פונקציה. כל השלושה מיועדים לסוגים שונים של משימות.
התיעוד של Anthropic מסביר במפורש את ההבדל בין CLAUDE.md ל-hooks:
התוכן של CLAUDE.md נמסר כהודעת משתמש אחרי הנחיית המערכת, ולא כחלק מהנחיית המערכת. Claude קורא אותו ומנסה לפעול לפיו, אבל אין ערובה לציות קפדני.
במילים אחרות: התוכן של CLAUDE.md מגיע ל-Claude כהודעה הראשונה מהמשתמש, לא כהוראת מערכת. המודל יקרא אותו וינסה לפעול לפיו. אבל אין ערבויות, במיוחד לקראת סוף סשן ארוך, כשההקשר מתרחב והוראות ישנות נדחקות החוצה.
Hook פועל אחרת. הוא נמצא ב-settings.json, אינו תלוי במודל, ותהליך Claude Code מריץ אותו באירוע מסוים: PreToolUse, PostToolUse, SessionStart ואחרים. ה-hook פועל באירוע שהוגדר: PreToolUse תואם יכול לדחות קריאה באמצעות יציאה 2; PostToolUse פועל אחרי הפעולה ואינו מבטל אותה. שינוי קובץ אחרי עריכה הוא פעולה נפרדת.
השוואה:
| מאפיין | CLAUDE.md | Hook | Skill |
|---|---|---|---|
| היכן הוא נמצא | CLAUDE.md בשורש הפרויקט | תיקיית .claude/settings.json | תיקיית .claude/skills/ |
| מי מריץ אותו | המודל קורא אותו כחלק מהודעת משתמש | תהליך Claude Code בעת אירוע | המודל באמצעות כלי Skill |
| ערובה להרצה | לא (מאמץ מיטבי) | hook פקודה שהוגדר ותואם לאירוע מריץ קוד; הכשלים והתנהגות קוד היציאה תלויים באירוע | באמצעות קריאת מודל (עם הרשאה, אך לא ברמת shell) |
| למה הוא מיועד | הקשר לפרויקט, טון, סגנון, ניתוב | הגבלות, עיצוב, בדיקות על קבצים מסוימים | נהלים מורכבים מרובי שלבים עם פרמטרים |
| מתי הוא רץ | בכל הודעת מודל בסשן | באירוע מחזור חיים | כשהמודל מפעיל אותו |
| האם הוא יכול לחסום פעולה? | לא | ב-PreToolUse תואם: יציאה 2; ב-PostToolUse: משוב בלבד | לא |
התבנית המלאה של CLAUDE.md ו-6 כללים לקובץ שמתפתח עם הפרויקט מופיעים במדריך איך להגדיר CLAUDE.md ב-2026: תבנית מוכנה לשימוש ו-6 כללים. למדו על skills כיכולות בעלות שם במדריך Claude Code Skills: איך לבנות ספרייה משלכם.
Hook הוא הרמה הנמוכה ביותר: בלי מודל, בלי פרשנות, רק shell.
Hooks הם אחד הכלים של הנדסת הקשר, לצד Plan Mode ו-/compact.
4 סוגי hooks: Command, HTTP, Prompt, Agent — במה לבחור?
הנקודה המרכזית
ל-Claude Code יש 4 סוגי handlers. Command הוא סקריפט shell, הסוג הנפוץ ביותר. HTTP שולח בקשת POST לכתובת ה-URL שלכם, עבור צוותים ואינטגרציות. Prompt מפעיל קריאת Haiku קצרה לבדיקה סמנטית. Agent יוצר subagent עם גישה לכלים לצורך אימות מעמיק. מתחילים זקוקים ל-Command ול-Prompt; הם מכסים 90% מהמשימות.
| סוג | מה הוא עושה | מתי לבחור בו | מורכבות |
|---|---|---|---|
| Command | מריץ פקודת shell, מקבל JSON דרך stdin ומחזיר קוד יציאה ו-stdout | 90% מהמקרים: בדיקת נתיבים, עיצוב, grep בתוכן, lsof, פעולות git | נמוכה |
| HTTP | שולח בקשת POST לכתובת ה-URL שלכם עם גוף JSON ומקבל JSON בתגובה | כשהכלל שייך לצוות/CI: אימות מרכזי, לוח מצב משותף, ביקורת מרחוק | בינונית (נדרש שרת) |
| Prompt | שולח הנחיה קצרה ל-Haiku (כברירת מחדל) ומקבל כן/לא להערכה סמנטית | כש-grep אינו מספיק: ״בדקו אם הטקסט נשמע תאגידי״ | נמוכה |
| Agent | יוצר subagent עם גישה ל-Read/Grep/Glob לצורך בדיקות מרובות שלבים | אימות כבד: ״מצאו את כל הקבצים שהשתנו ובדקו שקיימות בדיקות מתאימות״ | גבוהה |
הטעות הנפוצה ביותר היא לנסות לעשות באמצעות Command משהו שמצריך Prompt. למשל, ״אל תשתמשו במקפים ארוכים בקובצי .md״ היא משימת grep, ולכן Command מתאים לה. אבל ״אל תכתבו בטון תאגידי״ היא משימה סמנטית, ולכן היא דורשת Prompt.
אם רק התחלתם, השתמשו ב-Command. כל 7 ה-hooks המוכנים לשימוש בהמשך הם מסוג Command. HTTP/Prompt/Agent יגיעו בהמשך, כשתהיו מוכנים.
היכן נמצא settings.json, ומהם 4 רמות ההגדרה?
הנקודה המרכזית
Claude Code מחפש הגדרות ב-4 מקומות: ארגוני (נפרס באמצעות MDM), משתמש (~/.claude/settings.json), פרויקט (.claude/settings.json בשורש המאגר) ומקומי (.claude/settings.local.json, שאינו ב-git). כל 4 הקבצים מתמזגים בתחילת הסשן, כאשר הרמה הנמוכה יותר גוברת.
| רמה | נתיב | מתי היא חלה | ב-git? |
|---|---|---|---|
| ארגונית | /Library/Application Support/ClaudeCode/settings.json (Mac), /etc/claude-code/settings.json (Linux) | לכל הצוות באמצעות MDM | לא |
| משתמש | ~/.claude/settings.json | לכל הפרויקטים של משתמש אחד | לא |
| פרויקט | .claude/settings.json בשורש המאגר | הפרויקט הזה, עבור כל הצוות | כן |
| מקומית | .claude/settings.local.json | רק הפרויקט הזה, ורק המשתמש הזה | לא (ב-.gitignore) |
אני שומר את 7 ה-hooks שמתוארים בהמשך ב-.claude/settings.json של הפרויקט, כך שהם נכללים אוטומטית כשמשכפלים את המאגר ו-Claude פועל לפי אותם כללים בחלון חדש. Hooks אישיים לניסויים נשמרים ב-.claude/settings.local.json, כדי שלא יפריעו לצוות.
כל 4 הקבצים מתמזגים בתחילת הסשן. אם יש סתירה בין כללים, הרמה הנמוכה יותר גוברת (מקומית על פני פרויקט, פרויקט על פני משתמש).
הדרך המהירה ביותר ליצור את ה-hook הראשון היא באמצעות התפריט האינטראקטיבי /hooks בתוך Claude Code. בחרו אירוע מהרשימה, בחרו matcher (למשל, Bash או Edit) והדביקו פקודה. Claude Code יכתוב עבורכם JSON תקין אל settings.json.
31 אירועי מחזור חיים: לאילו מהם מתחילים זקוקים?
הנקודה המרכזית
ב-Claude Code יש כרגע 31 אירועי מחזור חיים, המחולקים ל-3 תדירויות: פעם אחת לסשן (SessionStart/SessionEnd), פעם אחת לתור (UserPromptSubmit/Stop) ובכל קריאה לכלי (PreToolUse/PostToolUse). מתחילים זקוקים ל-4 מתוך 31 האירועים: PreToolUse להגבלות, PostToolUse לעריכות אוטומטיות, SessionStart להקשר ו-Stop לבדיקות סופיות.
אירועים מתרחשים בשלוש תדירויות: פעם אחת לסשן (SessionStart, SessionEnd), פעם אחת לתור (UserPromptSubmit, Stop, StopFailure) ובכל קריאה לכלי בתוך הלולאה הסוכנית (PreToolUse, PostToolUse).
חשוב להבין את שלוש התדירויות כדי לא להתבלבל:
- פעם אחת לסשן -
SessionStart,SessionEnd,Setup. אלה רצים פעם אחת כש-Claude Code נפתח ונסגר. השתמשו בהם כדי לאתחל הקשר ולנקות קבצים זמניים. - פעם אחת לתור -
UserPromptSubmit,UserPromptExpansion,Stop,StopFailure. אלה מופעלים בכל הודעה שלכם ובכל פעם שהמודל נעצר. השתמשו בהם כדי לתעד את השיחה ולבדוק את התוצאה הסופית. - בכל קריאה לכלי -
PreToolUse,PostToolUse,PostToolUseFailure,PermissionRequest,PermissionDenied,PostToolBatch,SubagentStart,SubagentStop. אלה מופעלים בכל עריכת קובץ, הפעלת Bash, קריאה או חיפוש. זו השכבה העמוסה ביותר, ובה נמצאים כללי ההגבלה, העיצוב והאימות.
הרשימה המלאה של 31 האירועים כוללת אירועים אסינכרוניים/תגובתיים: TeammateIdle, PreCompact, PostCompact, Elicitation, ElicitationResult, InstructionsLoaded, ConfigChange, CwdChanged, FileChanged, WorktreeCreate, WorktreeRemove, Notification. אלה מיועדים לתרחישים מתקדמים; דלגו עליהם בינתיים.
מבחן בן חמש שאלות: מתי כלל שייך ל-hook ומתי הוא נשאר ב-CLAUDE.md?
הנקודה המרכזית
אם כלל עוסק בפעולה (ולא בהקשר), נוגע לבטיחות/כסף/נתונים, אפשר לבדוק אותו באמצעות grep/regex, קשה לתקן את הנזק אם הוא מופר, ו-Claude כבר הפר אותו לפחות פעם אחת — הוא שייך ל-hook. אם פחות משלוש מתוך חמש התשובות הן ״כן״, הוא נשאר ב-CLAUDE.md. יישמתי את המבחן על 80 השורות שלי, ו-5 כללים עברו ל-hooks.
מבחינתי, זה פועל כחוק, לא כהצעה. צמצמתי את הבחירה בין CLAUDE.md ל-hook למבחן פשוט בן חמש שאלות. אם לפחות שלוש תשובות הן ״כן״, הכלל עובר ל-hook. פחות משלוש, והוא נשאר בטקסט.
המבחן: ״מתי כלל שייך ל-hook?״
- האם הכלל עוסק בפעולה ולא בהקשר? (״אל תריצו
rm -rf״ היא פעולה; ״יש לי פרויקט TypeScript״ הוא הקשר.) - האם הכלל עוסק בבטיחות, בכסף או בנתונים? (״אל תיגעו ב-
.env״, ״אל תפרסמו מפתחות״.) - האם אפשר לבדוק אותו באמצעות grep, regex או קוד היציאה של פקודת shell? (״אחרי עריכת
.md, בדקו שאין מקף ארוך״.) - אם הכלל יופר, האם יהיו לכך השלכות שקשה לתקן? (״force push אל main״ קשה לתקן; ״שכחתם נקודה בסוף״ קל.)
- האם כבר ראיתם את Claude שוכח את הכלל לפחות פעם אחת?
דוגמה: ״אל תשתמשו במקפים ארוכים; השתמשו רק במקפים רגילים.״ פעולה? כן. בטיחות? לא. אפשר לבדוק באמצעות grep? כן. קשה לתקן? לא. ראיתם הפרה? כן. 3 מתוך 5: הכניסו אותו ל-hook.
דוגמה נגדית: ״יש לי vibe coders, לא developers; כתבו בלי סלנג.״ פעולה? יותר הקשר. בטיחות? לא. אפשר לבדוק באמצעות regex? קשה מדי. קשה לתקן? לא. ראיתם הפרה? כן. 1 מתוך 5: השאירו אותו ב-CLAUDE.md.
חמישה מהכללים שלי עברו את המבחן. העברתי אותם ל-hooks. 75% הנותרים נשארו בקובץ הטקסט.
7 hooks מוכנים להעתקה
הנקודה המרכזית
להלן 7 hooks מוכנים לשימוש עבור .claude/settings.json: חסימת עריכות .env, הרצת prettier אוטומטית, מניעת force-push אל main, בדיקת מקפים ארוכים, פינוי פורט לפני npm run dev, ביצוע commit אוטומטי אחרי בדיקות מוצלחות והזרקת הקשר עדכני בתחילת סשן. העתיקו כל אחד לקובץ, הפעילו מחדש את Claude Code והוא יעבוד.
כל 7 ה-hooks נשמרים בקובץ .claude/settings.json אחד בשורש הפרויקט. בכל רשומה יש סוג אירוע, מסנן כלי (matcher) ופקודת shell. קוד יציאה 2 דוחה קריאת PreToolUse תואמת לפני הביצוע. ב-PostToolUse הפעולה כבר התרחשה: ה-hook מדווח משוב ואינו יכול לבטל אותה.
ברוב אירועי ה-hook, רק קוד יציאה 2 חוסם פעולה. Claude Code מתייחס לקוד יציאה 1 כשגיאה שאינה חוסמת וממשיך בפעולה, אף שב-Unix נהוג להשתמש ב-1 לציון כישלון.
exit 0 פירושו הצלחה. exit 1 פירושו שגיאה, אבל Claude ממשיך (זו האנטי-תבנית הראשונה בהמשך). ההתנהגות של exit 2 תלויה באירוע: הוא יכול לחסום PreToolUse, ואילו PostToolUse רק מדווח משוב על פעולה שכבר בוצעה.
Hook 1. הגנה מפני עריכות ישירות של .env (PreToolUse, exit 2)
חוסם ניסיונות לערוך ישירות כל קובץ שתואם ל-.env, .env.local, .env.production וכן הלאה.
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '(^|/)\\.env(\\.|$)' && { echo 'Do not edit `.env` directly. Tell me which variable to add, and I’ll open the file myself.' >&2; exit 2; } || exit 0"
}
]
}
]
}
}
מה הוא עושה: לפני כל Edit/Write/MultiEdit, הוא מקבל את נתיב הקובץ, בודק באמצעות grep אם הוא תואם לתבנית .env, ואם כן מחזיר יציאה 2 עם הודעה. Claude רואה את stderr ואומר לי: ״ניסיתי לערוך את .env, אבל ה-hook חסם אותי; אמרו לי איזה משתנה להוסיף.״
Hook 2. הרצת prettier אוטומטית אחרי כל עריכת קוד (PostToolUse, exit 0)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '\\.(ts|tsx|js|jsx|json)$' && npx prettier --write \"$FILE\" 2>/dev/null & exit 0"
}
]
}
]
}
}
מה הוא עושה: אחרי כל Edit/Write, הוא מקבל את הנתיב ואם הסיומת היא .ts/.tsx/.js/.jsx/.json, מריץ prettier ברקע באמצעות &. הוא תמיד יוצא עם 0 כי מדובר בעיצוב, לא בהגבלה. אם prettier נכשל, זה לא נורא; הקובץ נשאר כפי שהיה.
ההבדל בין hook 1 ל-hook 2 מהותי: PreToolUse + יציאה 2 היא חסימה מוחלטת לפני הפעולה. PostToolUse + יציאה 0 הוא שינוי רך אחרי הפעולה. אלה שני אופנים שונים למשימות שונות.
Hook 3. חסימת git push --force לענף main (PreToolUse, exit 2)
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "CMD=$(jq -r '.tool_input.command // empty'); [ -z \"$CMD\" ] && exit 0; echo \"$CMD\" | grep -qE 'git[[:space:]]+push' && echo \"$CMD\" | grep -qE '(\\-\\-force|\\-\\-force-with-lease|[[:space:]]-f([[:space:]]|$))' && echo \"$CMD\" | grep -qE '([[:space:]/:])main([[:space:]/:]|$)' && { echo 'Force push to main is forbidden. Create a new branch or ask me to do it manually.' >&2; exit 2; } || exit 0"
}
]
}
]
}
}
מה הוא עושה: בכל הפעלת Bash הוא בודק שהפקודה כוללת push, כוללת --force/--force-with-lease/-f ומזכירה את main. אם כל שלושת התנאים מתקיימים, הוא חוסם ומציג הודעה ברורה.
פעם הכלל הזה היה כתוב אצלי ב-CLAUDE.md באותיות גדולות. Claude עדיין הפר אותו בערך פעם בשבועיים כשביקשתי ממנו ״לעשות force push כדי לבטל את ה-commit הגרוע שלי״. ה-hook תופס את צורות הפקודה המילוליות שמוצגות, אך כינויים, סקריפטים, ענף יעד משתמע או לקוח Git אחר יכולים לעקוף את בדיקת המחרוזת. אכפו הגנה על main בשרת המרוחק והגבילו את פרטי הגישה הזמינים לסוכן.
Hook 4. חסימת מקפים ארוכים בקובצי טקסט (PostToolUse, exit 2)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "FILE=$(jq -r '.tool_input.file_path // empty'); [ -z \"$FILE\" ] && exit 0; echo \"$FILE\" | grep -qE '\\.(md|mdx|tsx?)$' && grep -q $'\\xe2\\x80\\x94' \"$FILE\" && { echo \"File $FILE contains an em dash (U+2014). Replace it with a regular hyphen (U+002D).\" >&2; exit 2; } || exit 0"
}
]
}
]
}
}
מה הוא עושה: PostToolUse עם יציאה 2 מדווח ל-Claude על כישלון בדיקה אחרי העריכה. הוא אינו מבטל או מונע את הכתיבה. אם Claude ערך קובץ והשאיר בו מקף ארוך, ה-hook נכשל, Claude מקבל משוב ומנסה שוב. אחרי 2–3 סשנים, Claude מפסיק להוסיף את התו הזה לגמרי.
שימו לב ש-grep מחפש באופן ספציפי את תו המקף הארוך (U+2014) באמצעות $'\xe2\x80\x94', סימון Bash לכתיבתו כבתים של UTF-8. אם פשוט תכתבו grep -q '-', הוא יתפוס מקפים רגילים וירוץ בכל קובץ. תו בלתי נראה משבש את כל הלוגיקה.
Hook 5. פינוי פורט 3000 לפני npm run dev (PreToolUse, exit 0)
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "CMD=$(jq -r '.tool_input.command // empty'); [ -z \"$CMD\" ] && exit 0; echo \"$CMD\" | grep -qE '(npm|pnpm|yarn)[[:space:]]+run[[:space:]]+dev' && { lsof -ti:3000 | xargs -r kill -9 2>/dev/null; echo 'Port 3000 freed before launch' >&2; }; exit 0"
}
]
}
]
}
}
מה הוא עושה: לפני כל npm run dev (או pnpm/yarn), הוא הורג את התהליך בפורט 3000. הוא תמיד יוצא עם 0 כי זו הכנה, לא הגבלה. כך נמנעים מתרחישים שבהם Claude רואה ש״הפורט בשימוש״, חושב שיש בעיית קוד ומתחיל לתקן, כשלמעשה השרת הישן פשוט נשאר פעיל.
Hook 6. יצירת commit אוטומטית אחרי בדיקות מוצלחות (PostToolUse, exit 0)
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "INPUT=$(cat); CMD=$(printf '%s' \"$INPUT\" | jq -r '.tool_input.command // empty') || exit 1; EXIT=$(printf '%s' \"$INPUT\" | jq -r '.tool_response.exit_code // empty') || exit 1; case \"$CMD\" in 'npm test'|'pnpm test'|'yarn test') ;; *) exit 0 ;; esac; [ \"$EXIT\" = \"0\" ] || exit 0; git diff --cached --quiet || { echo 'Existing staged changes: review manually' >&2; exit 0; }; git add -- src/orders.ts tests/orders.test.ts || exit 1; git diff --cached --quiet && exit 0; git commit -m 'tests: checkpoint after successful run'"
}
]
}
]
}
}
מה הוא עושה: קורא את קלט ה-JSON מ-stdin פעם אחת ומקבל רק את פקודות הבדיקה הפשוטות והמדויקות שמוצגות. ממשיך רק כאשר tool_response.exit_code שנמסר הוא אפס במפורש; אם הגרסה המותקנת אינה מספקת את השדה, הוא מדלג על commit במקום לנחש הצלחה. החליפו את src/orders.ts ואת tests/orders.test.ts בקבצים המדויקים שבבעלות המשימה. שינויים שכבר נמצאים ב-staging עוצרים את המתכון כדי לא לכלול עבודה לא קשורה. הוספה שנכשלה עוצרת אותו, diff ריק אינו יוצר commit, ובדיקות commit רגילות נשארות פעילות. בדקו קלטי הצלחה, כישלון ותוצאה חסרה באופן לא מקוון לפני ההפעלה.
אנטי-תבנית: הוספת git commit --no-verify לכל Edit. השאירו את בדיקות ה-commit פעילות. אם בדיקה מפעילה שוב את האוטומציה באופן רקורסיבי, צמצמו את הטריגר או שנו את הבדיקה; אל תעקפו אימות כברירת מחדל. בדקו את ה-diff שב-staging ואת בעלות המשימה לפני הפעלת commits אוטומטיים.
Hook 7. הזרקת הקשר עדכני בתחילת סשן (SessionStart עם additionalContext)
{
"hooks": {
"SessionStart": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "BRANCH=$(git symbolic-ref --short HEAD 2>/dev/null || echo 'no-branch'); STATUS=$(git status --short 2>/dev/null | head -10); echo \"{\\\"additionalContext\\\":\\\"Current branch: $BRANCH. Uncommitted changes:\\n$STATUS\\\"}\""
}
]
}
]
}
}
מה הוא עושה: בתחילת הסשן הוא אוסף את ענף Git הנוכחי ואת רשימת השינויים שלא בוצע להם commit, ואז מחזיר JSON עם שדה additionalContext. Claude Code מזריק את הטקסט הזה להודעת המערכת הראשונה, כך ש-Claude יודע מההתחלה היכן הוא נמצא ומה נותר מהסשן הקודם.
השתמשו ב-additionalContext למידע ש-Claude צריך לדעת על מצב הסביבה או על פעולה שהושלמה זה עתה: מצב הסביבה (הענף הנוכחי, יעד פריסה, דגלי תכונות פעילים), כללי פרויקט מותנים (איזו פקודת בדיקה חלה על הקובץ שנערך זה עתה), נתונים חיצוניים (בעיות פתוחות שהוקצו לכם, תוצאות CI אחרונות).
אפשרויות להרחבת ה-hook הזה: להביא את ה-commit האחרון ואת התיאור שלו, את מצב GitHub Actions, את הספרינט הפעיל ב-Linear/Jira ובעיות פתוחות במאגר הנוכחי.
3 מלכודות hooks שכמעט כל אחד נתקל בהן
הנקודה המרכזית
המלכודת הראשונה: hook עם יציאה 1 עובר בשקט, ו-Claude מתעלם מהשגיאה. השנייה: עבודה כבדה ב-hook נהרגת אחרי timeout של 60 שניות. השלישית: hook רואה רק את משתני הסביבה מ-~/.zshrc, ולא את .env של הפרויקט. כל אחת נפתרת בשורה אחת, אבל בלי להכיר את המלכודות האלה אפשר לחשוב ש״hooks לא עובדים״.
מלכודת 1. Hook עם יציאה 1 עובר בשקט
המלכודת המסוכנת ביותר. במשך שבוע חשבתי שמנגנון ההגנה על .env עובד, אבל התברר שב-hook השתמשתי ב-jq -r '.tool_input.file_path' בלי לבדוק ערך null. כש-tool_input היה ריק, jq יצא עם קוד 1. Claude התייחס ליציאה 1 כאל ״שגיאת hook, ממשיכים״, ולכן הפעולה בוצעה. לא הבנתי למה עדיין נגעו ב-.env. הבנתי את הסיבה רק כשהרצתי את ה-hook ידנית בטרמינל עם קלט ריק.
הפתרון הוא כלל אחד: התחילו כל hook בבדיקה לערך null, וסיימו אותו ב-|| exit 0. כל יציאה בלתי צפויה תוביל אז ליציאה ״בטוחה״ במקום לעבור בשקט.
# Safe start and end template:
FILE=$(jq -r '.tool_input.file_path // empty')
[ -z "$FILE" ] && exit 0
# ... your logic ...
exit 0 # or || exit 0 on one line
מלכודת 2. Hooks איטיים נהרגים בגלל timeout
היה לי hook שהריץ eslint --fix על כל הקובץ אחרי Edit. עיבוד של קבצים גדולים (1000+ שורות) ארך 8–10 שניות. ברירת המחדל של timeout ל-hook ב-Claude Code היא 60 שניות, ולכן חשבתי שאני בתוך המגבלה. אבל כשמתבצעות כמה פעולות Edit בתוך דקה, ה-hooks מצטברים ונכנסים לתור, וחלקם פשוט מדולגים. הבנתי זאת רק כשראיתי בלוג ״hook timed out״.
פתרון: אם hook דורש עבודה כבדה, הריצו אותה ברקע. eslint --fix "$FILE" & בלי להמתין לתוצאה. כך ה-hook מחזיר יציאה 0 בתוך אלפיות שנייה, בזמן שהעבודה עצמה מתבצעת ברקע.
# Heavy operation in background:
npx eslint --fix "$FILE" &
exit 0
מלכודת 3. Hook אינו יכול לראות משתני סביבה של הפרויקט
חשבתי ש-process.env יהיה זמין ב-hook כמו באפליקציית Node.js. זה לא המצב. ה-hook רץ ב-shell שתהליך Claude Code האב מפעיל, והוא רואה רק את מה שנמצא ב-~/.zshrc או ב-~/.bashrc, בתוספת מה ש-Claude Code מעביר במפורש. אם ה-hook שלכם תלוי ב-OPENAI_API_KEY מתוך .env, תצטרכו לקרוא את .env ידנית.
פתרון: קראו במפורש את .env בפקודת ה-hook.
# Passing project env into hook:
cd "$PWD" && source .env && curl -H "Authorization: Bearer $OPENAI_API_KEY" ...
# Or with dotenv:
dotenv -e .env -- node my-validator.js
זה כואב במיוחד במונורפו, שבו לכל חבילה יש קובצי .env משלה. פתרו זאת באמצעות העברה של PWD והרצה מפורשת של cd "$PWD" בתחילת הפקודה.
איך בודקים hooks לפני ביצוע commit?
הנקודה המרכזית
Hook הוא פקודת shell. אפשר להריץ אותו ידנית בטרמינל עם stdin מזויף, לבדוק את קוד היציאה ואת stderr, ולעשות את כל זה לפני ש-Claude Code מריץ אותו. כך חוסכים שעות של ניפוי שגיאות ומתגוננים מפני hooks שחוסמים את הפעולה של עצמם.
תרחיש בדיקה בסיסי. קחו את פקודת ה-hook מתוך ה-JSON, פתחו טרמינל והעבירו אליו את ה-JSON ש-Claude Code היה שולח:
# Test hook 1 (protect .env):
echo '{"tool_input":{"file_path":".env"}}' | bash -c '
FILE=$(jq -r ".tool_input.file_path // empty")
[ -z "$FILE" ] && exit 0
echo "$FILE" | grep -qE "(^|/)\.env(\.|$)" && {
echo "BLOCKED" >&2
exit 2
} || exit 0
'
echo "Exit code: $?"
אמורים לראות BLOCKED ב-stderr ו-Exit code: 2. אם מתקבל 0, ה-regex לא עובד; תקנו את grep.
תרחישים לבדיקה:
- מסלול הצלחה - הקובץ אמור להיחסם.
.envעבור hook 1,git push --force mainעבור hook 3. - מסלול שלילי - הקובץ לא אמור להיחסם.
README.mdעבור hook 1,git push origin feature-branchעבור hook 3. - מקרי קצה - קלט ריק, ערכי null, תווים בלתי צפויים. ה-hook אמור להחזיר יציאה 0 או להיכשל עם שגיאה ברורה, ולא לעבור בשקט.
היכן לשים hooks ניסיוניים. לא ב-.claude/settings.json, אלא ב-.claude/settings.local.json (שאינו ב-git). שימו שם hooks חדשים תחת PostToolUse עם echo במקום הפעולה האמיתית, בדקו אם הם מופעלים ואז העבירו אותם אל settings.json של סביבת הייצור.
// Experiment in settings.local.json - writes to /tmp/hook-debug.log:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit",
"hooks": [
{
"type": "command",
"command": "echo \"[hook fired] $(date) $(jq -r '.tool_input.file_path // \"?\"')\" >> /tmp/hook-debug.log"
}
]
}
]
}
}
אחרי 5–10 עריכות ב-Claude Code, פתחו את /tmp/hook-debug.log כדי לראות אילו קבצים הפעילו את ה-hook. אם הוא ריק, ה-matcher לא מתאים; תקנו את ה-regex.
מה הלאה?
הנקודה המרכזית
התחילו ב-hooks של PostToolUse שיוצאים עם 0; הם הבטוחים ביותר ואינם חוסמים דבר. אחרי שבוע, הוסיפו hook ראשון מסוג PreToolUse עם יציאה 2 כדי להגן על .env או למנוע force-push. אחרי שבועיים, CLAUDE.md יצטמצם מחוזה בן 200 שורות לתיאור הקשר קצר בן 50–80 שורות, ובדיקות אירועים נבחרות יעברו ל-hooks, בעוד שמגבלות גישה קשיחות ייאכפו בנפרד באמצעות הרשאות, sandbox והגנות בשרת המרוחק.
5 צעדים לשבוע הקרוב:
- חפשו ב-
CLAUDE.mdמילים כמו ״לעולם לא״, ״אסור״, ״תמיד״ ו״חייבים״. כל כלל כזה מועמד ל-hook. אם כלל מנוסח כהוראה, קובץ הטקסט לא יאכוף אותו. - התחילו ב-PostToolUse + exit 0. אלה הבטוחים ביותר: הם מבצעים שינוי אך אינם חוסמים דבר. Prettier (hook 2), הריגת שרת הפיתוח (hook 5), יצירת commit אוטומטית אחרי בדיקות (hook 6).
- רק כשתהיו בטוחים, הוסיפו PreToolUse + exit 2 ראשון. למשל, הגנו על
.env(hook 1) או מנעו force-push (hook 3). זו חסימה קשיחה, וטעות בפקודת grep עלולה לחסום גם אתכם. - בדקו hooks ידנית לפני ביצוע commit (ראו בסעיף הקודם). כך חוסכים שעות של ניפוי שגיאות.
- שמרו hooks ניסיוניים ב-
settings.local.json. שימו בהםechoבמקום הפעולה האמיתית.
לאחר שתגדירו את ה-hooks, השלב הבא באשכול הוא איך לבטל שינויים ב-Claude Code, למקרה ש-hook יאפשר לפעולה מסוכנת לעבור. אם תרצו ש-Claude יזכור את מבנה הפרויקט בין סשנים, בנו מוח שני ב-Claude Code (תיקיית business/ + מאגר ידע מקושר). וכדי לתת שמות ל-skills של הפרויקט ולהשתמש בהם שוב, ראו Claude Code Skills.
מקורות
אם אתם זקוקים לגישה לרשתות עצביות דרך Ailoot, בקרו ב-Ailoot.
פרטים נוספים
שאלות ותשובות: Hooks ב-Claude Code 2026: הגדרה שלב אחר שלב ו-7 דוגמאות מוכנות לשימוש
למה hook חייב לקרוא את קלט ה-JSON רק פעם אחת?
stdin הוא זרם: תהליך jq הראשון צורך אותו, ולקריאות הבאות נשאר EOF. שמרו את הקלט פעם אחת וחלצו ממנו את שדות הפקודה והתוצאה. תוצאה חסרה או לא ידועה אינה מאומתת, ולכן יש לדלג על commit אוטומטי.
האם דוגמאות ה-regex של hooks יוצרות גבול אבטחה?
לא. הן בודקות אירועים מסוימים ומחרוזות פקודה מזוהות. הפניה מחדש במעטפת, כינויים, סקריפטים, כלי MCP או נתיב כתיבה אחר עשויים לעקוף אותן; השתמשו בפרטי גישה מוגבלים, בהרשאות מערכת קבצים, ב-sandbox ובענפים מוגנים למגבלות קשיחות.