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 הן 6 הקטגוריות הבאות.

6 הקטגוריות שבאמת מצילות

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

כל שורה מתנגדת לניחוש ברירת המחדל. כשרואה פרויקט Rails, ההנחות של Claude כברירת מחדל הן:

  • נכסים סטטיים עוברים Sprockets (אינרציה של פרויקטים ותיקים)
  • JS דרך Webpacker או esbuild
  • הפרונט הוא React, או ערבוב Stimulus + Turbo
  • Rich text הוא ActionText רגיל

בלי השורות האלה ב-CLAUDE.md, בקשו מ-Claude להוסיף פיצ'ר JS חדש: סיכוי גבוה שיתקין Webpacker, יערוך package.json, יכתוב config של bundler — הכל שגוי, ושגוי בשקט (האפליקציה רצה, אבל pipeline הנכסים מזוהם).

השורות האלה ב-CLAUDE.md אומרות ל-Claude: אל תנחש, כבר הוחלט.

2. חלוקת multi-database

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

ניסוח פשוט, אבל יכול לחסוך לילה שלם. Multi-DB כברירת מחדל ב-Rails 8 היא התנהגות חדשה — Claude לא יבדוק מיוזמתו כמה DBs אתם משתמשים. מיגרציה תמימה למראה נוחתת ב-DB הלא נכון, ב-dev אין שגיאה (ארבעתם PostgreSQL, ה-schema מתבצע בכל מקום). אבל בפרודקשן טבלת ה-job של Solid Queue מסתננת לגיבוי של primary, או שמודל של primary שולח שאילתה ל-DB של 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 סוג short link חדש — בסבירות גבוהה יפיק slug בן 6 תווים, בסגנון UUID או אך ורק ספרות — מחוץ לשפה הוויזואלית של המערכת.

המאפיין של "הסכמות" כאלה: הפרה לא מייצרת שגיאה, אבל קורא הקוד הבא ירגיש שמשהו לא מסתדר. חובה לכתוב.

4. ערכי סף עסקיים קשיחים

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

