Przejdź do głównej zawartości

CLAUDE.md / AGENTS.md — warstwowy kontekst, który przeżywa każdą sesję

Pytanie 4 (Inżynieria kontekstu): Jak wygląda Twój CLAUDE.md / AGENTS.md w typowym projekcie?

Odpowiedź na max: Warstwowa hierarchia, regularnie audytowana — global + projekt + .claude/rules/ per obszar.

Każda sesja Claude Code, Codex czy Cursor startuje jako pusty mózg. Agent nie wie, którego package managera używasz, który folder to API, czy wolno mu robić git push --force, ani że zespół ostatnio ustalił, żeby przestać używać useEffect do fetchowania danych. Bez trwałego kontekstu spędzasz pierwsze dziesięć minut każdej sesji na re-tłumaczeniu projektu — albo gorzej, pomijasz ten krok i wypuszczasz kod, który łamie Twoje własne konwencje.

CLAUDE.md i AGENTS.md są rozwiązaniem. To zwykłe pliki Markdown, które agent ładuje automatycznie przy starcie. Dobrze ustrukturyzowana hierarchia oznacza, że agent wchodzi w każdą sesję wiedząc już o globalnych regułach, które obowiązują we wszystkich Twoich projektach (bez średników, rg zamiast grep), o stacku i komendach specyficznych dla projektu oraz o głębokich regułach per obszar, które liczą się tylko wtedy, gdy dotyka auth, bazy danych albo integracji płatności.

Dźwignia jest ogromna. Godzina poświęcona na napisanie warstwowego kontekstu zwraca się w nieskończoność: każda przyszła sesja, każdy równoległy agent, każdy członek zespołu, który odpali to samo repo, startuje od tej samej bazy. Pomiń to i płacisz wieczny podatek “wytłumacz projekt od nowa” — własny best practices guide Anthropica nazywa dobrze dostrojony CLAUDE.md zmianą o największej dźwigni, jaką możesz wprowadzić w Claude Code.

Twistem 2026 jest AGENTS.md. To otwarty, niezależny od narzędzia standard wspierany przez OpenAI, Sourcegraph, Cursor, Google i Factory (pod patronatem Agentic AI Foundation w ramach Linux Foundation), więc ten sam plik działa z Codex, Cursor, Copilot i każdym innym agentem. Jeśli piszesz tylko instrukcje pod Claude, przepiszesz je od nowa w momencie, gdy kolega z zespołu otworzy Cursor. Setup na maksa używa obu — i traktuje je jako żywą, audytowaną część kodu, nie jednorazowy artefakt z /init.

Warstwowa hierarchia to trzy poziomy kontekstu, każdy ograniczony do innego obszaru, każdy na tyle mały, by nie napuchnąć w oknie kontekstowym. Tak to wygląda:

~/.claude/CLAUDE.md # Global: Twoje osobiste defaulty, ważne w każdym repo
project-root/
├── AGENTS.md # Projekt: niezależny od narzędzia, czytany przez Codex/Cursor/Copilot
├── CLAUDE.md → AGENTS.md # Symlink, żeby Claude Code czytał ten sam plik
└── .claude/
├── CLAUDE.md # Override'y specyficzne dla Claude (opcjonalnie)
└── rules/
├── auth.md # Per obszar: ładuje się tylko przy pracy nad auth
├── db.md # Per obszar: schema, migracje, wzorce zapytań
├── payments.md # Per obszar: specyfika Stripe/Polar
├── testing.md # Per obszar: konwencje Vitest, fixture'y
└── api.md # Per obszar: route handlery, kształty błędów

Nie chodzi o to, by wypełnić każdą warstwę — chodzi o to, że każda warstwa ma jedną rolę i wiesz dokładnie, gdzie należy nowa reguła. Global = “prawda w każdym repo, którego kiedykolwiek dotknę”. Projekt = “prawda w tym kodzie, niezależnie od tego, który agent go czyta”. Per obszar = “prawda tylko wtedy, gdy agent edytuje ten wycinek systemu”.

Regularnie audytowana hierarchia oznacza, że przeglądasz ją w stałym rytmie (miesięcznie lub per sprint), przycinasz to, co już nie obowiązuje, promujesz powtarzające się korekty na reguły i degradujesz reguły, których wszyscy już przestrzegają z automatu.

