Free

CLAUDE.md الجيد لا يصف الميزات — يكتب فقط ما لا يستطيع Claude رؤيته من قراءة الكود

CLAUDE.md الجيد ليس README — بل يلتقط الثوابت التي لا يستنتجها Claude من الكود. 6 أمور اكتبها، 4 تجنّبها، 5 أسئلة.


مشروعي Pickful فيه نظام هيئة محلّفين مجتمعي لامركزي، ومدفوعات عملات مشفّرة عبر x402، وSign-In with Ethereum، وقواعد بيانات متعددة، وإشعارات فورية — كلها تقنيات ظهرت خلال آخر عامين. Claude ينجز هذه الميزات بسرعة ودقة.

لكن إذا فتحت ملف CLAUDE.md الخاص بالمشروع، ستلاحظ: نظام هيئة المحلّفين وx402 لم تُذكرا ولا مرة واحدة.

هذا ليس سهواً. الغرض من CLAUDE.md لم يكن يوماً "وصف الميزات"، بل كتابة الأشياء التي لا يستطيع Claude اكتشافها مهما قرأ الكود.

وصف الميزات يُهدر الـ tokens

من يكتب CLAUDE.md للمرة الأولى غالباً ما يعامله كـ README ويشرح كل ميزة رئيسية:

  • "نظام هيئة المحلّفين يسمح للمستخدمين بالإبلاغ عن محتوى، ويدخل المبلّغ عنه في تصويت عام..."
  • "مدفوعات x402 تُفعّل تحويلات on-chain عبر رمز حالة HTTP 402..."
  • "الإعجابات تمنح المستخدمين نقاطاً، وعند 400 نقطة يصبح المستخدم VIP..."

هذه المحتويات يستطيع Claude قراءتها بدقة أكبر منك بمجرد فتح topic_review_service.rb / x402.rb / like_points_service.rb. وصف ألف كلمة عن منطق العمل يقرأه Claude بمئات الـ tokens من الكود مباشرة، ودون أي انحراف في التفسير — الكود هو الحقيقة، والوصف مصدر ثانوي.

ما يجعل Claude يتعثّر فعلاً هو الفئات الستّ التالية.

الفئات الستّ التي تُحدث الفرق حقاً

1. اختيارات معمارية مضادّة للبديهة

في CLAUDE.md الخاص بـ Pickful يوجد أسطر كهذه:

Propshaft (not Sprockets)
ImportMap (no JavaScript bundler)
Hotwire: Turbo Frames, Turbo Streams, Stimulus
Lexxy gem overrides ActionText:
  config.lexxy.override_action_text_defaults = false

كل سطر يقاوم التخمين الافتراضي. حين يرى Claude مشروع Rails، افتراضاته الأساسية هي:

  • الأصول الثابتة عبر Sprockets (موروث المشاريع القديمة)
  • JS عبر Webpacker أو esbuild
  • الواجهة إما React، أو مزيج Stimulus + Turbo
  • النصّ الغني هو ActionText الأصلي

بدون هذه الأسطر في CLAUDE.md، لو طلبت من Claude إضافة ميزة JS جديدة، فسيغلب عليه تثبيت Webpacker، وتعديل package.json، وكتابة إعدادات bundler — كل ذلك خطأ، وخطأ صامت (التطبيق يعمل، لكن خط الأصول يتلوّث).

هذه الأسطر في CLAUDE.md تقول لـ Claude: لا تخمّن، القرار اتُّخذ.

2. توزيع قواعد البيانات المتعددة

PostgreSQL with 4 separate databases:
- primary - Main application data
- cache   - Solid Cache storage
- queue   - Solid Queue jobs
- cable   - Action Cable subscriptions

