Przejdź do głównej zawartości

Strategie dla milionów linii kodu z agentami

Agenci kodujący radzą sobie z bazami kodu liczącymi miliony linii dzięki doborowi kontekstu, a nie pojemności okna. Warstwowe pliki instrukcji niosą architekturę, a serwer MCP do analizy kodu znajduje symbole i wywołania. Raport zasięgu zmian wskazuje przed edycją każdy dotknięty plik. Zmiany trafiają potem małymi porcjami sprawdzanymi przez bramki typów, testów i pozostałości, bez czytania całego diffu przez człowieka.

Odziedziczyłeś monolit liczący 1,8 miliona linii, którego architekci odeszli dwa lata temu, a twój pierwszy ticket zmienia nazwę User.role. Agent edytuje trzy pliki w packages/web, melduje sukces, a dwie godziny po wdrożeniu usługa billing-worker rzuca wyjątkiem, bo czyta to samo pole ze współdzielonego schematu zdarzeń, którego agent nigdy nie otworzył. Model nie był niedbały; po prostu nie zobaczył pliku, który miał znaczenie.

Ta strona jest dla programistów, którzy wprowadzają zmiany w bardzo dużym repozytorium, oraz dla tech leadów, którzy konfigurują pliki instrukcji, serwery MCP i bramki, na których opiera się cały zespół.

  • Trójwarstwowy układ instrukcji (katalog główny, pakiet, na żądanie) dla Claude Code, Codeksa i Cursora, razem z regułami ładowania, od których zależy, czy agent w ogóle zobaczy instrukcje pakietu
  • Wybór serwera MCP do analizy kodu (Serena, codebase-memory-mcp albo Claude Context) ze sprawdzonymi poleceniami instalacji i bez sekretów w plikach konfiguracyjnych
  • Cztery prompty do skopiowania: mapa architektury, zasięg zmiany nazwy, graf zależności jednego modułu i wykonanie jednej porcji planu
  • Bramkę przed scaleniem, która dowodzi kompletności zmiany w 60 plikach, choć nikt nie czyta wszystkich 60
  • Kroki naprawcze na nieaktualne indeksy, zmyślone ścieżki i liczby, przepełnienie kontekstu oraz zmiany, które przechodzą osobno, ale psują integrację

Dlaczego większe okno kontekstu nie rozwiązuje problemu milionowego repozytorium?

Dział zatytułowany „Dlaczego większe okno kontekstu nie rozwiązuje problemu milionowego repozytorium?”

Repozytorium liczące miliony linii nie mieści się w żadnym obecnym oknie kontekstu (rozmiary znajdziesz w przeglądzie modeli), a zapchanie większości okna kodem obniża jakość odpowiedzi na długo przed przepełnieniem. W historii z początku zawiódł dobór: jedyny ważny plik nie został załadowany. Dlatego projektujesz to, co się ładuje, warstwami:

WarstwaZawieraGdzie się znajdujeKiedy się ładuje
ArchitekturaMapa modułów, kierunek zależności, reguły typu „zawsze sprawdź współdzielony schemat”Główny CLAUDE.md / AGENTS.md / zawsze aktywna reguła CursoraW każdej sesji
DomenaNiezmienniki i kontrakty jednego pakietuPlik instrukcji pakietu albo reguła ograniczona do ścieżekGdy agent pracuje w tym pakiecie
Implementacja i wzorzecZmieniane pliki i dobrze napisany przykład do naśladowaniaZnajdowane wyszukiwaniem, dociągane przez agentaNa żądanie, osobno dla każdego zadania

Warstwę architektury piszesz raz i przestajesz za nią płacić. Trzymaj ją krótko: każda linia ładuje się w każdej sesji. Przycinanie CLAUDE.md i AGENTS.md pokazuje, jak zmierzyć, które linie są warte swojego miejsca.

Każde z trzech narzędzi inaczej ładuje zagnieżdżone instrukcje, a ta różnica decyduje, czy reguły pakietu zostaną kiedykolwiek przeczytane.