Warstwa globalna to Twój osobisty ~/.claude/CLAUDE.md — czytany raz na sesję dla każdego projektu na Twojej maszynie. Tu trafiają preferencje, które są prawdziwe niezależnie od repo: domyślny edytor, ulubione narzędzia shellowe (rg zamiast grep, fd zamiast find), styl commit message, kiedy pytać przed odpaleniem destrukcyjnych komend, dowolne workflow auto-PR czy automatyzacji przeglądarki, które chcesz, żeby agent stosował wszędzie.

~/.claude/CLAUDE.md
## Defaulty we wszystkich projektach
- Używaj `rg` (ripgrep) zamiast `grep`/`find` do szukania.
- Pojedyncze cudzysłowy w importach JS/TS; podwójne w atrybutach JSX.
- Commit message: conventional commits, czas teraźniejszy, bez body chyba że trzeba.
- Nigdy nie odpalaj `git push --force` do `main`/`master` bez wyraźnej zgody.
## Automatyzacja przeglądarki
Domyślnie używaj `browser-harness` do weryfikacji E2E.
Fallback: agent-browser → chrome-devtools MCP → Playwright.
## Workflow auto-PR
Po commitach o znaczeniu merytorycznym pushuj i otwórz PR przez `gh pr create`.
Przy komentarzach z review fetchuj `gh pr view --comments` i adresuj każdy
przed re-pushem. Nie pauzuj na potwierdzenie w żadnym z kroków.

Trzymaj plik globalny poniżej 200 linii. Frontierowe modele potrafią konsekwentnie podążać za 150–200 instrukcjami; powyżej tego reguły zaczynają być po cichu pomijane.

Warstwa projektowa to najważniejszy pojedynczy plik. Jest wpięty w repo, dzielony z zespołem i czytany przy każdej sesji w tym kodzie. Powinien odpowiadać na pytania, które nowy kontrybutor zadałby w pierwszej godzinie: co robi ten projekt, jaki jest stack, jakie są komendy, gdzie co leży i jakie są nieoczywiste reguły.

AGENTS.md
## Project overview
Edge-renderowany docs site dla developertoolkit.ai. Astro 5 + Starlight,
Cloudflare Workers, D1 do auth/subskrypcji, Polar.sh do płatności.
## Stack & commands
- `npm run dev` — Astro dev server na :4321
- `npm run dev:cf` — Wrangler z prawdziwymi bindingami CF
- `npm run lint && npm run type-check && npm run test` — musi przejść przed push
- Deploy idzie tylko z CI na push do `master`. Nie odpalaj `npm run deploy` lokalnie.
## Key directories
- `src/content/docs/{en,pl}/` — dwujęzyczna treść MDX
- `src/lib/db/` — Drizzle schema + zapytania do D1
- `src/pages/api/` — route handlery (użyj `locals.runtime.env` do bindingów)
- `public/paywall-inline.js` — vanilla JS paywall, nie konwertuj na TS
## Conventions
- Server components domyślnie; oznaczaj `'use client'` tylko gdy faktycznie trzeba.
- Drizzle do zapytań D1 — żadnych raw SQL poza `scripts/schema.sql`.
- Astro env: `import.meta.env.PUBLIC_*` w build, bindingi w runtime.
## Nieoczywiste pułapki
- Paywall siedzi w `public/paywall-inline.js` (NIE TypeScript) i jest
ładowany jako `<script>` z `Head.astro`. Edytuj JS bezpośrednio.
- Submoduły trzymają prywatną treść docs. Odpal `npm run submodule:update`
po świeżym clone albo CI nie zbuduje.

Symlink CLAUDE.md → AGENTS.md oznacza, że Claude Code, Cursor i Codex czytają ten sam plik. Jeśli potrzebujesz instrukcji tylko-Claude (np. konkretny hook), wrzuć je do .claude/CLAUDE.md, żeby nie zaśmiecały wspólnego pliku.

