هوکها: قاعدههایی که همیشه اجرا میشوند
در CLAUDE.md لیلا بهروشنی نوشته شده: «بعد از ویرایشِ یک گزارش، همیشه python check_report.py را روی آن اجرا کن.» بیشترِ روزها عامل این کار را میکند. ولی این هفته دو بار گزارشی را ویرایش کرد و بیبررسی رد شد، و هر دو بار گزارش خطایی داشت که بررسی پیدایش میکرد.
دستور آنجا بود. چرا دنبال نشد؟
لیلا در فایلِ دستورها هست. حتی با حروفِ درشت. و گاهی همینطوری انجامش نمیدهد.
امید از دیدِ مدل، فایلِ دستورها چیست؟
لیلا متنی در زمینهاش. نزدیکِ بالا، در هر درخواست.
امید و مدل چطور تصمیم میگیرد بعد چه بنویسد؟
لیلا توکنِ بعدی را از روی همهی چیزهایی که در زمینه است پیشبینی میکند. پس دستورِ من «بررسی را اجرا کن» را خیلی محتمل میکند... ولی نه حتمی. مخصوصاً در یک نشستِ طولانی، با کلی متنِ دیگر که با آن رقابت میکند.
امید همین است. دستور یک فشارِ قوی است، نه یک تضمین. برای بیشترِ کارها فشارِ قوی کافی است. ولی این یکی را چند وقت یک بار لازم داری که انجام شود؟
لیلا هر بار، بیاستثنا.
امید پس آن را به مدل نسپار. چه کسِ دیگری در هر ویرایش حضور دارد؟
لیلا برنامهی دورِ مدل. هر درخواستِ ابزار از آن میگذرد.
امید پس از برنامه بخواه این کار را بکند. به آن بگو: «هر وقت ویرایشی انجام شد، این فرمان را اجرا کن.» برنامه چیزی را پیشبینی نمیکند. فقط انجامش میدهد، هر بار.
لیلا پس قاعده را از سمتِ مدل به سمتِ برنامه میبرم.
امید از کلمه به کد. هوک همین است.
هوک چیست
هوک (hook) فرمانی است که برنامهی دورِ عامل در لحظهای معین از کارش بهطور خودکار اجرا میکند، هر بار که آن لحظه برسد، مدل هر چه در سر داشته باشد. به این لحظهها رویدادهای هوک (hook events) میگویند.
در Claude Code (در سال ۲۰۲۶) رویدادهای اصلیِ هوک اینها هستند:
- UserPromptSubmit: پیامی فرستادهاید، پیش از آنکه مدل آن را ببیند.
- PreToolUse: مدل ابزاری خواسته است، پیش از اجرای آن. هوکی در این لحظه میتواند جلوی کار را بگیرد.
- PostToolUse: ابزاری همین حالا اجرا شده است. هوکی در این لحظه میتواند نتیجه را بررسی یا مرتب کند.
- Stop: عامل میخواهد بگوید کارش تمام شده است. هوکی در این لحظه میتواند آن را دوباره سرِ کار بفرستد.
- SessionStart، پیش از فشردهسازی، وقتی یک عاملِ کمکی کارش را تمام میکند، و روی هم بیش از سی رویداد.
هوکی که جلوی کار را میگیرد
هوکها در همان فایلهای تنظیماتی تعریف میشوند که اجازهها. این یکی پیش از هر فرمانِ پوسته یک اسکریپتِ کوچک اجرا میکند:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{ "type": "command", "command": ".claude/hooks/no-rm-rf.sh" }]
}
]
}
}"PreToolUse" رویداد است؛ "matcher": "Bash" یعنی «فقط برای فرمانهای پوسته»؛ و "command" همان چیزی است که اجرا میشود. برنامهی دورِ مدل شرحِ رویداد را به شکلِ JSON به اسکریپت میدهد، از جمله فرمانی که مدل میخواهد اجرا کند. اسکریپت این است:
#!/bin/bash
command=$(jq -r '.tool_input.command')
if echo "$command" | grep -q 'rm -rf'; then
echo "Blocked: don't use rm -rf here. Delete files one by one." >&2
exit 2
fi
exit 0خط به خط: jq فرمان را از JSON بیرون میکشد. اگر فرمان rm -rf داشته باشد (یعنی همه چیزِ یک پوشه را بیهیچ پرسشی پاک کن)، اسکریپت دلیلی چاپ میکند («جلویش گرفته شد: اینجا از rm -rf استفاده نکن، فایلها را یکییکی پاک کن») و با کدِ خروجِ ۲ تمام میشود، که در Claude Code یعنی «جلوی این کار را بگیر». فرمان هرگز اجرا نمیشود و دلیل به شکلِ نتیجهی ابزار به مدل برمیگردد، تا راه دیگری را امتحان کند. کدِ خروجِ ۰ یعنی «مشکلی نیست، ادامه بده».
هوکی که همیشه مرتب میکند
این یکی بعد از هر ویرایش یک قالببندیکننده (ابزاری که چیدمانِ یک فایل را درست میکند) اجرا میکند:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [{ "type": "command", "command": "jq -r '.tool_input.file_path' | xargs npx prettier --write" }]
}
]
}
}"Edit|Write" با هر دو ابزارِ فایل جور میشود. فرمان مسیرِ فایلِ ویرایششده را از JSON برمیدارد و قالببندیکننده را روی آن اجرا میکند. بررسیِ گزارشِ لیلا هم همین شکل را دارد، با اسکریپتِ خودِ او به جای قالببندیکننده.
کلمه یا کد؟
هر دو جای خودشان را دارند. بیشترِ راهنماییها به داوری بستگی دارند («تابعهای کوتاه را ترجیح بده»، «تغییرهایت را توضیح بده»)، و داوری را فقط با کلمهها میشود گفت. ولی اگر قاعدهای باید هر بار و بیاستثنا برقرار باشد، و اسکریپتی میتواند آن را بررسی کند، جایش در یک هوک است.
مراقب باشید
هوک فرمانی است که با اجازههای شما روی رایانهتان اجرا میشود، هر بار که رویدادش رخ دهد. فقط از هوکهایی استفاده کنید که خواندهاید و فهمیدهاید، و با پروژههایی که هوکهای خودشان را همراه دارند محتاط باشید.
امتحان کنید
در Claude Code،
/hooksرا بنویسید تا ببینید کدام هوکها تنظیم شدهاند (احتمالاً هنوز هیچکدام). بعد به فایلِ دستورهایتان، یا به فهرستِ عادتهایتان با هر عاملی، نگاه کنید و کنارِ هر قاعده بنویسید «معمولاً» یا «همیشه». قاعدههای «همیشه» اولین هوکهای شما هستند.
درست به کار بردن
- هوک برای «باید»ها، دستور برای «بهتر است»ها. قالببندی، بررسیها، فرمانهای ممنوع: هوک. سبک، اولویتها، توضیحها: دستور.
- یک هوکِ Stop را تعریفِ «تمام شد» کنید. هوکی که وقتی عامل میخواهد کار را تمام کند آزمونها را اجرا میکند و اگر شکست خوردند آن را برمیگرداند، یعنی «تمام شد» همیشه یعنی «آزمونها قبول شدند».
- وقتی جلوی کاری را میگیرید، دلیلِ بهدردبخوری بدهید. مدل دلیل را میخواند و دوباره تلاش میکند، پس «جلویش گرفته شد: به جایش از پوشهی trash/ استفاده کن» بهتر از «نه» کار میکند.
- هوکها را سریع نگه دارید. هر بار اجرا میشوند؛ هوکِ کُند هر کاری را کُند میکند.
واژههای این درس
- هوک (hook) - فرمانی که برنامهی دورِ عامل در لحظهای معین، هر بار، بهطور خودکار اجرا میکند، مدل هر چه در سر داشته باشد
- رویدادِ هوک (hook event) - یکی از لحظههایی که هوک میتواند در آن اجرا شود، مثل پیش از اجرای ابزار، پس از اجرای آن، یا وقتی عامل میخواهد کار را تمام کند
ایدهی اصلی
دستور از مدل میخواهد کاری را بکند، و مدل معمولاً میکند. هوک کاری میکند که برنامهی دورِ مدل آن را هر بار انجام دهد. «معمولاً» را با کلمه بگویید و «همیشه» را با کد.