جلسه ۲ از ۱۱، بخش ۱: کار با ایجنت‌ها

Claude Code از درون

متنی ۳۰ دقیقه به‌روز شده در ۱۰ آبان ۱۴۰۵

در این جلسه
  1. حلقه‌ی ایجنتی
  2. کانتکست، حتی پیش از اولین کلمه‌ی شما
  3. حافظه: چیزی که بین نشست‌ها می‌ماند
  4. ابزارها
  5. چهار سازوکار توسعه
  6. جمع‌بندی
  7. پرسش‌هایی برای فکر کردن
  8. منابع

سؤال این جلسه ساده است: وقتی در Claude Code پرامپتی می‌نویسید و Enter می‌زنید، دقیقاً چه اتفاقی می‌افتد؟ جواب این سؤال اساس همه‌ی جلسه‌های بعدی است، چون هر ایجنت کدنویسی تقریباً همین ساختار را دارد.

حلقه‌ی ایجنتی#

مدل زبانی بی‌حالت (stateless) است: هر فراخوانی از صفر شروع می‌شود و فقط چیزی را می‌بیند که در کانتکستش گذاشته‌ایم. Claude Code این مدل بی‌حالت را در یک حلقه‌ی سه‌مرحله‌ای قرار می‌دهد:

  1. جمع‌آوری کانتکست: پرامپت شما، فایل‌ها، نتیجه‌ی ابزارهای قبلی
  2. تولید عمل: مدل تصمیم می‌گیرد چه کند، مثلاً Bash("pytest") یا Read("session.py")
  3. اجرای ابزار: هارنس دستور را اجرا می‌کند و نتیجه را برمی‌گرداند

هر دور به نتیجه‌ی دور قبل وابسته است. پس یک پرامپت شما به ده‌ها فراخوانی مدل و ابزار تبدیل می‌شود:

پرامپت ─◄ M₁ ─◄ T₁ ─◄ M₂ ─◄ T₂ ─◄ ... ─◄ Mₙ ─◄ پاسخ

مثلاً برای «تست لاگین را درست کن»:

قدم مدل تصمیم می‌گیرد ابزار برمی‌گرداند
۱ pytest را اجرا کن ۲ تست شکست خورد
۲ session.py را بخوان محتوای فایل
۳ create_session را grep کن ۴ مورد در ۲ فایل
۴ session.py را ویرایش کن ویرایش انجام شد
۵ دوباره pytest همه سبز
۶ «مشکل از … بود و … را تغییر دادم» (پاسخ نهایی)

مدل پیشنهاد می‌دهد، هارنس اجرا می‌کند#

مدل هیچ‌وقت مستقیم روی سیستم شما کاری نمی‌کند. فقط یک درخواست ساخت‌یافته تولید می‌کند. هارنس آن را تفسیر می‌کند، مجوزها را بررسی می‌کند، روی سیستم شما اجرا می‌کند و خروجی (stdout و stderr) را به‌عنوان tool_result به کانتکست برمی‌گرداند.

مجوزها بین نیت و اجرا#

حالت مجوز رفتار
Manual (پیش‌فرض) برای هر عمل حساس از شما می‌پرسد
Accept Edits ویرایش فایل را خودکار قبول می‌کند، دستورهای دیگر را می‌پرسد
Auto یک مدل کوچک هر درخواست را بررسی و تأیید یا رد می‌کند
Bypass بدون پرسیدن همه چیز را اجرا می‌کند

هر درخواست یکی از سه نتیجه را دارد: اجازه (اجرا می‌شود)، پرسش (شما تأیید می‌کنید) یا رد (هیچ اتفاقی نمی‌افتد). دستوری مثل rm -rf build/ نمونه‌ی درخواستی است که باید از این فیلتر بگذرد.

کانتکست، حتی پیش از اولین کلمه‌ی شما#

وقتی هنوز چیزی تایپ نکرده‌اید، کانتکست Claude Code معمولاً بیش از ۱۰ هزار توکن دارد:

  • دستورالعمل‌های سیستمی
  • اطلاعات محیط پروژه (پوشه‌ی کاری، وضعیت git)
  • حافظه‌ی پایدار (CLAUDE.md و یادداشت‌ها)
  • تعریف ابزارها: Read، Edit، Bash، Glob، Grep، Web، Agent
  • فقط نام و توضیح skillها و ابزارهای MCP؛ متن کاملشان فقط هنگام استفاده بار می‌شود

