Claude Code Hooks چیست؟ آموزش ساخت گیت خودکار برای فرمت، تست و فایلهای حساس
Hooks در Claude Code فرمانها و کنترلهای قطعی را در نقاط مشخص چرخه عامل اجرا میکنند. در این راهنما PreToolUse، PostToolUse و Stop را با نمونههای امن برای فرمت، تست و حفاظت از فایلها پیاده میکنیم.
وقتی از Claude Code میخواهید پس از ویرایش فایل، Formatter را اجرا کند یا پیش از دستزدن به فایل حساس توقف کند، اتکا به یک جمله در Prompt همیشه کافی نیست. Hook یک نقطه اجرای مشخص در چرخه Claude Code است که با رخدادن Event، فرمان یا Handler تعریفشده را اجرا میکند.
Hook برای کار قطعی مناسب است: فرمت کد، ثبت Audit، اعلان نیاز به ورودی، اعتبارسنجی فایل یا جلوگیری از یک عملیات مشخص. تصمیمهای نیازمند قضاوت همچنان باید به انسان یا سازوکار مناسب سپرده شوند. در این راهنما از یک Hook کوچک شروع میکنیم و آن را با Scope محدود، خروجی قابلفهم و رفتار Fail-closed ایمن میسازیم.
Claude Code Hooks چیست و کجا اجرا میشود؟
Hook یک Handler تعریفشده توسط کاربر است که در Eventهای چرخه Claude Code فعال میشود. Handler میتواند Command، درخواست HTTP، MCP tool، Prompt یا Agent باشد. Command hook ورودی JSON رویداد را از Standard Input میگیرد، آن را بررسی میکند و با Exit Code یا JSON ساختیافته نتیجه را به Claude Code برمیگرداند.
برخلاف یک دستور طبیعی که مدل ممکن است با توجه به Context تفسیر کند، Event و Matcher تعیین میکنند Hook در چه لحظهای اجرا شود. این ویژگی Hooks را برای کنترلهای تکراری و قابلآزمون مناسب میکند؛ بااینحال Script شما کد واقعی است و با مجوز سیستم اجرا میشود، پس باید مانند بخشی از زنجیره تأمین نرمافزار بازبینی شود.
Eventهای مهم برای شروع
| Event | زمان اجرا | کاربرد مناسب | آیا میتواند متوقف کند؟ |
|---|---|---|---|
SessionStart | شروع یا ادامه نشست | بارگذاری Context پویا یا Environment | بسته به خروجی |
UserPromptSubmit | پیش از پردازش Prompt | افزودن Context یا اعتبارسنجی ورودی | بله |
PreToolUse | پیش از اجرای Tool | حفاظت فایل و کنترل فرمان | بله |
PermissionRequest | هنگام درخواست مجوز | تصمیم تکمیلی درباره Permission | بله |
PostToolUse | پس از موفقیت Tool | فرمت، ثبت نتیجه و بررسی سریع | خروجی را بازخورد میدهد |
PostToolUseFailure | پس از شکست Tool | ثبت خطا و راهنمای بازیابی | خیر؛ خطا رخ داده است |
Stop | پیش از پایان پاسخ عامل | گیت تکمیل و کنترل Test | بله |
Notification | هنگام اعلان Claude Code | اعلان Desktop یا پیام تیمی | معمولاً خیر |
برای اولین پیادهسازی فقط یک Event انتخاب کنید. اتصال یک Script پرهزینه به همه Toolها هم سرعت را کم میکند و هم Debug را دشوار میسازد. اگر هدف فرمت فایل پس از ویرایش است، PostToolUse با Matcher محدود به Edit|Write انتخاب روشنتری است.
ساخت اولین Hook در settings.json
Hook را میتوان در Settings کاربر، پروژه، فایل محلی، Managed policy، Plugin یا Frontmatter یک Skill تعریف کرد. برای Hook مشترک تیم از .claude/settings.json استفاده کنید؛ برای آزمایش شخصی همان پروژه، .claude/settings.local.json مناسبتر است و نباید Commit شود.
نمونه زیر بعد از Edit یا Write یک Script پروژه را اجرا میکند. مسیر با متغیر CLAUDE_PROJECT_DIR ساخته شده تا به Current directory شکننده وابسته نباشد.
{ "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-changed.sh" } ] } ] }}Matcher نام Tool را فیلتر میکند، نه مسیر فایل را. اگر میخواهید فقط فایلهای .cs یا پوشه src بررسی شوند، Script باید مقدارهایی مانند tool_input.file_path را از JSON ورودی بخواند و خودش Scope را اعتبارسنجی کند.
چرا Script جدا بهتر است؟
قرار دادن Logic طولانی داخل رشته JSON، Escape و Review را سخت میکند. Script جدا را میتوان مستقل Test، Lint و Version کرد. Settings فقط Event، Matcher، نوع Handler و مسیر Script را نگه میدارد؛ این جداسازی خطای Configuration را کم میکند.
نمونه PreToolUse برای حفاظت فایلها
یک کاربرد مهم، جلوگیری از Edit یا Write روی فایلهای حساس است. Script زیر ورودی را میخواند، مسیر مقصد را استخراج میکند و در صورت تطبیق با الگوهای محافظتشده با Exit Code 2 عملیات را Block میکند.
#!/usr/bin/env bashset -euo pipefail input="$(cat)"file_path="$(printf '%s' "$input" | jq -r '.tool_input.file_path // empty')" case "$file_path" in *.env|*.env.*|*/secrets/*|*/.git/*) echo "Blocked protected path: $file_path" >&2 exit 2 ;;esac exit 0این Script را با PreToolUse و Matcher برابر Edit|Write ثبت کنید. پیام Standard Error باید علت Block را روشن بگوید تا عامل بتواند مسیر دیگری انتخاب کند. روی macOS و Linux فایل باید Executable باشد؛ در ویندوز میتوانید معادل PowerShell را با ابزار اختصاصی PowerShell Hooks بسازید.
Exit Code و خروجی Hook را درست بفهمیم
| خروجی | معنای عمومی | کاربرد |
|---|---|---|
| Exit 0 | اجرای موفق | اجازه ادامه یا ارائه Context از stdout |
| Exit 2 | Block قطعی در Eventهای پشتیبانیشده | جلوگیری از Tool یا توقف تکمیل |
| Exit دیگر | خطای غیرمسدودکننده یا وابسته به Event | گزارش اشکال Hook |
| JSON ساختیافته | Decision و Context دقیق | کنترل پیشرفته Permission و نتیجه |
رفتار دقیق Exit 2 به Event بستگی دارد؛ آن را از Reference همان Event بررسی کنید. Script نباید خروجی Debug یا Banner غیرضروری روی stdout بنویسد، چون ممکن است با JSON ساختیافته تداخل کند یا وارد Context شود. Log تشخیصی را به stderr یا فایل Audit کنترلشده بفرستید.
Hook مسدودکننده و Permission چه نسبتی دارند؟
PreToolUse پیش از بررسی Permission اجرا میشود. Hook مسدودکننده میتواند حتی در حالت مجوز باز، Tool را متوقف کند؛ اما Allow از Hook نمیتواند Deny موجود در Settings را دور بزند. برای امنیت از Defense in depth استفاده کنید: Deny ساده و ثابت در Permission، و Validation پویا در Hook.
سه سناریوی کاربردی و کمریسک
فرمت خودکار پس از ویرایش
با PostToolUse فقط فایل تغییرکرده را Formatter کنید، نه کل Repository را. پسوند را Allowlist، مسیر را Canonicalize و Timeout کوتاه تعیین کنید. اگر Formatter فایل را تغییر داد، نتیجه را به عامل برگردانید تا Diff نهایی را ببیند.
اعلان نیاز به ورودی
Event Notification میتواند اعلان Desktop ایجاد کند تا لازم نباشد Terminal را دائم نگاه کنید. پیام اعلان را محدود کنید؛ Prompt، مسیر خصوصی یا محتوای فایل را به سرویس ثالث ارسال نکنید.
گیت تست پیش از Stop
Hook مربوط به Stop میتواند بررسی کند Testهای ضروری اجرا شدهاند. از Loop جلوگیری کنید: وضعیت اجرای قبلی را در ورودی بشناسید و اگر Failure واقعی وجود دارد علت مشخص بدهید. Test بسیار طولانی را در هر Stop اجرا نکنید؛ Suite متناسب با فایلهای تغییرکرده انتخاب کنید.
Command، Prompt، Agent یا HTTP Hook؟
- Command: انتخاب پیشفرض برای کنترل قطعی، سریع و قابلآزمون است.
- Prompt: وقتی تصمیم فقط از داده ورودی و با قضاوت زبانی ممکن است کاربرد دارد.
- Agent: برای بررسی نیازمند خواندن فایل و اجرای ابزار مناسب است، اما آزمایشی و پرهزینهتر است.
- HTTP: برای Audit مرکزی یا سرویس مشترک مفید است و باید محدودیت URL، احراز هویت و Timeout داشته باشد.
- MCP tool: زمانی مناسب است که تصمیم یا اقدام در ابزار MCP موجود انجام میشود.
برای Workflow تولیدی، ابتدا Command hook کوچک بسازید. اگر Logic بدون مدل قابل نوشتن است، Prompt یا Agent اضافه نکنید. خروجی قطعی، هزینه کمتر و رفتار قابلتکرار دارد.
امنیت Hooks؛ کد مخزن را خودکار اجرا نکنید
Hookها با Credential و دسترسی کاربر فعلی اجرا میشوند. مخزن ناشناس ممکن است Settings یا Script مخرب پیشنهاد کند. Workspace Trust، Code Review و محدودکردن Hookهای مجاز در سطح سازمان اهمیت دارند. فرمان Hook را Quote کنید و ورودی JSON را داده غیرقابلاعتماد بدانید.
- Script و Settings را مانند کد Production Review کنید.
- مسیر ورودی را Canonicalize و سپس با ریشه پروژه مقایسه کنید.
- از ساختن Command با Concatenation ورودی پرهیز کنید.
- Secret را در آرگومان Command یا Log قرار ندهید.
- Network را فقط برای Hostهای لازم باز کنید.
- Timeout و حجم خروجی را محدود نگه دارید.
- برای Hookهای سازمانی از Managed settings استفاده کنید.
- نسخه Dependencyهای Script را Pin و بهروزرسانی را بازبینی کنید.
اگر هدفتان فقط محدودکردن ابزار یا فایل است، ابتدا Permission و Sandbox را تنظیم کنید. مقاله راهنمای CLAUDE.md نیز تفاوت دستور رفتاری با کنترل فنی را توضیح میدهد.
تست Hook پیش از اشتراکگذاری
- Script را با Fixture JSON مستقل اجرا کنید.
- مسیر مجاز، ممنوع، خالی و خارج از پروژه را آزمایش کنید.
- Exit Code، stdout و stderr را جدا بررسی کنید.
- Hook را ابتدا در
settings.local.jsonفعال کنید. - با
/hooksثبت Event و Matcher را تأیید کنید. - یک Tool call واقعی کمریسک اجرا کنید.
- زمان اجرا و Failure path را ثبت کنید.
- پس از Review تیمی به Settings مشترک منتقل کنید.
اگر Hook اجرا نمیشود، Case حساس Matcher، نام Event، Executable بودن Script و مسیر مبتنی بر CLAUDE_PROJECT_DIR را بررسی کنید. برای خطای JSON، تمام خروجی غیر JSON روی stdout را حذف کنید. برای Timeout، Scope کار را کوچک یا اجرای غیرهمگام را فقط با درک محدودیتها انتخاب کنید.
Hooks در برابر CLAUDE.md و Skills
Hook تضمین میکند Handler در Event مشخص فراخوانی شود. CLAUDE.md Context پایدار و قرارداد پروژه را به مدل میدهد. Skill یک فرایند یا دانش قابلاستفاده مجدد است و Subagent Context جدا برای کار مستقل دارد. اگر هدف «همیشه بعد از Edit Formatter اجرا شود» است، Hook مناسب است؛ اگر هدف «سبک نامگذاری تیم را بدان» باشد CLAUDE.md مناسبتر است.
برای ساخت Workflow تخصصی چندمرحلهای، راهنمای Agent Skills را ببینید. Hook میتواند آغاز یا پایان آن Workflow را کنترل کند، اما نباید تمام دانش فرایند را در یک Script مبهم پنهان کند.
اشتباههای رایج
- Matcher خالی که Hook را برای هر Tool اجرا میکند.
- فرمتکردن کل Repository پس از هر Edit کوچک.
- اعتماد به مسیر ورودی بدون Canonicalization.
- چاپ Log روی stdout کنار JSON ساختیافته.
- استفاده از Hook برای جایگزینی کامل Permission.
- ارسال Prompt یا کد خصوصی به HTTP endpoint.
- اجرای Test طولانی در هر Stop و ایجاد Loop.
- Commit کردن Hook آزمایشنشده برای کل تیم.
چکلیست انتشار Hook تیمی
- Event و Matcher کمترین Scope لازم را دارند.
- Script مستقل Test شده و ورودی را Validate میکند.
- Exit Code هر مسیر مشخص است.
- پیام Block دلیل و راه اصلاح دارد.
- Timeout و Failure path تعریف شدهاند.
- Secret در Command، stdout و Log نیست.
- Permission و Sandbox مستقل تنظیم شدهاند.
- مالک، Reviewer و روش غیرفعالسازی مشخصاند.
/hooksConfiguration نهایی را نمایش میدهد.
جمعبندی
Claude Code Hooks بهترین انتخاب برای اتصال کنترل قطعی به چرخه عامل هستند: پیش از Tool جلوی مسیر ممنوع را میگیرند، پس از Edit فرمت را اجرا میکنند و پیش از پایان، گیت تکمیل را بررسی میکنند. کیفیت Hook به انتخاب Event درست، Matcher محدود و Script کوچک وابسته است.
با یک سناریوی کمریسک شروع کنید، Script را خارج از Claude Code Test کنید و سپس آن را محلی فعال کنید. امنیت را به Hook واگذار نکنید؛ Permission، Sandbox، Workspace Trust و Review تیمی باید لایههای مستقل باقی بمانند.
امروز یک Hook محلی و کمریسک برای فرمتکردن فقط یک نوع فایل بسازید، آن را با Fixture JSON آزمایش کنید و پیش از انتقال به تنظیمات مشترک تیم، Event، Matcher، خروجی و Failure path را در /hooks بازبینی کنید.