Claude Code przy starcie ładuje każdy CLAUDE.md od katalogu roboczego w górę. CLAUDE.md w podkatalogu ładuje się na żądanie, gdy Claude czyta plik w tym podkatalogu. Dla reguł zależnych od pliku, a nie od folderu, użyj reguły ograniczonej do ścieżek w .claude/rules/:

---
paths:
- "services/payment/**"
---
# Payment invariants
- Amounts are integer cents; never floats.
- Every mutation takes an idempotency key.
- Never log a full card number.

Główny CLAUDE.md przechowuje warstwę architektury:

# Architecture (1.8M lines, event-driven)
- Services own their schemas; shared types live in packages/shared-types/.
- Inter-service traffic goes through packages/event-bus/. A field read by
another service is also read from event payloads: search events/ too.
- Before any cross-package change, produce a blast-radius report (see
docs/architecture/map.md) and wait for approval.

Claude Code (kanał latest, od v2.1.277) czyta AGENTS.md, gdy projekt nie ma CLAUDE.md, więc repozytorium współdzielone z użytkownikami Codeksa może mieć jeden plik.

Bez pomocy agent przegląda duże repozytorium przez wyszukiwanie i czytanie: dziesiątki wywołań, z których każde dokłada treść plików do okna. Serwer MCP do analizy kodu odpowiada na pytanie „kto to wywołuje?” jednym wywołaniem. Trzy utrzymywane opcje z różnymi kompromisami:

SerwerJak znajduje kodDokąd trafia twój kodWymagaPopularność (odczyt 2026-09-26)
Serena (Oraios)Serwery językowe: symbole, referencje, edycje na poziomie symboliZostaje lokalnieuv, serwer językowy dla każdego języka★29,8 tys.; PyPI serena-agent 1.7.0
codebase-memory-mcp (DeusData)Graf wiedzy z tree-sittera ze śledzeniem ścieżek wywołań (trace_path)Zostaje lokalnieNatywny plik wykonywalny★44,9 tys.; 0.11.0 na npm i PyPI
Claude Context (Zilliz)Hybrydowe wyszukiwanie BM25 i wektorowe po fragmentach koduEmbeddingi, a przy hostowanym dostawcy także fragmenty kodu, opuszczają maszynę, chyba że uruchomisz Milvus i Ollamę lokalnieWektorowa baza Milvus lub Zilliz i API embeddingów★12,6 tys.; npm @zilliz/claude-context-mcp 0.1.15, ostatnie wydanie 2026-06-22

Zacznij od Sereny, gdy twoje języki mają dobre serwery językowe, a kod musi zostać na twoich maszynach. Serena rozwiązuje zmianę nazwy przez serwer językowy, więc znajduje miejsca wywołań, które umykają wyszukiwaniu tekstowemu. Wybierz Claude Context, gdy pytanie jest pojęciowe („gdzie ponawiamy nieudane obciążenia?”), a nazewnictwo niespójne. Pełne porównanie znajdziesz na stronie serwery MCP, które rozumieją twój kod.

Okno terminala
# Terminal: instalacja Sereny i rejestracja dla wszystkich projektów (Claude Code 2.1.283, kanał `latest`)
uv tool install -p 3.13 serena-agent
serena init
claude mcp add --scope user serena -- serena start-mcp-server --context claude-code --project-from-cwd

Dla codebase-memory-mcp zainstaluj plik wykonywalny z npm i zarejestruj go:

Okno terminala
# Terminal: codebase-memory-mcp 0.11.0 (rejestracja wyprowadzona z konfiguracji JSON w README)
npm install -g codebase-memory-mcp
claude mcp add codebase-memory -- codebase-memory-mcp

Dla Claude Context zatwierdź w repozytorium (commit) projektowy .mcp.json, który czyta klucze ze zmiennych środowiskowych, dzięki czemu żaden klucz nie trafia do repozytorium. Przypnij wersję pakietu: nieprzypięte @latest w pliku zatwierdzonym w repozytorium uruchamia na maszynie każdego członka zespołu to, co zostanie opublikowane jako następne. Podbijaj wersję świadomie, po przeczytaniu informacji o wydaniu.

