در booking-platform، ریشهٔ مخزن میگوید «هر تغییر API باید integration test داشته باشد»؛ یک دستور نزدیک web میگوید «فقط unit test»؛ و فایل شخصی توسعهدهنده میگوید «هرگز test اجرا نکن». Agent نمیتواند از طول متن بفهمد کدام معتبر است. افزون بر آن، نام یکسان `AGENTS.md` در Cursor و Codex به معنای discovery یا precedence یکسان نیست. دستور خوب، متن بیشتر نیست: Scope، Host، مسیر کشف و راه حل تعارض را روشن میکند.
## اهداف یادگیری
پس از این درس میتوانی دستور پایدار را از task prompt و policy اجرایی جدا کنی، Scope مسیرمحور و تعارض را تشخیص دهی، semantics مستندِ `AGENTS.md`، `CLAUDE.md`/`.claude/rules`، Cursor Rules، Copilot instructions و Codex را مقایسه کنی، یک هستهٔ قابلحمل بدون ادعای portability runtime بنویسی، و دستورهای متناقض یا بیشازحد بزرگ را به artifactهای کوچکتر تبدیل کنی.
## جای درس در چرخهٔ سرتاسری
Context budget درس ۸ و repository map درس ۹ میگویند چه اطلاعاتی لازم است. در Specify/Plan، دستورها توضیح میدهند این اطلاعات چگونه باید مصرف شوند: کدام test required است، چه fileهایی در Scopeند و چه زمانی باید `DECIDE` شود. آنها جای Spec رفتاری، policy امنیتی enforced یا review انسانی را نمیگیرند. اگر conflict با معیار پذیرش یا دستور سطح بالاتر حل نشد، Agent باید توقف کند و شاهد تعارض را گزارش دهد.
## چهار چیز را یکی نگیرید
**Instruction** متن راهنما برای مدل است؛ model context است و ممکن است بهدلیل ابهام یا تضاد نادرست دنبال شود. **Task Contract** هدف، Scope، command، owner و stop condition همان کار است. **Policy/enforcement** کنترل خارج از مدل، مثل CI، permission، branch protection یا hook است. **Memory/progress** وضعیت و evidence قابلبازیابی است. نوشتن «هرگز secret commit نکن» در هر چهار جا شاید لازم باشد، اما تنها secret scanner یا permission میتواند یک عمل را قطعی متوقف کند.
برای پایداری، rule را کوتاه و آزمونپذیر بنویسید: «برای `apps/api/**`، قبل از handoff فرمان X را اجرا و نتیجه را ثبت کن» بهتر از «کیفیت عالی بنویس» است. Rule باید canonical source را ارجاع دهد، نه ۵۰ صفحه راهنمای سبک را copy کند. اگر محدودیت فقط برای migration است، آن را به path مناسب scope کنید تا در کار markdown همیشه وارد Context نشود.
## جدول semantics: نام برابر، Runtime متفاوت
| مکانیزم | آنچه مستند رسمی این دوره میگوید | Scope/ترتیب | هشدار |
|---|---|---|---|
| `AGENTS.md` Convention | قرارداد بازِ متن در repo | Convention بهتنهایی loader یا precedence ندارد | وجود فایل، رعایت در هر Host را ثابت نمیکند |
| Cursor `AGENTS.md` | root و زیرپوشه پشتیبانی میشوند | nestedها با parent ترکیب و specificتر مقدم است | فقط Cursor Agent؛ با `.cursor/rules` یکی نیست |
| Cursor Project Rules | `.cursor/rules/*.mdc` با frontmatter | always، glob، intelligent یا manual activation؛ Team→Project→User در تعارض | `.md` ساده در rules شناخته نمیشود |
| Claude Code `CLAUDE.md` | `CLAUDE.md`/`.claude/CLAUDE.md` و local memory | از parent تا working directory concatenate؛ نزدیکتر دیرتر میآید؛ زیرپوشه هنگام خواندن فایل load میشود | Claude بهطور پیشفرض `AGENTS.md` نمیخواند |
| Claude `.claude/rules` | ruleهای Markdown، اختیاری `paths` | بدون `paths` در شروع؛ paths هنگام کار با فایل match؛ project پس از user | تضاد ممکن است arbitrarily انتخاب شود؛ حذفش کنید |
| Copilot instructions | `.github/copilot-instructions.md` و در surfaceهای پشتیبانیشده `.github/instructions/**/*.instructions.md` | path-specific بالاتر از repository-wide است | پشتیبانی میان GitHub.com، VS Code و IDEها فرق میکند |
| Codex | `AGENTS.override.md` یا `AGENTS.md` و fallbackهای پیکربندیشده | global سپس project root تا cwd concatenate؛ نزدیکتر دیرتر؛ override در هر directory مقدم | حداکثر byte و discovery، Codex-specific است |
این جدول portability promise نیست. مثلاً یک `AGENTS.md` قابلفهم برای انسان میتواند در Cursor و Codex رفتار متفاوت داشته باشد، و Claude Code آن را تنها اگر `CLAUDE.md` صریحاً import کند یا محتوا را منتقل کند میبیند. Copilot instructions هم feature matrix دارد؛ نگویید «همهٔ Copilotها path instruction را میخوانند» بدون Surface و نسخه.
Cursor Rules و `AGENTS.md`
در Cursor، Project Ruleها فایل `.mdc` در `.cursor/rules` هستند و metadata تعیین میکند always apply، glob-scoped، intelligently applied یا manual باشند. `AGENTS.md` markdown ساده و جایگزین سادهتر Rules است؛ مستند رسمی پشتیبانی nested را میگوید و دستور نزدیکتر را مقدم میداند. بنابراین برای API میتوانید rule glob-scoped بسازید و برای قرارداد سادهٔ مشترک، AGENTS root کوتاه نگه دارید. precedence میان ruleهای متعدد را با امید به مدل حل نکنید؛ duplicate را حذف کنید و canonical owner داشته باشید.
Claude Code
Claude Code، `CLAUDE.md` میخواند، نه `AGENTS.md`. فایلهای CLAUDE و CLAUDE.local از ancestorهای working directory concatenated میشوند؛ فایل نزدیکتر دیرتر است و در سطح یک directory، local بعد از CLAUDE میآید. CLAUDE در زیرپوشه هنگام خواندن فایل آن ناحیه وارد Context میشود. `.claude/rules` برای modularity است: rule بدون `paths` unconditional و rule دارای `paths` برای فایل match وارد میشود. مستند رسمی هشدار میدهد تضادها ممکن است arbitrarily انتخاب شوند؛ «آخرین متن همیشه برنده است» ضمانت semantic نیست، هرچند ترتیب Context علت عملی برای حذف تضاد است.
اگر repository به AGENTS.md متکی است، Claude Code docs پیشنهاد میدهد CLAUDE.md آن را با `@AGENTS.md` import کند یا symlink بسازد؛ import نیز token مصرف میکند و import بیرونی ممکن است approval بخواهد. این پلی برای یک Host مشخص است، نه اینکه AGENTS convention ذاتاً Claude semantics بدهد.
GitHub Copilot
در GitHub Copilot، repository-wide instruction در `.github/copilot-instructions.md` قرار میگیرد. path-specificها فایلهای `NAME.instructions.md` در یا زیر `.github/instructions` هستند و طبق مستند response customization، path-specific applicable بر repository-wide precedence دارد. اما در همهٔ Copilot features و IDEها agent instructions یا path-specific support یکسان نیست. پس lab باید Surface را ثبت کند و fallback—Task Contract، test command و canonical docs—را برای runtime دیگر حفظ کند.
Codex
Codex instructions را در آغاز run بهصورت chain میسازد: در Codex home از `AGENTS.override.md` وگرنه `AGENTS.md`، سپس از project root تا current working directory، در هر directory ابتدا override و بعد AGENTS (و fallbackهای configured)، حداکثر یک فایل. محتوا از root به cwd concatenate میشود؛ محلیتر در prompt بعدتر میآید. discovery تا cwd است و `project_doc_max_bytes` ceiling دارد. نتیجهٔ مهم: `AGENTS.override.md` یک قابلیت Codex است، نه filename عمومی برای Cursor یا Claude. آن را بدون آزمایش در Host دیگر بهعنوان «override قابلحمل» منتشر نکنید.
## تعارض را بهجای پنهانکردن، طراحی کنید
سه نوع تعارض رایج است: دستورهای یک Scope رفتار مخالف دارند؛ global preference با project contract برخورد میکند؛ و task prompt درخواست خارج از policy میدهد. ابتدا منبع، Host، path و زمان load را ثبت کنید. سپس اگر یکی enforced policy است، آن محدودیت باقی میماند. اگر دو instruction مدل تعارض دارند، به owner گزارش دهید و ruleها را به یک canonical constraint تبدیل کنید؛ Agent نباید از روی «من جدیدترم» یا شدت لحن winner انتخاب کند.
در monorepo، parent rule باید invariantهای کمتعداد باشد: security، command discovery و evidence format. child rule فقط تفاوت domain را بنویسد: مثلاً API integration test یا web accessibility. قرار دادن دستور متضاد «هرگز test نزن» در user scope با «test لازم است» در project scope نمونهٔ تنظیم اشتباه است، نه معمایی برای Agent.
مثال ضعیف در booking-platform
# AGENTS.md
همهٔ فایلها را بخوان. همیشه تمام testها را اجرا کن. هرگز test اجرا نکن.
از بهترین معماری استفاده کن. APIها را سریع بساز.این متن هم متناقض است، هم Scope ندارد، هم Context را میبلعد. در Claude Code نیز ممکن است اصلاً load نشود. قرار دادن آن در `.cursor/rules/api.md` نیز کار نمیکند، چون Cursor Rule به `.mdc` و frontmatter نیاز دارد. کپی همان فایل به Copilot و Codex، semantics هر runtime را برابر نمیکند.
مثال اصلاحشده
# AGENTS.md — هستهٔ انسانیِ قابلحمل
- قبل از تغییر، Task Contract و Decision ledger را بخوان؛ policy باز را `DECIDE` کن.
- برای هر Fact مسیر/فرمان شاهد و revision/date ثبت کن.
- فرمان Verification را از manifest یا CI کشف کن؛ نتیجه و Scope آن را در Evidence ثبت کن.
- این فایل loader یا precedence ابزار دیگر را تعیین نمیکند.و برای Cursor API، فایل `.cursor/rules/api-tests.mdc`:
---
globs: apps/api/**
alwaysApply: false
---
برای تغییر API، integration test مربوط را از manifest کشف کن؛ اگر سرویس بیرونی لازم است، اجرا را متوقف و Recovery را ثبت کن.برای Claude Code، نمونهٔ دقیقِ `.claude/rules/api.md` چنین است:
---
paths:
- "apps/api/**/*.ts"
---
برای تغییر API، integration test مربوط را از manifest کشف کن؛ اگر سرویس بیرونی لازم است، اجرا را متوقف و Recovery را ثبت کن.برای GitHub Copilot در Surfaceهای پشتیبانیشده، نمونهٔ دقیقِ `.github/instructions/api.instructions.md` چنین است:
---
applyTo: "apps/api/**/*.ts"
---
برای تغییر API، integration test مربوط را از manifest کشف کن؛ اگر سرویس بیرونی لازم است، اجرا را متوقف و Recovery را ثبت کن.`paths` syntax و زمان load را با [Claude Code memory](https://code.claude.com/docs/en/memory) کنترل کنید. `applyTo` با glob و فایل `*.instructions.md` در [مستند رسمی Copilot](https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot) تعریف شده است؛ path-specific instructions در GitHub.com فعلاً فقط برای Cloud Agent و Code Review پشتیبانی میشود، پس نتیجه را به IDE یا CLI تعمیم ندهید. برای Codex دستور نزدیک را در AGENTS.md همان subtree قرار دهید. متن هسته میتواند مشابه باشد، ولی فایل، trigger، Surface/نسخه و precedence را جدا verify کنید.
## آزمایشگاه: ماتریس دستور و conflict بساز
**ورودی:** root guidance ۵۰۰ خطی، یک rule nested برای `apps/api` و یک نیاز reschedule. **گامها:** ۱) هر بند را instruction، task contract، durable state یا enforcement برچسب بزن. ۲) برای چهار بند، path/Host/trigger و owner بنویس. ۳) دو تناقض واقعی را با مسیر و اثر نشان بده. ۴) invariantهای root را به حداکثر هشت bullet کوتاه تقلیل بده و domain rule را path-scoped کن. ۵) برای Cursor، Claude، Copilot و Codex یک ماتریس «فایل/زمان load/روش verify» بساز؛ فقط رفتار مستند همان Host را ادعا کن.
**فرمانهای read-only:** ابتدا وجود و محل ruleها را بررسی کن:
rg -n --glob 'AGENTS.md' --glob 'CLAUDE.md' --glob '*.mdc' --glob '*.instructions.md' --glob '*.md' \
'(^paths:|^applyTo:|alwaysApply:|globs:|integration test|هرگز test)' \
.cursor .claude .github AGENTS.md CLAUDE.md 2>/dev/null
git rev-parse --show-toplevel**خروجی واقعبینانهٔ مورد انتظار:** matchها filename و شمارهٔ خط `paths:` در `.claude/rules/api.md`، `applyTo:` در `.github/instructions/api.instructions.md` و `globs:` در `.cursor/rules/api-tests.mdc` را نشان میدهند؛ فرمان دوم مسیر absolute ریشهٔ checkout را چاپ میکند. نبود یک path، assertionی دربارهٔ پشتیبانی runtime نیست؛ فقط نشان میدهد آن نمونه در checkout حاضر نیست.
**خروجی مورد انتظار:** AGENTS هستهٔ کوتاه، rule محلی بیتضاد، و گزارش `unknown` برای Surfaceی که آزمایش/مستند نشده است. خروجی command باید path و trigger را به artifact وصل کند؛ یک command یا تست مستقل enforcement را تأیید میکند؛ خود instruction evidence موفقیت نیست.
**Recovery:** اگر `rg` هیچ match نداد، اول با `ls -la .cursor .claude .github` وجود directory را تأیید کن و سپس absence را گزارش بده؛ فایل را بهنام validation نساز. اگر نمیدانید یک runtime فایل را میخواند، آن را portable فرض نکنید؛ مستند رسمی همان Surface را بخوانید و fallback Task Contract بدهید. اگر دو rule یک رفتار مخالف دارند، یکی را با owner حذف یا به policy روشن تبدیل کنید. اگر file مرجع بزرگ شد، reference path/command بدهید، ولی مطمئن شوید Agent راه بازیابی آن را دارد.
## خطاهای رایج و نشانهها
- **نام فایل را استاندارد runtime میدانیم:** AGENTS در هر Host انتظار یکسان دارد.
- **instruction را enforcement میدانیم:** rule میگوید secret ممنوع است، اما scanner/permission وجود ندارد.
- **Scope مبهم است:** rule frontend روی migration database هم مینشیند.
- **تعارض را با طول متن حل میکنیم:** root بزرگتر و child بلندتر میشود.
- **نسخه/Surface ثبت نشده:** نتیجهٔ یک CLI به IDE یا Cloud تعمیم مییابد.
## چکلیست Verification
- [ ] Host، Surface و تاریخ/نسخهٔ آزمایش برای هر semantics ثبت شده است.
- [ ] AGENTS convention را از Cursor و Codex runtime جدا کردهام.
- [ ] CLAUDE.md و `.claude/rules` را با semantics Claude Code توضیح دادهام.
- [ ] Copilot path-specific instruction را فقط در surface پشتیبانیشده ادعا کردهام.
- [ ] تعارضها canonical owner و راه حل دارند، نه winner حدسی.
- [ ] policy پرریسک با کنترل مستقل enforce میشود.
## تمرین مستقل
برای monorepo فرضی شامل `apps/web` و `apps/api`، هستهٔ ۸-bullet، یک rule API و یک rule web بنویس. سپس بگو همان رفتار برای Cursor، Claude Code، Copilot و Codex در کدام فایلها و با چه محدودیتی قرار میگیرد.
**Rubric پاسخ:** پاسخ خوب invariantها را کوتاه و domain ruleها را path-scoped میکند، test/command را از manifest کشف میخواهد، و Fact/Decision را جدا نگه میدارد. برای Cursor `.mdc`/trigger، برای Claude CLAUDE/rules، برای Copilot repository/path instructions با Surface caveat و برای Codex chain/override را جدا میکند. ادعای «یک AGENTS.md همهجا یکسان اجرا میشود» مردود است.
## جمعبندی
دستور مؤثر، قرارداد کوچک و قابلسنجش برای Host مشخص است. یک متن انسانی مشترک مفید است، اما runtime، trigger و precedence را صادر نمیکند. برای ادامهٔ کار فراتر از هر session، تصمیم، progress و evidence باید در حافظهٔ پایدار و provenance-aware ثبت شوند؛ موضوع درس بعد.
## منابع مستقیم
- [Cursor Rules and AGENTS.md](https://cursor.com/docs/rules.md) — مستند رسمی Cursor برای Ruleهای `.mdc` و AGENTS nested.
- [Claude Code memory](https://code.claude.com/docs/en/memory) — مستند رسمی CLAUDE.md، ruleهای path-scoped و ترتیب load.
- [GitHub Copilot response customization](https://docs.github.com/en/copilot/concepts/prompting/response-customization) — مستند رسمی instructionهای repository و path-specific با caveat Surface.
- [OpenAI Codex — AGENTS.md](https://developers.openai.com/codex/guides/agents-md) — مستند رسمی chain، override و سقف Context Codex.
- [AGENTS.md](https://agents.md/) — Convention باز؛ نه specification runtime مشترک.
به زبان ساده
Instruction، Task Contract و Policy اجرایی نقش یکسان ندارند؛ متن راهنما ممکن است نادیده گرفته شود، اما permission یا CI میتواند واقعاً جلوی عمل را بگیرد. تعارض باید با Host، Scope و مالک تصمیم حل شود، نه با طول متن.
مثال واقعی
مستند رسمی Cursor، Ruleهای `.mdc` و `AGENTS.md` را با semantics مشخص خود توضیح میدهد؛ همین نام فایل نباید بهطور خودکار به رفتار Claude Code یا Codex تعمیم داده شود.