كتابة بسيطة، لكنها توفّر مطبّات بقيمة ليلة كاملة. التعدّد الافتراضي لقواعد البيانات في Rails 8 سلوك جديد، و Claude لا يذهب من تلقاء نفسه للتحقق من عدد القواعد. migration يبدو بريئاً يحطّ في قاعدة خاطئة، والتطوير لا يعطي خطأ (الأربعة كلها PostgreSQL، والـ schema يمرّ في أيّها)، لكن في الإنتاج تختلط جداول job الخاصة بـ Solid Queue مع نسخ primary الاحتياطية، أو يستعلم نموذج primary من قاعدة cache — أعطال تستغرق أياماً لتظهر.

سطران في CLAUDE.md مقابل يوم كامل من تصحيح خطأ إنتاجي.

3. "اتفاقات غير مرئية" لتوجيه URL

/p-{slug} - Short post URLs (4-5 char alphanumeric)
/t-{slug} - Topic URLs (3-4 char alphanumeric)
/s-{code} - Short URL redirects (3-4 char alphanumeric)
/r-{referral} - Referral links

المسارات نفسها يراها Claude في routes.rb، لكن اتفاقيات الطول (4-5 حرفاً، 3-4 أحرف) مدفونة داخل منطق توليد الـ slug في النماذج أو الخدمات. اطلب من Claude إضافة نوع رابط قصير جديد، وعلى الأرجح سيولّد slug من 6 خانات، أو بنمط UUID، أو أرقاماً خالصة — خارج انسجام النظام البصري.

سمة هذه "الاتفاقيات": مخالفتها لا تنتج خطأً، لكن من يقرأ الكود لاحقاً يشعر أن شيئاً ما غير منسجم. يجب كتابتها.

4. عتبات الأعمال المرمّزة يدوياً

VIP status at 400+ points
Posts with 15+ likes are "hot" posts