{
"mcpServers": {
"claude-context": {
"command": "npx",
"args": ["-y", "@zilliz/claude-context-mcp@0.1.15"],
"env": {
"OPENAI_API_KEY": "${OPENAI_API_KEY}",
"MILVUS_ADDRESS": "${MILVUS_ADDRESS}",
"MILVUS_TOKEN": "${MILVUS_TOKEN}"
}
}
}
}

Za rozpoznanie, które wyrzucisz, zapłacisz ponownie w przyszłym tygodniu. Zrób je raz, w trybie tylko do odczytu, i zapisz wynik w docs/architecture/map.md, na który wskazuje główny plik instrukcji.

Okno terminala
# Terminal, katalog główny repozytorium. dontAsk uruchamia odczyty, polecenia tylko
# do odczytu i narzędzia z twojej listy dozwolonych; wszystko, co wymagałoby pytania,
# odrzuca. Prompt mówi też „Do not modify any file”. Zapis do map.new.md chroni starą mapę.
mkdir -p docs/architecture
claude -p --permission-mode dontAsk "$(cat prompts/architecture-map.md)" > docs/architecture/map.new.md
git diff --no-index docs/architecture/map.md docs/architecture/map.new.md
mv docs/architecture/map.new.md docs/architecture/map.md # po przejrzeniu diffu

W sesji interaktywnej wklej prompt po /plan. Wbudowany subagent Explore czyta pliki we własnym kontekście i zwraca tylko podsumowanie, więc twoje główne okno zostaje małe.

Zapisz prompt jako prompts/architecture-map.md na potrzeby poleceń bez interfejsu. Przy pierwszym uruchomieniu starej mapy nie ma, więc diff pokaże cały plik. Generuj mapę ponownie po dużym scaleniu i przeglądaj jej diff, zanim zastąpisz starą wersję: zmiana kierunku zależności to decyzja architektoniczna, którą ktoś powinien był podjąć świadomie.

Przygotuj raport zasięgu zmian przed jakąkolwiek edycją

Dział zatytułowany „Przygotuj raport zasięgu zmian przed jakąkolwiek edycją”

Najbardziej opłacalny ruch w dużym repozytorium to kazać agentowi znaleźć i zaraportować dotknięte pliki, zanim cokolwiek zmieni. Przebieg tylko do odczytu jest tani w porównaniu z refaktoryzacją, która psuje usługę, której nikt nie wymienił. Raport jest też listą akceptacyjną dla bramki przed scaleniem opisanej niżej, więc poproś na końcu o listę plików czytelną dla maszyny.

Zmiana skupiona na jednej klasie wymaga grafu, a nie listy. Ta wersja wyłapuje słuchaczy zdarzeń i subskrybentów, którzy reagują na zdarzenia klasy, nie importując jej:

Jeśli raport pomija usługę, o której wiesz, że istnieje, zatrzymaj się. Albo indeks jest nieaktualny, albo reguły ignorowania ukrywają folder. Napraw to, zanim zaufasz kolejnemu raportowi.

Nigdy nie dawaj dużemu repozytorium otwartego zadania w rodzaju „zrefaktoryzuj system uwierzytelniania”. Agent rozchodzi się w wielu kierunkach, gubi wątek, a ty dostajesz diff na 40 plików, którego nikt nie przejrzy. Ułóż pracę tak, żeby kompilator znalazł to, co pominął raport:

  1. Zatwierdź raport zasięgu. Dopisz każdego konsumenta, którego pominął, a o którym wiesz, zapisz blok FILES jako blast-radius.txt i zatwierdź go (commit) na gałęzi, zanim uruchomisz porcje równolegle. Nowe worktree dostają tylko śledzone pliki, a worktree Claude Code startują z domyślnej gałęzi zdalnej, chyba że ustawisz worktree.baseRef na "head", jak pokazują zakładki poniżej.

  2. Najpierw zmień współdzielone kontrakty. Typy, interfejsy, schematy zdarzeń i migracje idą pierwsze. Błędy typów, które wywołają, to druga, niezależna lista dotkniętych plików.

  3. Zmieniaj jeden pakiet na turę. Każda tura kończy się przejściem testów tego pakietu i sprawdzenia typów całego repozytorium, a nie słowem „gotowe”.

  4. Uruchamiaj testy konsumentów, nie tylko swoje. Najszybciej znajdzie je polecenie systemu budowania do celów dotkniętych zmianą. Grafy projektów Nx i Turborepo opisuje strona praca z monorepo.

  5. Uruchom bramkę przed scaleniem opisaną niżej, zanim otworzysz pull request.