שני המספרים חיים איפשהו בקוד (User#vip?, scope Post#hot?). הבעיה: כש-Claude נוגע במשהו סמוך — מכוון תגמולי נקודות, מוסיף התראת "כמעט VIP", כותב cron שנועץ hot posts — הוא לא יישר את הספים באופן אוטומטי במקומות אחרים.

התוצאה: אתם מתגמלים משימה ב-500 נקודות אבל הטקסט אומר "אתה יכול להיות VIP" (400 מספיק); או שאתם מזינים seed data לפיצ'ר חדש עם מעט לייקים ולעולם לא חוצים את סף ה-15.

יכולות הקוד של Claude חזקות, אבל אין לו תחושה מספרית מערכתית. שימת הספים הקריטיים ב-CLAUDE.md גורמת לכל שיחה להתחיל עם הידיעה ש"400 ו-15 הם מספרים מיוחדים".

5. שלט הכוונה ל-stack של auth/authz

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

תפקידה של השורה הזו הוא ניווט, לא תיאור.

בלעדיה, כש-Claude צריך להוסיף בקרת הרשאה חדשה, שלוש אפשרויות:

  • כותב unless current_user.admin? היישר בתוך ה-controller
  • חופר שרידים של CanCan שכבר לא בשימוש
  • ממציא שיטה authorize? משלו במודל

עם "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)

אבל הפרויקט שלכם זקוק בפועל ל:

  • תרגומים ב-3 locales
  • RSpec + FactoryBot, לא fixtures

הפרה של "אילוצים חיצוניים ברמת פרויקט" כאלה מייצרת ערמה של עבודת ניקוי בדיעבד — תרגומים להשלמה, בדיקות לשכתוב. כתיבה ב-CLAUDE.md מעגנת פעם ולתמיד את "הדברים שחייבים להתבצע בכל פעם".

הצד השני: את זה לא שווה לכתוב

חשוב באותה מידה כמו "חובה לכתוב" הוא "אל תכתוב". הקטגוריות הבאות — רואים = מוחקים:

1. תיאורי פיצ'רים

"מערכת חבר המושבעים: משתמשים יכולים לדווח על תוכן מפר, המדווח נכנס להצבעה ציבורית, חברי המושבעים נבחרים מ..."

→ Claude יפתח topic_review_service.rb ויקרא בדיוק רב יותר מכפי שכתבתם. לדחוף את זה לכל שיחה חדשה זה בזבוז טהור.

2. מה שנקרא מידית מעץ הספריות / Gemfile

"app/models/ מכיל מודלים של ActiveRecord", "משתמש ב-Rails 8", "DB הוא PostgreSQL"

→ Claude מעיף מבט בשורש הפרויקט וב-Gemfile — יודע.

3. ידע תכנות כללי

"Controllers should be thin, delegate to services", "הימנעו מ-N+1", "כתבו בדיקות לפיצ'רים העיקריים"

→ זה כבר בנתוני האימון של Claude. כתבו את זה רק אם הפרויקט שלכם חריג — לדוגמה "אנחנו בכוונה לא משתמשים בשכבת service; הלוגיקה חיה ב-controllers".

4. הקשר של המשימה הנוכחית

"כרגע אנחנו עושים refactor למערכת התשלומים; הדגש הוא..."

→ זה הקשר שיחה, לא עובדה של פרויקט. זריקה ל-CLAUDE.md מזהמת את כל השיחות האחרות.

ביקורת שטח: גם ה-CLAUDE.md שלי ניתן לחתוך לחצי

שימו את ההוכחה "אני יכול לעשות את זה" לפני הדרשה. אחרי שכתבתי את הסעיף למעלה, העברתי את ה-CLAUDE.md של Pickful — 238 שורות — דרך 5 השאלות שלי. התוצאה: בערך חצי הוא בזבוז.

מה לחתוך (~120 שורות):

רוב בלוק פקודות הפיתוח (70 שורות → 10): bin/setup / bin/rails db:migrate / bundle exec rspec / bin/rubocop / bin/brakeman — כולן פקודות Rails סטנדרטיות, כבר בתוך אימון Claude. להשאיר רק שלוש הייחודיות לפרויקט: bin/jobs (worker של Solid Queue), 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, חלוקת 4 DB, ספי VIP 400 / Hot 15, override של Lexxy, בחירות ארכיטקטורה אנטי-ברירת מחדל, שלט Pundit, רשימת locales, FactoryBot (לא fixtures).

אבל חשוב יותר: אילו invariants עדיין חסרים?

במהלך הביקורת הבנתי כמה פריטים שהייתי צריך להוסיף ולא הוספתי מעולם:

  • מספרים קבורים במערכת חבר המושבעים (סף הצבעה, דרישות כשירות של חבר מושבעים) — כלל לא חשופים ב-CLAUDE.md
  • אם ל-x402 יש chain id, כתובת חוזה, env vars נדרשים — Claude לא ילך ל-grep בקובץ ה-config וימציא ערכים
  • כללי אילוץ מיוחדים בשירותים של point-trading / Referral

238 שורות לדחוס ל-100–120, להוסיף 5–10 שורות של invariants שפוספסו — זה קרוב יותר ל"צפיפות הנכונה" של CLAUDE.md.

זה לא טוטוריאל. זו ביקורת על הפרויקט שלי עצמי — וגם אני לא כתבתי נכון. הצורה הנכונה של CLAUDE.md היא למחוק ברציפות ולהוסיף ברציפות — כל פרויקט שמתבגר מעט אמור להיות בעל CLAUDE.md קצר יותר וצפוף יותר עם הזמן.

5 שאלות לפני הכנסת חוק

בכל פעם שאני רוצה להוסיף משהו ל-CLAUDE.md, אני מעביר אותו דרך ה-checklist הבא:

  1. האם Claude יכול להסיק את החוק הזה מקריאת 3 קבצים? כן — אל תכתבו, תנו לו לקרוא.
  2. האם החוק הזה אנטי-אינטואיטיבי? (ספים חריגים, בחירת ספרייה לא מיינסטרים, config שסותר את ברירות המחדל של upstream.) כן — חובה לכתוב.
  3. האם הוא invariant ברמת כל ה-codebase, או משפיע על קובץ אחד בלבד? קובץ אחד — הערת קוד, לא להעלות ל-CLAUDE.md.
  4. האם הפרה תגרום ל-Claude לטעות בשקט? (בלי שגיאה, אבל סמנטיקה שגויה — DB לא נכון, תרגום חסר, policy מדולגת.) כן — חובה.
  5. האם אפשר להסביר ב-3 שורות? לא — אתם בעצמכם עדיין לא חידדתם. לא לכתוב בינתיים.

חוקים שעברו את כל ה-5 נשארים; אחד שלא עובר — מוחקים או משכתבים.

סיכום בשורה אחת

השימוש הנכון ב-CLAUDE.md אינו "להציג את הפרויקט", אלא לדחוס את הידע המובלע בינכם לבין ה-codebase, שאותו Claude לעולם לא ישלים מקריאת קוד — בחירות חריגות, ספים בלתי נראים, הסכמות נגד ברירות מחדל, אילוצים חיצוניים ברמת הפרויקט.

כל שורה שאתם מוסיפים צריכה לענות על שאלה: "האם זה משהו ש-Claude לא יקרא מהקוד?" לא יקרא — נשאר. יקרא — מוחקים.

CLAUDE.md כתוב כך הוא בדרך כלל יותר מחצי קצר מהטיוטה הראשונה, אבל ערכו לכל שיחה גדול לאין שיעור מאלפי מילים של תיאור פיצ'רים. והוא תמיד "עוד לא גמור" — כל פיצ'ר חדש ששולחים מאיר invariant נוסף שהיה אמור להיות בפנים, ופסקה נוספת שכעת אפשר לחתוך. למחוק ולהוסיף, למחוק ולהוסיף — זו התחזוקה היומית של CLAUDE.md.