نکته‌ی مهم: کل مخزن کد به مدل فرستاده نمی‌شود. مخزن روی دیسک می‌ماند و مدل با ابزارهایی مثل Grep فقط تکه‌های لازم را برمی‌دارد. جستجوی «authentication» فقط خط‌های منطبق را برمی‌گرداند، نه همه‌ی فایل‌ها را.

کانتکست رشد می‌کند و بعد فشرده می‌شود#

هر قدم چیزی به کانتکست اضافه می‌کند: پاسخ مدل، محتوای فایل، خروجی دستور. وقتی به حد پنجره نزدیک شود، compaction اتفاق می‌افتد: تاریخچه‌ی قدیمی خلاصه می‌شود و CLAUDE.md و حافظه دوباره تزریق می‌شوند.

کانتکست رایگان نیست

مدل‌های پیشرو امروز پنجره‌ی حدود یک میلیون توکنی دارند؛ اوایل همین سال ۲۵۶ هزار توکن رایج بود. اما هر فراخوانی مدل کل کانتکست را دوباره می‌خواند. حتی با prefix cache، خواندن از کش بخش عمده‌ی هزینه‌ی یک نشست است. جلسه‌ی ۸ این را با عدد نشان می‌دهد.

حافظه: چیزی که بین نشست‌ها می‌ماند#

ایجنت بین نشست‌ها هیچ چیز به خاطر نمی‌آورد؛ هر نشست از صفر شروع می‌شود. «حافظه» در عمل یعنی فایل‌هایی که هنگام شروع نشست خوانده می‌شوند:

  • حافظه‌ی کاری (کانتکست): با پایان نشست از بین می‌رود.
  • حافظه‌ی پایدار: می‌ماند و نشست بعد دوباره خوانده می‌شود.

پس ساختن هر حافظه یک تصمیم است درباره‌ی چیزی که از این به بعد همیشه دوباره خوانده می‌شود.

بدون حافظه‌ی پایدار، هر بار باید دستورها را تکرار کنید، تصمیم‌ها و دلیلشان بعد از compaction گم می‌شوند، ایجنت هر بار ساختار پروژه را از نو کشف می‌کند و رفتارش بین نشست‌ها ناهمگون است. حافظه دستور را به قرارداد تبدیل می‌کند.

دو سیستم حافظه در Claude Code#

فایل‌های CLAUDE.md حافظه‌ی خودکار (auto memory)
نویسنده شما خود Claude
محتوا دستورها و قواعد آموخته‌ها و الگوها
دامنه سازمان، کاربر، پروژه هر مخزن، مشترک بین worktreeها
بارگذاری هر نشست هر نشست (فقط ابتدای فایل فهرست)
کاربرد استانداردها، روند کار، معماری ترجیحات، اصلاح‌ها، کانتکست پروژه

CLAUDE.md کجا قرار می‌گیرد#

از گسترده‌ترین دامنه به نزدیک‌ترین، به این ترتیب بار می‌شوند:

  1. سیاست سازمانی (managed policy): برای همه، قابل حذف نیست
  2. ~/.claude/CLAUDE.md: دستورهای شخصی شما برای همه‌ی پروژه‌ها
  3. ./CLAUDE.md یا ./.claude/CLAUDE.md: دستورهای پروژه، در git و مشترک با تیم
  4. ./CLAUDE.local.md: دستورهای شخصی برای این پروژه، در .gitignore

چه چیزی در CLAUDE.md بنویسیم#

چهار قاعده‌ی ساختاری برای CLAUDE.md:

قاعده
اندازه زیر ۲۰۰ خط در هر فایل
ساختار سرآیند و بولت Markdown
دقت قاعده‌ی مشخص، نه مبهم
سازگاری بدون قاعده‌ی متناقض یا کهنه

و محتوایش چیزهایی است که ایجنت نمی‌تواند ارزان بفهمد:

# پروژه‌ی llmlearn

## دستورها
- تست: `pytest -q`
- اجرای محلی: `uvicorn app.main:app --reload`
- بررسی محتوا: `python scripts/manage.py check-content`

## قواعد سخت
- هرگز مستقیم روی main کامیت نکن.
- فایل‌های content/notebooks/*/grader.yaml را بدون اجرای check-content تغییر نده.
- الگوهای grader هرگز نباید به مرورگر برسند.

## نکته‌های غیرواضح
- محتوا هر ۳ ثانیه از دیسک دوباره خوانده می‌شود؛ ری‌استارت لازم نیست.
- اگر مقداری در front matter علامت «:» دارد، باید داخل گیومه باشد؛ وگرنه درس بی‌صدا حذف می‌شود.

چیزهایی که نباید آنجا باشند: دانش عمومی زبان یا فریم‌ورک، قواعد سبکی که linter اجرا می‌کند، متن طولانی، changelog و هر نوع رمز و کلید.

کانتکست اجاره‌ای است، حافظه مال خودتان است.

برای پروژه‌های بزرگ، قواعد را در .claude/rules/ بشکنید: هر موضوع یک فایل (testing.md، db-migrations.md). با فیلد paths در front matter، هر قاعده فقط وقتی بار می‌شود که فایل‌های منطبق لمس شوند؛ قاعده‌ی بدون paths در هر نشست بار می‌شود. نتیجه: پنجره‌ی کانتکست کوچک می‌ماند، فقط قواعد مربوط به کار فعلی بار می‌شوند، و CLAUDE.md کوتاه می‌ماند چون جزئیات در فایل‌های rules است.

حافظه‌ی خودکار از نزدیک#

حافظه‌ی خودکار را خود Claude می‌نویسد. چهار نوع یادداشت در آن نگه داشته می‌شود:

نوع چه چیزی
user نقش و ترجیحات شما
feedback اصلاح‌هایی که کرده‌اید و روش‌هایی که تأیید کرده‌اید
project کار در جریان و تصمیم‌هایی که در خود کد نیستند
reference اطلاعاتی بیرون از پروژه

یادداشت‌ها در ~/.claude/projects/<project>/memory/ ذخیره می‌شوند:

~/.claude/projects/<project>/memory/
├── MEMORY.md              # index
├── user_role.md
├── feedback_testing.md
└── other-topic-files.md

هر فایل یک فیلد type دارد که نوعش را مشخص می‌کند. حافظه‌ی خودکار به‌طور پیش‌فرض روشن است، فقط روی همان ماشین می‌ماند (worktreeهای یک مخزن همین پوشه را به اشتراک می‌گذارند) و با /memory خاموش می‌شود.

بازیابی از راه همین فهرست انجام می‌شود، نه با خواندن همه‌ی یادداشت‌ها:

شروع نشست ─◄ بار شدن فهرست MEMORY.md ─◄ پیدا کردن موضوع مرتبط ─◄ خواندن همان فایل موضوع ─◄ استفاده در کار

فقط ابتدای فهرست، تا ۲۰۰ خط یا ۲۵ کیلوبایت، در هر نشست بار می‌شود. پس فهرست باید کوتاه و دقیق بماند.

هزینه‌ی به خاطر سپردن#

  • حافظه‌ی پایدار اجاره‌ای است که هر نشست پرداخت می‌شود.
  • حافظه با خود کار سر جای کانتکست رقابت می‌کند.
  • حافظه‌ی کهنه از نبودِ حافظه بدتر است.
  • با حافظه مثل کد رفتار کنید: بازبینی، هرس، نسخه‌بندی.

دستورهای مفید:

دستور کار
/memory دیدن، ویرایش، حذف یا خاموش کردن حافظه
/context اینکه کدام فایل‌های دستورالعمل بار شده‌اند
/init ساختن یک CLAUDE.md اولیه
/doctor علامت زدن محتوایی که احتمالاً جایش در CLAUDE.md نیست

ابزارها#

ابزار کار نکته
Read خواندن فایل و وضعیت پرکاربردترین ابزار
Grep / Glob جستجو فقط نتیجه‌ی منطبق برمی‌گردد
Fetch خواندن صفحه یا مستند متن نامطمئن وارد کانتکست می‌کند
Edit / Write تغییر فایل اولین ابزاری که پیامد واقعی دارد
Bash build، تست، git یعنی دسترسی کامل به ماشین، مگر در sandbox
Agent ساختن زیرایجنت فقط خلاصه‌ی نتیجه برمی‌گردد

مدل خودش تصمیم می‌گیرد از کدام ابزار استفاده کند. در جلسه‌ی ۴ همین ابزارها را خودمان طراحی می‌کنیم.

چهار سازوکار توسعه#

سازوکار به چه سؤالی جواب می‌دهد کجای حلقه اثر می‌کند
Skill این کار را چطور انجام دهم؟ هنگام استدلال مدل
MCP به چه داده و عملی بیرون از ماشین دسترسی دارم؟ هنگام انتخاب ابزار
Hook چه چیزی باید خودکار و همیشه اجرا شود؟ هنگام اجرای ابزار و رویدادهای نشست
Plugin این‌ها را چطور بسته‌بندی و توزیع کنم؟ همه‌ی موارد بالا

یک مثال واحد، انتشار نسخه‌ی جدید نرم‌افزار:

  • مراحل انتشار را دنبال کن ← Skill
  • release را در GitHub بساز ← MCP
  • اگر تست‌ها شکست خوردند، انتشار را مسدود کن ← Hook
  • این تنظیمات را با تیم به اشتراک بگذار ← Plugin

Skill#

skill دانش و رویه‌ای است که ایجنت فقط وقتی کار به آن نیاز دارد بار می‌کند: دانش یک حوزه، مرجع، و روند تکرارشونده. اسلاید پیشنهاد می‌کند skill را نوعی مهندسی کانتکست ببینید. مثال: /release 2.4.0.

یک پوشه با یک فایل SKILL.md و در صورت نیاز مراجع و اسکریپت:

.claude/skills/release/
├── SKILL.md
├── references/checklist.md
└── scripts/bump_version.py
---
name: release
description: انتشار نسخه‌ی جدید. وقتی کاربر از انتشار، release یا نسخه‌ی جدید حرف می‌زند استفاده شود.
---

1. یادداشت‌های انتشار را از CHANGELOG.md بخوان.
2. شماره‌ی نسخه را با کاربر تأیید کن.
3. تست‌ها را اجرا کن؛ اگر شکست خوردند متوقف شو.
4. کامیت انتشار را آماده کن.
5. پیش از انتشار نهایی از کاربر اجازه بگیر.

description تعیین می‌کند skill کی پیدا شود و بدنه رویه را نگه می‌دارد. skill را یا مدل خودش صدا می‌زند (وقتی توضیح منطبق باشد) یا کاربر با /release.

هزینه‌ها و ملاحظه‌ها:

  • توضیح همه‌ی skillها در شروع نشست بار می‌شود، اما بدنه‌ی کامل فقط وقتی اجرا شود.
  • روندهایی که اثر جانبی دارند (انتشار، استقرار) بهتر است فقط با فراخوانی صریح کاربر اجرا شوند.
  • توضیح‌های متمایز احتمال انتخاب skill اشتباه را کم می‌کنند.

MCP#

Model Context Protocol ایجنت را به سرویس‌های بیرونی وصل می‌کند: GitHub، پایگاه داده، Slack، مرورگر. پیش از MCP، اتصال N ابزار به M سرویس به N×M یکپارچه‌سازی اختصاصی نیاز داشت. MCP این را به یک پروتکل باز تبدیل کرد.

ابزار MCP از دید مدل دقیقاً مثل ابزار محلی است: نام، توضیح، شِمای تایپ‌شده و قرارداد «فراخوانی و نتیجه». فقط در پروسه‌ی دیگری اجرا می‌شود. MCP سه نوع قابلیت دارد:

  • Tools: عمل‌ها، مثل create_issue
  • Resources: داده‌ی خواندنی، مثل github://issues/123
  • Prompts: قالب‌هایی که کاربر صدا می‌زند

امنیت MCP

توکن‌ها را با کمترین دسترسی لازم بسازید. خواندن و نوشتن را جدا کنید و نوشتن را پشت تأیید بگذارید. خروجی ابزار را داده بدانید، نه دستور. سرورهای MCP شخص ثالث را پیش از نصب بررسی کنید، چون می‌توانند حامل prompt injection باشند. سرور متصل هر چیزی را که برایش بفرستید می‌بیند و با اعتبارنامه‌ی شما عمل می‌کند. پیش از اتصال بپرسید: این سرور چه چیزی را می‌تواند بخواند و چه چیزی را می‌تواند تغییر دهد؟

معماری MCP#

Host (e.g. Claude Code) ─► MCP client ─► MCP protocol ─► MCP server ─► external system
                          (one per server)               (exposes tools)   (GitHub, Slack, Postgres, ...)

یک فراخوانی ابزار MCP این مسیر را طی می‌کند: Claude نیاز به یک عمل را تشخیص می‌دهد، کلاینت MCP ابزار را صدا می‌زند، سرور MCP اتصال را مدیریت می‌کند، سرویس بیرونی کار را انجام می‌دهد، نتیجه‌ی ساخت‌یافته برمی‌گردد و Claude آن را ارزیابی می‌کند. ایجنت همچنان خودش تصمیم می‌گیرد ابزار را صدا بزند یا نه.

سه نوع قابلیت در یک کار#

فرض کنید درخواست این است: «issue شماره‌ی ۱۲۳ را بررسی کن و اگر باگ حیاتی احراز هویت است، assign کن». هر سه نوع قابلیت به کار می‌آیند:

  • Prompt رویه‌ی بررسی سازمان را می‌دهد. یک prompt مجموعه‌ای دستور برمی‌گرداند، مثلاً: issue را بازبینی کن، تکرارپذیر بودنش را بررسی کن، شدتش را «بالا» ارزیابی کن، و مالک و قدم بعدی را پیشنهاد بده. promptها را کاربر کنترل می‌کند و در Claude Code به‌شکل دستور اسلش با فضای نام ظاهر می‌شوند: /mcp__github__triage_issue 123 high
  • Resource محتوای issue را می‌دهد: github://issues/123
  • Tool خطاهای مرتبط را می‌آورد، مثلاً get_related_errors

MCP gateway#

وقتی تعداد سرورهای MCP زیاد شود، یک gateway بین کلاینت و سرورها می‌نشیند؛ مثل API gateway، اما با پروتکل MCP:

Claude Code ─► MCP gateway ─► GitHub / Jira / database MCP servers
               (auth, policy, logging, routing, rate limits)

gateway همه‌ی عملیات MCP را می‌فهمد (tools/list، tools/call، resourceها، promptها، شِماها و نسخه‌های پروتکل) و از دید کلاینت فقط یک سرور MCP دیگر است. شش کار اصلی:

کار یعنی
تجمیع یک اتصال و یک فهرست با فضای نام: github.*، jira.*، postgres.*
مسیریابی هر فراخوانی به سرور صاحبش می‌رود؛ با هدر Mcp-Method بدون خواندن بدنه
اعمال سیاست چه کسی وصل شود، کدام ابزارها دیده یا صدا زده شوند و کدام تأیید انسانی بخواهند
واسطه‌گری هویت کلاینت یک بار احراز هویت می‌کند و اعتبارنامه‌های سرورها پشت gateway می‌مانند
مشاهده ثبت مرکزی برای ممیزی: هویت، ابزار، تصمیم، تأخیر، نتیجه و هزینه
مقیاس توزیع بار، تلاش مجدد، circuit breaker، کش فهرست، سهمیه

کی ارزشش را دارد؟ وقتی کاربر، ایجنت، سرور، اعتبارنامه یا قواعد انطباق زیاد است و باید یکسان مدیریت شوند. اما gateway خودش یک مرز اعتماد است و خطرهای خودش را دارد: اعتبارنامه‌های با دسترسی زیاد، گم شدن هویت کاربر نهایی، تداخل نام‌ها، نشت رمز در لاگ‌ها، و یک نقطه‌ی شکست واحد.

نسخه‌ی جدید MCP (۲۸ ژوئیه‌ی ۲۰۲۶)#

  • هسته‌ی بی‌حالت: نشست ندارد، پس هر نمونه‌ی سرور پشت load balancer می‌تواند هر درخواستی را جواب دهد.
  • مسیریابی: هدرهای Mcp-Method به gateway اجازه می‌دهند بدون باز کردن بدنه مسیریابی کند. نتیجه‌ی فهرست‌ها هم با TTL قابل کش است.
  • افزونه‌ها: Tasks برای کارهای طولانی و MCP Apps برای رابط کاربری که سرور رندر می‌کند، به‌شکل افزونه منتشر شده‌اند.

Hook#

hookها در رویدادهای چرخه‌ی عمر نشست اجرا می‌شوند، نه در میانه‌ی استدلال مدل:

رویداد کاربرد نمونه
شروع نشست بار کردن کانتکست، ثبت لاگ
ارسال پرامپت کاربر اعتبارسنجی یا افزودن کانتکست
پیش از اجرای ابزار بررسی یا مسدود کردن
پس از اجرای ابزار format، اجرای تست، لاگ
پیش از توقف بررسی اینکه تست‌ها واقعاً پاس شده‌اند

تفاوت مهم با skill: skill پیشنهاد است و مدل ممکن است از آن پیروی نکند. hook اجبار است و همیشه اجرا می‌شود. نمونه‌ای از hook را در جلسه‌ی ۹ می‌نویسیم.

خود hook هم می‌تواند از چند نوع باشد: یک دستور شل، یک درخواست HTTP، یک ابزار MCP، یک پرامپت به مدل یا یک زیرایجنت.

Plugin#

plugin همه‌ی این‌ها را یک‌جا بسته‌بندی می‌کند:

my-plugin/
├── .claude-plugin/plugin.json   # manifest
├── skills/
├── hooks/
├── agents/
├── .mcp.json                    # MCP servers
└── .lsp.json                    # language servers

مزیت‌ها: نصب با یک دستور، نسخه‌ی ثابت، فضای نام جدا، استفاده‌ی دوباره در تیم و توزیع از طریق marketplace.

پوشه‌ی .claude/ در یک نگاه#

.claude/
├── CLAUDE.md, rules/              # memory
├── settings.json                  # permissions, hooks, env (shared)
├── settings.local.json            # same, personal
├── commands/, skills/             # workflows
├── agents/, hooks/                # delegation and guardrails
└── plugins/

همین ساختار در ~/.claude/ برای تنظیمات شخصی هم هست. تنظیمات پروژه بر تنظیمات کاربر اولویت دارد.

تمرین: کدام سازوکار؟#

نیاز پاسخ
قراردادهای API شرکت Skill
خواندن یک issue از Jira MCP
format کردن کد پس از هر ویرایش Hook
راهنمای چندمرحله‌ای استقرار Skill
اعلان پایان کار Hook + MCP
جلوگیری از نوشتن روی دیتابیس تولید Hook یا سیاست مجوز
اشتراک بین چند مخزن Plugin

جمع‌بندی#

پرامپت + کانتکست ─◄ مدل پیشنهاد می‌دهد ─◄ هارنس اجرا می‌کند ─◄ نتیجه به کانتکست برمی‌گردد ─◄ تکرار تا پایان

تقریباً همه‌ی ایجنت‌های کدنویس همین ساختار را دارند. تفاوتشان در جزئیات است: چه ابزارهایی دارند، کانتکست را چطور مدیریت می‌کنند، مجوزها را کجا می‌گذارند و حافظه را چطور نگه می‌دارند. این جزئیات موضوع جلسه‌های بعدی است.

پرسش‌هایی برای فکر کردن#

  • در پروژه‌ی خودتان کدام سه نکته را ایجنت هر بار از نو کشف می‌کند؟ همین‌ها اولین خط‌های CLAUDE.md شما هستند.
  • چرا ممکن است یک skill نصب شده باشد ولی ایجنت هرگز از آن استفاده نکند؟ (جلسه‌ی بعد جواب را در یک plugin واقعی می‌بینیم.)

منابع#