Gdy porcje są mechaniczne i niezależne, na przykład ta sama zmiana nazwy w 20 pakietach, uruchom je równolegle, zamiast jedną po drugiej:

Wbudowany skill /batch, który według dokumentacji dzieli pracę na 5–30 niezależnych jednostek i przedstawia plan, po twojej akceptacji uruchamia jednego subagenta w tle na każdą jednostkę, każdego we własnym worktree. Nazwij jednostki sam, żeby skill nie wymyślił własnego podziału.

Domyślnie worktree odgałęziają się od domyślnej gałęzi zdalnej. Najpierw ustaw "worktree": { "baseRef": "head" } w .claude/settings.json, żeby każda jednostka startowała z twojej gałęzi funkcjonalnej, z blast-radius.txt i nowymi kontraktami. blast-radius.txt musi być zatwierdzony w repozytorium (commit), bo nowe worktree dostają tylko śledzone pliki:

/batch rename User.role to User.accountType, one unit per package listed in blast-radius.txt. Each unit installs dependencies first, changes only files from blast-radius.txt inside its package, and is done when that package's tests and the repository type check pass.

Każdy subagent publikuje własną zmianę, więc dostajesz jedną zmianę na pakiet. Scal je na gałęzi funkcjonalnej i uruchom bramkę przed scaleniem na połączonej gałęzi, a nie na każdej jednostce osobno.

Skaluj równoległość według przepustowości przeglądu, a nie według liczby agentów, których możesz uruchomić. Migracja trwająca tygodnie, z testami charakteryzacyjnymi i dowodami przełączenia, to już program: zobacz modernizację legacy z agentami.

Jak zweryfikować zmianę w 60 plikach bez czytania każdej linii?

Dział zatytułowany „Jak zweryfikować zmianę w 60 plikach bez czytania każdej linii?”

Dużej zmiany nie zatwierdzasz, czytając ją. Zatwierdzasz ją, bo przeszedł zestaw sprawdzeń, z których każde mogło zawieść. Przy zmianie obejmującej wiele pakietów liczą się te:

BramkaCzego dowodziKiedy zawodzi
Sprawdzenie typów całego repozytoriumKażdy kompilowany konsument zgadza się z nowym kontraktemJakieś wywołanie wciąż przekazuje stary kształt
Testy wszystkich dotkniętych konsumentówZachowanie każdego zależnego pakietu się utrzymujeUsługa niżej w łańcuchu polegała na starym polu
Wyszukiwanie pozostałościNie przetrwało żadne odwołanie do starej nazwyPominięto klucz tekstowy, kolumnę SQL albo pole zdarzenia
Uzgodnienie raportu z diffemKażdy plik z raportu został zmieniony albo jawnie usprawiedliwionyAgent po cichu pominął konsumenta
Testy kontraktów lub schematów zdarzeń i APIKonsumenci spoza systemu typów wciąż parsują danebilling-worker czyta role z JSON-a
Funkcje dopasowaniaKierunek zależności i warstwy są nienaruszoneAgent zaimportował coś przez zakazaną granicę
Przegląd przez agentaDrugi model szukał błędów poprawności w diffieBłędy logiki, których powyższe sprawdzenia nie widzą

Sprawdzenie pozostałości i uzgodnienie to dwa polecenia, które możesz wstawić do CI:

Okno terminala
# Terminal lub CI, na gałęzi funkcjonalnej; ścieżki w blast-radius.txt są względem katalogu głównego
# 1. Zero pozostałości: zawęź wzorzec tak, by trafiał tylko w zmienione pole
rg -n '\.role\b|"role"' packages/ services/ --glob '!**/migrations/**' && exit 1
# 2. Każdy plik z raportu został zmieniony albo jest usprawiedliwiony w excused.txt
touch excused.txt
git diff --name-only origin/main...HEAD | sort > changed.txt
sort -u blast-radius.txt | comm -23 - changed.txt | grep -vxFf excused.txt && exit 1
echo "blast radius covered"