To warstwa, którą większość setupów pomija — i to ona oddziela odpowiedź na max od tej “tylko dobrej”. Katalog .claude/rules/ trzyma modularne pliki .md, każdy ograniczony do jednego wycinka systemu. Docs Anthropica o pamięci potwierdzają, że pliki .claude/rules/*.md ładują się razem z CLAUDE.md i wspierają YAML frontmatter z polem paths, więc reguły można scope’ować po glob i ładują się tylko wtedy, gdy agent faktycznie dotyka tych plików.

---
paths:
- "src/lib/auth/**"
- "src/pages/api/auth/**"
---
# Reguły auth
Używamy BetterAuth z Email-OTP + Polar.sh do subskrypcji.
## Mental model
- BetterAuth posiada sesje, accounts i flow OTP.
- Polar.sh posiada stan subskrypcji, karmiony przez webhook do `subscription_access_tokens`.
- Zalogowany user bez aktywnej subskrypcji dostaje 402 z gated route.
## Do
- Używaj helperów `auth.api.*` z BetterAuth; nigdy nie pisz własnego sprawdzania sesji.
- Stan subskrypcji czytaj z `subscription_access_tokens`, nie z API Polara
w czasie żądania (latencja + rate limity).
- Zawsze `await auth.api.getSession({ headers })` na samym początku gated handlera.
## Don't
- Nie twórz raw userów w tabeli `users`. Zawsze idź przez BetterAuth.
- Nie wołaj API Polara z handlera Worker request — dorzuca 300ms+.
- Nigdzie nie trzymaj kodów OTP plaintext — są hashowane w BetterAuth.
## Częsty bug
Bridge webhooka Polar jest async. Jeśli sprawdzasz stan subskrypcji od razu
po checkout success, wiersz z tokenem może jeszcze nie istnieć. Pollnij z backoff
albo użyj wzorca redirect-with-state z `src/pages/checkout/success.astro`.

Taki plik ładuje się tylko wtedy, gdy agent edytuje pliki auth — więc może być szczegółowy, nie wypierając reszty Twojego kontekstu. Ten sam wzorzec powtarza się dla db.md (schema, polityka migracji, częste gotcha Drizzle), payments.md (flow webhooka Polar.sh, klucze idempotencji), testing.md (konwencje Vitest, wzorce fixture’ów) i tak dalej. Walkthrough Knightli pokazuje czteroczęściowy setup — CLAUDE.md, rules, memory, hooks — i jak ze sobą współpracują.

Niektóre zespoły symlinkują reguły między repo (katalog .claude/rules/ wspiera symlinki z detekcją cykli), pozwalając, by zestaw “house style” pozostawał zsynchronizowany w każdym wewnętrznym projekcie.

  1. Zacznij od globalu, sesją pisania na 30 minut.

    Otwórz ~/.claude/CLAUDE.md i wypisz rzeczy, które powtarzasz każdemu agentowi w każdym projekcie: preferencje shellowe, domyślne wybory narzędzi, reguły “nigdy nie rób X bez pytania”. Trzymaj zwięźle — poniżej 100 linii spokojnie wystarczy. Cokolwiek specyficznego dla projektu nie należy tutaj.

  2. Odpal /init w najczęściej używanym repo.

    W Claude Code wpisz /init. Wygeneruje pierwszą wersję CLAUDE.md z uwzględnieniem projektu, czytając repo. Traktuj to jako punkt startowy, nie finalny artefakt. Zmień nazwę na AGENTS.md (lub zasymlinkuj), potem przytnij generyczną treść i zastąp ją konkretnymi, testowalnymi regułami “tak działa ten projekt”.

  3. Dodaj dlaczego do każdej nieoczywistej reguły.

    “Używaj Drizzle ORM” to reguła. “Używaj Drizzle ORM — raw SQL omija nasz connection pooling D1 i pada pod obciążeniem” to reguła, z której model umie generalizować. Przewodnik HumanLayer mówi to dosadnie: reguła z uzasadnieniem przeżywa edge case’y; reguła bez niego jest ignorowana.

  4. Stwórz .claude/rules/ i przenieś tam głębokie rzeczy.

    Za każdym razem, gdy główny CLAUDE.md/AGENTS.md zaczyna przekraczać 200 linii, podziel. Reguły specyficzne dla auth → .claude/rules/auth.md. Reguły bazy → db.md. Konwencje testów → testing.md. Każdy plik dostaje frontmatter paths:, żeby ładował się tylko wtedy, gdy agent faktycznie pracuje w tym obszarze.

  5. Symlinkuj dla kompatybilności między narzędziami.

    ln -s AGENTS.md CLAUDE.md. Teraz Claude Code, Codex i Cursor czytają ten sam kontekst projektu. Jeśli faktycznie potrzebujesz zachowania tylko-Claude (hook, referencja do slash commanda), wrzuć to do .claude/CLAUDE.md — ten plik jest Claude-only.

  6. Audytuj w stałym rytmie.

    Wstaw “audyt kontekstu” na 30 minut w kalendarz — miesięcznie lub na koniec każdego sprintu. Otwórz reguły. Skasuj to, co już oczywiste. Promuj rzeczy, na które poprawiałeś agenta trzy razy, na reguły. Degraduj reguły, do których nikt się nie odwołuje. Półtrwałość użytecznej instrukcji jest krótka; traktuj hierarchię jak żywy kod.

  7. Zweryfikuj świeżą sesją.

    Odpal nową sesję Claude Code w repo i spytaj: “Podsumuj kontekst projektu, który masz załadowany”. Jeśli odpowiedź nie zgadza się z tym, co obiecuje Twoja hierarchia, coś się nie ładuje — sprawdź ścieżki plików, składnię frontmattera i czy poprawnie zasymlinkowałeś.

Napuchnięcie do 500+ linii w jednym pliku. Powyżej ~200 linii w jednym pliku instrukcje zaczynają być po cichu gubione. Model nie powie Ci, że stracił regułę — po prostu nie będzie jej stosował. Dziel na .claude/rules/ długo przed momentem, w którym poczujesz presję.

Set-and-forget po /init. CLAUDE.md wygenerowany w dniu pierwszym i niewzięty już do ręki staje się przestarzały w jeden sprint. Pojawiają się nowe konwencje, stare umierają, a plik kłamie. Traktuj go jak każdy inny kod: PR-y zmieniające konwencje aktualizują też reguły.

Aspiracyjne reguły bez zębów. “Pisz czysty kod” nie mówi agentowi nic. “Server Components domyślnie; dodawaj 'use client' tylko wtedy, gdy potrzebujesz state’u, refs albo API z przeglądarki” jest testowalne. Każda reguła powinna być czymś, na co możesz zrobić review PR-a.

Brak “dlaczego” gdziekolwiek. Reguła bez powodu nie potrafi generalizować. Pierwszy edge case zmusi agenta do zgadywania — pewnie źle. Dwa zdania uzasadnienia per reguła są warte więcej niż dziesięć reguł bez nich.

Sekrety, osobisty styl albo stan specyficzny dla sesji w pliku projektu. Plik projektu jest wpięty w repo i dzielony z zespołem. Osobiste preferencje należą do pliku globalnego. Stan specyficzny dla biegu (lista zadań, TODO) należy do scratchu, nie do AGENTS.md.

Tylko-Claude, gdy zespół używa też Cursora. Jeśli kolega otworzy to samo repo w Cursor czy Codex, dostanie zerowy kontekst, chyba że pisałeś w AGENTS.md (lub zasymlinkowałeś). 60 000+ repo w 2026 używa już AGENTS.md jako domyślnego — to bezpieczniejszy wybór dla zespołów multi-tool.

Reguły per obszar bez scope’u paths:. Plik reguł bez frontmattera ładuje się na każdej sesji, niwecząc cały sens .claude/rules/. Dodawaj paths: do każdej rzeczy specyficznej dla obszaru, żeby ładowało się tylko, gdy ma znaczenie.

  • Mam ~/.claude/CLAUDE.md z osobistymi defaultami, poniżej 100 linii.
  • Mam projektowy AGENTS.md (lub CLAUDE.md zasymlinkowany do niego) wpięty w każde aktywne repo.
  • Plik projektowy odpowiada na “co to za projekt, jak go odpalić, gdzie co leży, jakie są nieoczywiste reguły” — i kończy się na tym.
  • Mam katalog .claude/rules/ z co najmniej jednym plikiem per obszar (auth, db, payments, testing — wybierz to, co u Ciebie złożone).
  • Każdy plik reguł per obszar ma frontmatter paths:, żeby ładował się tylko na istotnych plikach.
  • Każda nieoczywista reguła ma jednozdaniowe “dlaczego”.
  • Świeża sesja, zapytana o podsumowanie załadowanego kontekstu, wymienia prawdziwy stack projektu i prawdziwe reguły per obszar — nie generyczny boilerplate.
  • Mam powtarzający się 30-minutowy audyt w kalendarzu (miesięcznie lub per sprint).
  • Główny plik projektowy ma poniżej 200 linii; głębokie rzeczy zostały podzielone do .claude/rules/.
  • Hierarchia jest bezpieczna multi-tool — koledzy używający Cursora i Codex dostają ten sam kontekst, co ja.