وبلاگ / راهنمای مسیر یادگیری و فناوری
راهنمای مسیر یادگیری و فناوری

Claude Code Hooks چیست؟ آموزش ساخت گیت خودکار برای فرمت، تست و فایل‌های حساس

Hooks در Claude Code فرمان‌ها و کنترل‌های قطعی را در نقاط مشخص چرخه عامل اجرا می‌کنند. در این راهنما PreToolUse، PostToolUse و Stop را با نمونه‌های امن برای فرمت، تست و حفاظت از فایل‌ها پیاده می‌کنیم.

· ۱۹ بازدید

وقتی از می‌خواهید پس از ویرایش فایل، Formatter را اجرا کند یا پیش از دست‌زدن به فایل حساس توقف کند، اتکا به یک جمله در Prompt همیشه کافی نیست. Hook یک نقطه اجرای مشخص در چرخه است که با رخ‌دادن Event، فرمان یا Handler تعریف‌شده را اجرا می‌کند.

Hook برای کار قطعی مناسب است: فرمت کد، ثبت Audit، اعلان نیاز به ورودی، اعتبارسنجی فایل یا جلوگیری از یک عملیات مشخص. تصمیم‌های نیازمند قضاوت همچنان باید به انسان یا سازوکار مناسب سپرده شوند. در این راهنما از یک Hook کوچک شروع می‌کنیم و آن را با Scope محدود، خروجی قابل‌فهم و رفتار Fail-closed ایمن می‌سازیم.

چیست و کجا اجرا می‌شود؟

Hook یک Handler تعریف‌شده توسط کاربر است که در Eventهای چرخه فعال می‌شود. Handler می‌تواند Command، درخواست HTTP، MCP tool، Prompt یا Agent باشد. Command hook ورودی JSON رویداد را از Standard Input می‌گیرد، آن را بررسی می‌کند و با Exit Code یا JSON ساخت‌یافته نتیجه را به برمی‌گرداند.

برخلاف یک دستور طبیعی که مدل ممکن است با توجه به Context تفسیر کند، Event و Matcher تعیین می‌کنند Hook در چه لحظه‌ای اجرا شود. این ویژگی را برای کنترل‌های تکراری و قابل‌آزمون مناسب می‌کند؛ بااین‌حال Script شما کد واقعی است و با مجوز سیستم اجرا می‌شود، پس باید مانند بخشی از زنجیره تأمین نرم‌افزار بازبینی شود.

Eventهای مهم برای شروع

Eventزمان اجراکاربرد مناسبآیا می‌تواند متوقف کند؟
SessionStartشروع یا ادامه نشستبارگذاری Context پویا یا Environmentبسته به خروجی
UserPromptSubmitپیش از پردازش Promptافزودن Context یا اعتبارسنجی ورودیبله
PreToolUseپیش از اجرای Toolحفاظت فایل و کنترل فرمانبله
PermissionRequestهنگام درخواست مجوزتصمیم تکمیلی درباره Permissionبله
PostToolUseپس از موفقیت Toolفرمت، ثبت نتیجه و بررسی سریعخروجی را بازخورد می‌دهد
PostToolUseFailureپس از شکست Toolثبت خطا و راهنمای بازیابیخیر؛ خطا رخ داده است
Stopپیش از پایان پاسخ عاملگیت تکمیل و کنترل Testبله
Notificationهنگام اعلان اعلان 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 شکننده وابسته نباشد.

settings.jsonJSON
{  "hooks": {    "PostToolUse": [      {        "matcher": "Edit|Write",        "hooks": [          {            "type": "command",            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-changed.sh"          }        ]      }    ]  }}
UTF-8JSON

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 می‌کند.

protect-files.shBash
#!/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
UTF-8Bash

این Script را با PreToolUse و Matcher برابر Edit|Write ثبت کنید. پیام Standard Error باید علت Block را روشن بگوید تا عامل بتواند مسیر دیگری انتخاب کند. روی macOS و Linux فایل باید Executable باشد؛ در ویندوز می‌توانید معادل PowerShell را با ابزار اختصاصی PowerShell بسازید.

Exit Code و خروجی Hook را درست بفهمیم

خروجیمعنای عمومیکاربرد
Exit 0اجرای موفقاجازه ادامه یا ارائه Context از stdout
Exit 2Block قطعی در 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 اضافه نکنید. خروجی قطعی، هزینه کمتر و رفتار قابل‌تکرار دارد.

؛ کد مخزن را خودکار اجرا نکنید

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 پیش از اشتراک‌گذاری

  1. Script را با Fixture JSON مستقل اجرا کنید.
  2. مسیر مجاز، ممنوع، خالی و خارج از پروژه را آزمایش کنید.
  3. Exit Code، stdout و stderr را جدا بررسی کنید.
  4. Hook را ابتدا در settings.local.json فعال کنید.
  5. با /hooks ثبت Event و Matcher را تأیید کنید.
  6. یک Tool call واقعی کم‌ریسک اجرا کنید.
  7. زمان اجرا و Failure path را ثبت کنید.
  8. پس از Review تیمی به Settings مشترک منتقل کنید.

اگر Hook اجرا نمی‌شود، Case حساس Matcher، نام Event، Executable بودن Script و مسیر مبتنی بر CLAUDE_PROJECT_DIR را بررسی کنید. برای خطای JSON، تمام خروجی غیر JSON روی stdout را حذف کنید. برای Timeout، Scope کار را کوچک یا اجرای غیرهمگام را فقط با درک محدودیت‌ها انتخاب کنید.

در برابر 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 و روش غیرفعال‌سازی مشخص‌اند.
  • /hooks Configuration نهایی را نمایش می‌دهد.

جمع‌بندی

بهترین انتخاب برای اتصال کنترل قطعی به چرخه عامل هستند: پیش از Tool جلوی مسیر ممنوع را می‌گیرند، پس از Edit فرمت را اجرا می‌کنند و پیش از پایان، گیت تکمیل را بررسی می‌کنند. کیفیت Hook به انتخاب Event درست، Matcher محدود و Script کوچک وابسته است.

با یک سناریوی کم‌ریسک شروع کنید، Script را خارج از Test کنید و سپس آن را محلی فعال کنید. را به Hook واگذار نکنید؛ Permission، Sandbox، Workspace Trust و Review تیمی باید لایه‌های مستقل باقی بمانند.

امروز یک Hook محلی و کم‌ریسک برای فرمت‌کردن فقط یک نوع فایل بسازید، آن را با Fixture JSON آزمایش کنید و پیش از انتقال به تنظیمات مشترک تیم، Event، Matcher، خروجی و Failure path را در /hooks بازبینی کنید.

منابع رسمی