Do przeglądu przez agenta uruchom /code-review w Claude Code, codex review --base main w Codeksie albo Bugbota na pull requeście w Cursorze. Raport, wynik bramek i listę usprawiedliwień dołącz do pull requesta jako jego pakiet dowodów. Zatwierdzenie należy do właścicieli każdego dotkniętego pakietu, przez CODEOWNERS. Ich zadaniem jest ocenić, czy lista usprawiedliwień i raport są wiarygodne dla ich usługi, a nie czytać każdą linię.

W długiej sesji sama rozmowa staje się nieaktualnym kontekstem: agent wciąż „pamięta” układ plików sprzed ostatniego rebase’u. Resetuj kontekst, gdy zmieniasz zadanie.

/clear zaczyna nową rozmowę i zachowuje pamięć projektu. /compact Focus on the accountType rename; drop the CSS work zachowuje wątek, ale go streszcza. /context pokazuje, co wypełnia okno, zanim zaczniesz duże zadanie. Jeśli dwa razy poprawiałeś agenta w tej samej sprawie, zrób /clear i zacznij od ostrzejszego promptu.

Co się psuje, gdy agenci pracują w bazie kodu liczącej miliony linii?

Dział zatytułowany „Co się psuje, gdy agenci pracują w bazie kodu liczącej miliony linii?”

Indeks jest nieaktualny po dużym scaleniu. Agent cytuje pliki, które się przeniosły albo już nie istnieją. Indeksuj ponownie po dużych scaleniach, rebase’ach i generowaniu kodu; Claude Context ma narzędzie clear_index do pełnej przebudowy. W Claude Code i Codeksie, które czytają pliki na żywo, nieaktualnym artefaktem jest zwykle mapa architektury albo główny plik instrukcji: wygeneruj mapę ponownie i porównaj diff.

Agent wymyśla ścieżki i importy. Warstwa architektury jest zbyt uboga albo plik pakietu się nie załadował (w Codeksie sprawdź katalog, w którym startowałeś: pliki poniżej niego zostaną przeczytane tylko wtedy, gdy model sam ich poszuka). Każ agentowi najpierw znaleźć definicję: „Find where UserService is defined, then write the import.” Każdą podaną ścieżkę traktuj jak twierdzenie do sprawdzenia.

Agent wymyśla dokładne liczby. Zapytaj „ile jest callbacków?”, a możesz dostać pewną siebie, precyzyjnie wyglądającą liczbę, której nigdy nie policzył. Wymagaj polecenia: „Report the count with the rg command you ran.” Ufaj liczbie tylko wtedy, gdy możesz ją powtórzyć.

Okno kontekstu wypełnia jeden plik. Wygenerowany klient na 8000 linii potrafi wyprzeć wszystko inne. Wskaż agentowi symbol, a nie plik, albo każ mu przeczytać zakres linii. Trzymaj wygenerowany kod poza indeksem semantycznym, przez .cursorignore albo reguły ignorowania serwera.

Każda porcja przechodzi, integracja pada. Zepsuł się konsument spoza systemu typów, na przykład subskrybent zdarzeń albo widok SQL. Dodaj test kontraktu dla tej granicy, dopisz konsumenta do listy „czyta bez importu” w mapie architektury i uruchom ponownie bramkę uzgodnienia.

Agent edytuje reeksport zamiast źródła. Zgubił kierunek zależności. Uruchom ponownie prompt z grafem zależności i w prompcie porcji wprost wskaż plik będący źródłem prawdy.

Równoległe porcje się zderzają. Dwóch agentów edytowało współdzielone narzędzie, które podział przeoczył. Przydzielaj współdzielone pliki tylko jednej porcji i scalaj ją jako pierwszą.

Serwer MCP się nie łączy. Sprawdź claude mcp list lub codex mcp list, a w Claude Code /mcp. Brakujący ${VAR} w .mcp.json pojawia się jako ostrzeżenie z nazwą zmiennej. W przypadku Sereny uruchom serena start-mcp-server ręcznie, żeby zobaczyć błąd serwera językowego.