كلا الرقمين موجود في الكود في مكان ما (User#vip?، و Post#hot? scope). المشكلة أن Claude حين يعدّل شيئاً قريباً — تعديل مكافآت النقاط، إضافة إشعار "قريباً VIP"، كتابة مهمّة تُثبّت "المنشورات الساخنة" — لا يذهب تلقائياً لمحاذاة العتبات في المواضع الأخرى.

النتيجة: تمنح 500 نقطة لإنجاز مهمة لكن النص يقول "يمكنك أن تصبح VIP" (بينما 400 كافية)، أو تُنشئ بيانات seed لميزة جديدة بإعجابات أقل من اللازم فلا تصل قط إلى عتبة 15.

قدرة Claude البرمجية قوية، لكنه لا يملك إحساساً عامّاً بأرقام النظام ككل. وضع العتبات الحرجة في CLAUDE.md يعني أن كل محادثة تبدأ وهو يعرف أن "400 و15 أرقام خاصة".

5. لافتة إرشاد لطبقة المصادقة / التفويض

- Devise (authentication) + Pundit (authorization)
- Pundit policies in app/policies/
- Check UserPolicy, PostPolicy, etc. for permission rules

دور هذا السطر تنقّلي وليس وصفياً.

بدونه، إذا احتاج Claude إضافة تحكّم صلاحيات جديد، ستظهر ثلاث احتمالات:

  • يكتب unless current_user.admin? مباشرة في الـ controller
  • يستخرج بقايا مكتبة CanCan التي لم تعد مستخدمة
  • يخترع دالة authorize? خاصة به في الـ model

مع وجود "Pundit policies in app/policies/"، سيتجه Claude دائماً إلى app/policies/ لإضافة ملف policy، بأسلوب موحّد.

سطر واحد يوفّر على Claude "عمل المحقّق" في كل مرة.

6. قيود خارجية على مستوى المشروع

Supported locales: en, zh-CN, zh-TW
Testing stack: RSpec + FactoryBot + Capybara + Shoulda Matchers

عند إضافة ميزة جديدة، افتراضات Claude هي:

  • إضافة نصوص إنجليزية فقط
  • كتابة اختبارات بـ Minitest + fixtures (افتراضي Rails)

لكن مشروعك يحتاج فعلياً:

  • ترجمات لثلاث لغات
  • RSpec + FactoryBot، وليس fixtures

مخالفة هذه "القيود الخارجية على مستوى المشروع" تُنتج تنظيفاً لاحقاً مكلفاً — ترجمات ناقصة، اختبارات تُعاد كتابتها. CLAUDE.md يثبّت مرة واحدة "ما يجب فعله في كل مرة".

في المقابل: هذه الأمور كتابتها هدر

قدر أهمية "يجب كتابته" تأتي أهمية "لا تكتبه". هذه الفئات التالية احذفها فور رؤيتها:

1. وصف الميزات

"نظام هيئة المحلّفين: يستطيع المستخدمون الإبلاغ عن محتوى مخالف، والمحتوى المُبلَّغ عنه يدخل مرحلة تصويت عام..."

→ Claude يفتح topic_review_service.rb ويقرأه بدقّة أعلى ممّا كتبت. حشو هذا في سياق كل محادثة جديدة هدر صافٍ.

2. ما يمكن استنتاجه فوراً من شجرة الملفات / Gemfile

"app/models/ تحوي نماذج ActiveRecord"، "يستخدم Rails 8"، "قاعدة البيانات PostgreSQL"

→ نظرة سريعة على جذر المشروع وعلى Gemfile كافية لـ Claude.

3. معرفة برمجية عامّة

"Controllers should be thin, delegate to services"، "تجنّب استعلامات N+1"، "اكتب اختبارات للميزات الرئيسية"

→ هذا موجود في بيانات تدريب Claude بالفعل. لا تكتبه إلا إذا كان مشروعك شاذاً — مثلاً "نحن عمداً لا نستخدم طبقة service، المنطق يوضع في الـ controller".

4. سياق المهمّة الحالية

"الآن نحن نُعيد هيكلة نظام الدفع، الهدف هو..."

→ هذا سياق محادثة وليس حقيقة مشروع. دسّه في CLAUDE.md يلوّث بقية المحادثات.

تدقيق ميداني: CLAUDE.md الخاص بي يمكن تقليصه للنصف أيضاً

ضع إثبات "أستطيع ذلك" قبل الدعوة. بعد كتابة القسم السابق، أعدت تشغيل أسئلتي الخمسة على CLAUDE.md الخاص بـ Pickful — 238 سطراً — والنتيجة: تقريباً النصف هدر.

ما يجب حذفه (حوالي 120 سطراً):

معظم قسم أوامر التطوير (70 سطراً → 10): bin/setup / bin/rails db:migrate / bundle exec rspec / bin/rubocop / bin/brakeman كلها أوامر Rails قياسية، موجودة في تدريب Claude. يُستبقى فقط الثلاثة الخاصة بالمشروع: bin/jobs (Solid Queue worker)، bin/importmap pin (خاصّ بـ ImportMap)، bin/kamal deploy.

قائمة Core Domain Models (35 سطراً → حذف كامل): إدراج 20 نموذجاً باسم ودور هو أوضح نموذج لـ "CLAUDE.md بأسلوب README" — Claude يشغّل ls app/models/ أو يقرأ ملف نموذج واحداً ويعرف. دسّه في كل محادثة هدر صافٍ.

العناصر القياسية في Tech Stack (28 سطراً → 8): Rails 8 / Devise / Pundit / Tailwind / pg_search كلها تُقرأ من Gemfile فوراً. يُستبقى فقط ما هو مضادّ للبديهة: Propshaft / ImportMap / Lexxy / x402-rails / Grover.

معرفة برمجية عامّة متناثرة: "Controllers should be thin"، "Use app/jobs/ for async processing"، ما تختبره request specs / model specs — هذه يفعلها Claude افتراضياً. هدر tokens.

المتبقّي نحو 100 سطر: اتفاقيات توجيه URL، توزيع الأربع قواعد، عتبتا VIP 400 / Hot 15، تجاوز Lexxy، خيارات معمارية مضادّة للافتراضي، لافتة Pundit، قائمة اللغات، FactoryBot (not fixtures).

لكن الأهم: أيّ invariant لم يُكتب بعد؟

أثناء التدقيق أدركتُ عدة أمور كان يجب إضافتها ولم أضفها:

  • الأرقام المدفونة داخل نظام هيئة المحلّفين (عتبات التصويت، شروط أهلية المحلّف) — غير معروضة في CLAUDE.md إطلاقاً
  • إن كان لـ x402 chain id أو عنوان عقد أو env var إلزامي — Claude لن يفتّش ملفات الإعداد وسيخترع قيماً من تلقاء نفسه
  • قواعد مخصوصة في خدمات تداول النقاط / Referral

238 سطراً تُقلَّص إلى 100–120 سطراً، ثم تضاف 5–10 أسطر من invariants سبق إغفالها — هذا أقرب إلى "الكثافة الصحيحة" لـ CLAUDE.md.

هذه ليست دروس تعليم، بل تدقيق على مشروعي أنا. أنا أيضاً لم أكتبه صحيحاً. الشكل الصحيح لـ CLAUDE.md هو الحذف المستمرّ والإضافة المستمرّة — كلّما نضج المشروع قليلاً، يجب أن يصبح CLAUDE.md أقصر وأصلب.

خمسة أسئلة قبل إدخال أيّ قاعدة

كلّما فكّرت بإضافة شيء إلى CLAUDE.md، أُجري عليه القائمة التالية:

  1. هل يستطيع Claude اشتقاق هذه القاعدة بقراءة ثلاثة ملفات؟ إذا نعم — لا تكتبها، دعه يقرأ بنفسه.
  2. هل هذه القاعدة مضادّة للبديهة؟ (عتبات غير معتادة، اختيار مكتبة خارج التيار، إعدادات تناقض الافتراضيات). إذا نعم — يجب كتابتها.
  3. هل هي invariant على مستوى الـ codebase، أم تؤثّر على ملف واحد فقط؟ القواعد المحصورة بملف واحد تُوضع كتعليق كود، ولا تُرفع إلى CLAUDE.md.
  4. هل خرق هذه القاعدة يجعل Claude يُخطئ بصمت؟ (بدون خطأ ظاهر، لكن المعنى غير صحيح — قاعدة بيانات خاطئة، ترجمة ناقصة، فحص policy متجاوَز). إذا نعم — يجب كتابتها.
  5. هل يمكنك شرحها في ثلاثة أسطر؟ إذا لا — أنت نفسك لم تهضمها بعد، لا تكتبها.

القواعد التي تجتاز الخمس جميعاً تبقى، وما لا يتحصّل على إجابة عن أيّ سؤال يُحذف أو يُعاد صياغته.

الخلاصة في سطر

الاستعمال الصحيح لـ CLAUDE.md ليس "تقديم المشروع"، بل ضغط المعرفة الضمنية بينك وبين الـ codebase، تلك التي لا يملؤها Claude مهما قرأ الكود — اختيارات شاذّة، عتبات غير مرئية، اتفاقيات مخالفة للافتراضيات، قيود خارجية على مستوى المشروع.

كل سطر تكتبه يجب أن يُجيب على سؤال: "هل هذه معلومة لا يمكن لـ Claude قراءتها من الكود؟" لا يمكن — تبقى. يمكن — تُحذف.

CLAUDE.md مكتوب بهذا الأسلوب عادة ما يقصر عن نسخته الأولى بأكثر من النصف، لكنه لكلّ محادثة أثمن بكثير من آلاف الكلمات من وصف الميزات. كما أنه لن يكتمل أبداً — كلّ ميزة جديدة تُسلّط الضوء على invariant كان ينبغي إدراجه سابقاً، وعلى فقرة كُتبت قديماً وحان وقت حذفها. الحذف والإضافة — تلك هي الصيانة اليومية لـ CLAUDE.md.