Większość szablonów CLAUDE.md, które znajdziesz w internecie, ma 300 linii. I jest gorsza niż brak CLAUDE.md w ogóle.
W tym artykule pokażę Ci mój szablon dla projektów .NET - 65 linii. Przejdziemy przez każdą sekcję i powiem Ci dlaczego to, co w nim jest, tam być musi - a czego celowo nie ma.
Cześć! CLAUDE.md to plik w katalogu głównym Twojego repo, który Claude Code czyta na starcie każdej sesji. To jego stałe wprowadzenie do projektu. Bez niego w każdej nowej rozmowie tłumaczysz Claude'owi od zera, co używacie, jakie macie konwencje, gdzie co leży.
Rzecz, której większość poradników nie powie: przeładowany CLAUDE.md jest gorszy od jego braku. Anthropic mówi to wprost w swojej dokumentacji - przeładowany kontekst pogarsza wyniki. Każda linia w Twoim CLAUDE.md konkuruje o uwagę modelu.
W tym artykule pokażę plik. Pójdziemy sekcja po sekcji z uzasadnieniem. Przeczytaj całość - pokażę też, czego w moim CLAUDE.md CELOWO nie ma, bo to jest równie ważne.
Cały plik Claude.md:
# Project: [Nazwa projektu] ASP.NET Core 10 Web API. Domena: [krótko, 1 zdanie]. ## Stack - .NET 10, C# 14 - EF Core 10 + SQL Server - MediatR (CQRS) - FluentValidation - Serilog + Seq - xUnit + AwesomeAssertions + Moq + WebApplicationFactory ## Struktura - `/src/Api` — kontrolery, DI, middleware, Program.cs - `/src/Application` — CQRS (`Features/<Moduł>/<NazwaFeature>`), behaviors, walidatory - `/src/Domain` — encje, value objecty, domain events - `/src/Infrastructure` — EF Core (`ApplicationDbContext`, konfiguracje), integracje - `/tests/UnitTests` — testy warstw Application + Domain - `/tests/IntegrationTests` — testy API z `WebApplicationFactory<Program>` Feature = folder `/Features/<Moduł>/<NazwaFeature>/` z plikami: `<Nazwa>Command.cs` (albo Query), `<Nazwa>Handler.cs`, `<Nazwa>Validator.cs`, `<Nazwa>Endpoint.cs`. ## Komendy - Build: `dotnet build` - Testy jednostkowe: `dotnet test tests/UnitTests` - Testy integracyjne: `dotnet test tests/IntegrationTests` - Run lokalnie: `dotnet run --project src/Api` - EF migrations: `dotnet ef migrations add <Nazwa> -p src/Infrastructure -s src/Api` ## Konwencje - **Nazewnictwo**: `CreateOrderCommand` + `CreateOrderHandler` + `CreateOrderValidator` + `OrdersEndpoints` - **DTO**: requesty → `<Nazwa>Request`, odpowiedzi → `<Nazwa>Response`, persystencja → encje Domain - **Testy**: `Should_<oczekiwanie>_When_<warunek>` (np. `Should_ReturnValidationError_When_QuantityIsZero`) - **Async**: wszystkie publiczne metody zwracające I/O są async, z `CancellationToken` jako ostatni parametr - **Read-only queries w EF Core**: ZAWSZE `AsNoTracking()` ## Używamy - **Result pattern** dla błędów biznesowych (nie wyjątki): `Result<T>` z `Application.Common.Results` - **Value objects** dla identyfikatorów domenowych (`OrderId`, `CustomerId`) - **Domain events** do komunikacji między agregatami - **Minimal APIs + endpoint classes** (nie `ControllerBase`) ## NIE używamy - **NIE** `Repository<T>` generic — pracujemy bezpośrednio przez `IApplicationDbContext` - **NIE** AutoMapper — mapowanie ręczne w handlerach - **NIE** `throw new Exception(...)` dla błędów walidacji/biznesowych — używaj `Result<T>` - **NIE** `async void` poza event handlerami - **NIE** zmieniaj publicznego API bez uzgodnienia ## Git - Branche: `feature/<jira-id>-<short-desc>`, `fix/<jira-id>-<short-desc>` - Commity: conventional commits — `<type>(<scope>): <message>` - NIE commituj do `main` bezpośrednio — zawsze PR ## WAŻNE - Dla zmian dotykających **>3 plików**: używaj Plan Mode i pokaż plan do zatwierdzenia - Po każdej serii zmian: uruchom `dotnet build` i odpowiednie testy — pokaż wynik - Nigdy nie commituj sekretów (connection strings, API keys) — sprawdź diff przed commitem - Przed zmianami w migracjach EF Core: pokaż diff wygenerowanej migracji do review
To jest to. 65 linii, dokładnie tyle. Sekcje: Stack, Struktura, Komendy, Konwencje, Używamy, NIE używamy, Git, WAŻNE.
Każda sekcja ma 5 do 8 linii. Żadna nie dominuje. To nie jest dokumentacja. To jest krótkie wprowadzenie.
Idziemy sekcja po sekcji.
Nagłówek i Stack
Nagłówek - 2 linie. Nazwa projektu, jedno zdanie o tym, co to jest i jaka domena.
Nie ma tu opisu wymagań biznesowych ani historii. Claude potrzebuje orientacji, nie szczegółowego wprowadzenia produktowego. "System zarządzania zamówieniami dla dystrybutora B2B" - wystarczy.
Stack – z wersjami. To krytyczne. ".NET 10", nie ".NET". "EF Core 10", nie "EF Core". Bez wersji Claude może użyć składni z poprzedniej wersji, która już się nie kompiluje.
Popatrz, czego tutaj NIE ma. Nie ma Microsoft.Extensions.DependencyInjection, Microsoft.Extensions.Configuration, System.Text.Json. Claude wie, że są w .NET 8. Wypisuję tylko rzeczy, które są decyzją - MediatR, FluentValidation, Serilog. Tego Claude sam nie zgadnie.
Struktura projektu
Struktura – każda linia to folder plus jego cel. Nie opis zawartości.
Rozróżnienie subtelne, ale ważne. "Application zawiera klasy Command" - to opis. Claude sam to zobaczy. "Application - CQRS, Features, behaviors, walidatory" - to cel. Claude wie, czego tam szukać.
Spójrz na ostatnią linię tej sekcji.
"Feature = folder z plikami Command, Handler, Validator, Endpoint". To jest wzór, który Claude musi znać. Bez niego, dodając nowy endpoint, rozrzuci pliki po różnych folderach. Z tym - zbuduje strukturę zgodną z resztą projektu.
To jeden z najlepszych zwrotów z inwestycji w cały plik.
Komendy
Komendy - konkretnie, ze ścieżkami.
Szczególnie ta:
dotnet ef migrations add -p src/Infrastructure -s src/Api.
Bez tych flag nie zadziała, bo w solucji .NET często projekt startupu jest osobny od projektu migracji. Claude nie zna Twojej konfiguracji. Podpowiedz mu.
Rozdzielam też testy jednostkowe od integracyjnych. Czemu - integracyjne są wolne. Nie chcę, żeby Claude po każdej drobnej zmianie uruchamiał pełny zestaw. Chcę mieć kontrolę.
Konwencje (tylko te, których Claude nie zgadnie)
Tu jest krytyczne rozróżnienie, którego większość ludzi nie robi.
Nie piszę "używaj PascalCase dla publicznych właściwości". Wie. Nie piszę "klasy w osobnych plikach". Wie.
Piszę konwencje, których Claude nie zgadnie:
• Konwencja nazewnictwa testów - w każdym projekcie inna
• AsNoTracking() dla zapytań tylko do odczytu - nawyk, którego Claude domyślnie nie stosuje
• CancellationToken jako ostatni parametr - to standard w .NET, ale łatwo go pominąć
Popatrz na słowo ZAWSZE dużymi literami przy AsNoTracking(). Anthropic potwierdza w dokumentacji: emfaza typu "IMPORTANT" czy "YOU MUST" realnie poprawia przestrzeganie reguł. Używam oszczędnie - tylko tam, gdzie reguła musi trafiać w 100% przypadków.
Używamy / NIE używamy
To jest najważniejsza sekcja w całym pliku. I ta, którą najczęściej zmieniam.
Dlaczego: Claude zna wszystkie popularne wzorce. Repository<T>, AutoMapper, throw new Exception. Bez wytycznych zastosuje cokolwiek wydaje mu się sensowne. Jeśli w Twoim projekcie to nie pasuje - dostaniesz kod, który jest stylistycznie OK, ale strukturalnie obcy.
I tu jest rzecz, która zaskakuje: jawne NIE jest mocniejsze niż jawne TAK.
Czemu? Claude domyślnie robi to, co najczęściej widział w danych treningowych. Pozytywna instrukcja konkuruje z tym nawykiem. Zakaz go wycina.
"Używamy Result pattern" może zostać zignorowane, jeśli Claude ma silną tendencję do throw. "NIE używamy throw new Exception() dla błędów walidacji" - to jest zakaz, który Claude traktuje znacznie poważniej.
Ta sekcja ratuje mnie codziennie. I ewoluuje w czasie. Kiedy zauważysz, że Claude ciągle robi coś inaczej niż chcesz, zamiast korygować go w każdej sesji - dodaj linię do "NIE używamy". Rozwiązujesz problem raz na zawsze.
Git
3 linie. Nie piszę tu, jak działa git. Piszę, jak działa git w tym projekcie.
Bez tej sekcji Claude commitował do main, nie trzymał się conventional commits, nie stosował naszej konwencji nazw branchy. Teraz trzyma w 100%.
Jeśli Twój zespół ma inny przepływ pracy z gitem - dopisz to tutaj.
WAŻNE
4 linie. Każda jest odpowiedzią na konkretny błąd, który popełniłem w pierwszych miesiącach.
Plan Mode dla zmian większych niż 3 pliki - bo kilka razy Claude poszedł w złą stronę na 10 plikach.
Build i testy po każdej serii zmian - bo commitował kod, który się nie kompilował.
Diff migracji EF Core do review - bo raz autogenerowana migracja miała DropColumn na kolumnie z danymi.
"WAŻNE" używam tylko dla reguł, które realnie chronią projekt. Nie dla stylistyki. Jeśli dasz wszystkiemu status "WAŻNE", nic nie będzie ważne.
Czego CELOWO NIE ma
I teraz sekcja, o której najrzadziej się mówi - czego w moim CLAUDE.md świadomie nie umieszczam.
Zasady stylu kodu - wcięcia, spacje, using statements. EditorConfig i linter robią to lepiej. Nie dubluj.
Dokumentacja biznesowa - link przez @docs/domain.md jeśli potrzebujesz. Nie wklejaj.
Lista wszystkich NuGetów - Claude czyta .csproj. Wypisuję tylko te, które są architektoniczną decyzją.
Przykłady kodu - Claude czyta projekt. W sesji powiesz mu "popatrz na @SomeFeature jako wzór". Nie kopiuj kodu do CLAUDE.md.
Sekrety, connection stringi - kategoryczne nie. Plik trafia do gita.
Reguła, która tu działa: każda linia w CLAUDE.md musi odpowiadać na pytanie "czy bez tej informacji Claude popełniłby błąd?". Jeśli nie - wyrzuć.
Zapamiętaj to zdanie, wrócimy do niego.
Jak ewoluować w czasie + demo "przed/po"
2 nawyki, które najbardziej mi się sprawdziły.
Pierwszy - komenda /memory w sesji Claude Code. Wpisujesz /memory, otwiera Ci się CLAUDE.md w edytorze, dopisujesz linię, zapisujesz. Claude od następnej wiadomości stosuje regułę.
Krótka uwaga, bo to się ostatnio zmieniło i sporo poradników jest nieaktualnych: jest też skrót #, ale on już NIE dopisuje do CLAUDE.md. Wpisy z # trafiają do osobnej pamięci automatycznej Claude'a - to inny system. Jeśli chcesz, żeby reguła wylądowała w CLAUDE.md i była commitowana z projektem do gita, używaj /memory. To ważne rozróżnienie.
Pokażę Ci to w praktyce.
(1) Pytasz Claude'a o coś typowego - np. "napisz zapytanie pobierające zamówienia klienta o danym ID". Tutaj prawdopodobnie Claude napisze kod bez AsNoTracking(). To jest "przed".
(2) Wpisujesz /memory, w edytorze dopisujesz "ZAWSZE używaj AsNoTracking() w zapytaniach read-only", zapisujesz plik.
(3) Zadajesz to samo pytanie ponownie - Claude pisze kod z AsNoTracking(). To jest "po".
1 scena, 2 problemy rozwiązane - widzisz, jak działa /memory, i widzisz konkretną różnicę w zachowaniu Claude'a.
Drugi nawyk - regularny przegląd. Raz na tydzień-dwa otwieram plik i pytam: "czy gdyby tej linii nie było, Claude popełniłby błąd?". Jeśli nie - wyrzucam. Plik powinien być krótszy z czasem, nie dłuższy.
Najważniejsze
Szablon masz na górze artykułu - do skopiowania. Skopiuj, dostosuj nawiasowane elementy, wrzuć do swojego repo.
Po tygodniu używania zobaczysz różnicę, której nie da się opisać liczbami. Claude zacznie zachowywać się jak ktoś, kto zna Twój projekt, zamiast jak zewnętrzny konsultant.
Powtórzę regułę z segmentu 9, bo to jest jedyna rzecz, którą musisz zapamiętać z tego artykułu: czy bez tej informacji Claude popełniłby błąd? Jeśli nie - wyrzuć.
Jeśli chcesz szablony CLAUDE.md dla różnych typów projektów .NET - czystej architektury, DDD, architektury hexagonalnej, monorepo, mikroserwisów - plus przykłady z prawdziwych projektów pokazujące, jak szablon ewoluuje przez pół roku pracy, to w Szkole 3x Dev - jak budować aplikacje szybciej dzięki AI mam to rozpisane z gotowymi plikami.