Graft: mapa bazy kodu dla agentów AI
Graft wykorzystuje tree-sitter do tworzenia trwałego indeksu repozytorium przez MCP. Pozwala to agentom programistycznym uniknąć wielokrotnego skanowania plików w każdej sesji.
Czym jest mapa bazy kodu dla agentów programistycznych
Mapa bazy kodu dla agentów programistycznych to trwały indeks repozytorium, w którym agent wyszukuje informacje, zamiast przeszukiwać pliki za pomocą grep od zera w każdej nowej sesji. Graft jest jedną z implementacji tej koncepcji. Narzędzie to analizuje kod przy użyciu tree-sitter, tworzy folder z powiązanymi węzłami w formacie Markdown oraz graf połączeń dla każdego symbolu, a następnie udostępnia narzędzia wyszukiwania przez MCP (model context protocol, standardowy interfejs używany przez agentów programistycznych do wywoływania zewnętrznych narzędzi).
Graft nie jest proxy ani bramą sieciową. Nic nie znajduje się pomiędzy agentem a API modelu. Mapa to folder na dysku, który odczytuje agent. To rozróżnienie determinuje rozwiązywany problem: samodzielnie hostowana brama tokenów mierzy i kieruje wysyłanymi już żądaniami, podczas gdy mapa zmienia liczbę żądań, które w ogóle trzeba wysłać.
Ta technika jest starsza niż samo narzędzie i przetrwa je. Najpierw należy poznać technikę, a dopiero potem mechanikę jej działania.
Dlaczego agenci programujący zużywają kontekst na ponowne odkrywanie struktury
Obserwacja agenta rozpoczynającego pracę nad repozytorium, które widział już pięćdziesiąt razy, ujawnia powtarzalny schemat. Agent listuje katalogi. Używa grep do wyszukania symbolu. Otwiera trzy pliki, aby ustalić, w którym zdefiniowano funkcję, a następnie czwarty, aby sprawdzić, kto ją wywołuje. Żadna z tych czynności nie jest właściwym zadaniem. To orientacja, za którą płaci się tokenami wejściowymi w każdej sesji.
Przyczyna jest prosta. Model nie posiada pamięci między sesjami. Wszystko, czego agent dowiedział się o strukturze projektu, znajdowało się w oknie kontekstowym, które zostało odrzucone po zakończeniu sesji. Dlatego to samo odkrywanie struktury uruchamia się ponownie od zera, po pełnej cenie. W dużym repozytorium faza orientacji kosztuje więcej niż sama edycja: dziesięć wywołań narzędzi, aby zlokalizować kod, i jedno, aby go zmienić. Orientacja stanowi połowę kosztów, a edycja drugą, dlatego umiejętność ograniczania działań agenta do najmniejszej skutecznej zmiany warto łączyć z mapą, zamiast wybierać między nimi.
Mapa przerywa tę pętlę, przenosząc proces odkrywania z modelu na dysk. Parser przeszukuje repozytorium raz, rejestruje definicje i wywołania symboli, a następnie aktualizuje ten zapis wraz ze zmianami w kodzie. Agent zadaje jedno pytanie i otrzymuje odpowiedź wraz z nazwą pliku i numerem linii. Powtarzalna eksploracja staje się tanim wyszukiwaniem.
Używasz już słabszej wersji tego rozwiązania. Plik AGENTS.md określający konwencje zapobiega ponownemu wyprowadzaniu konwencji przez agenta przy każdym uruchomieniu. Wygenerowana mapa zapobiega ponownemu wyprowadzaniu struktury. Różnica polega na tym, kto ją tworzy. Plik instrukcji piszesz ręcznie, więc pozostaje on niewielki. Mapę generuje parser, dzięki czemu może ona obejmować dziesięć tysięcy plików. Jeśli chodzi o to, na co faktycznie zużywany jest budżet wewnątrz sesji, sposób, w jaki Claude Code wykorzystuje okno kontekstowe wyjaśnia szczegóły rozliczeń.
Co faktycznie buduje Graft
Dwa artefakty, oba w folderze graft/ w katalogu głównym repozytorium.
Pierwszym jest graf węzłów zapisany w formie powiązanych plików markdown, jeden plik na węzeł. Każdy węzeł zawiera podsumowanie w języku naturalnym, „sedno” najważniejszych linii logiki wyodrębnionych z kodu źródłowego, dokładne pliki źródłowe wraz z sumą kontrolną zawartości, typowane linki typu wiki do innych węzłów (depends_on, part_of, uses, implements) oraz sekcję notatek, która przetrwa regenerację, co pozwala na zapisanie kontekstu, którego parser nie jest w stanie wywnioskować.
Drugim jest graft/.graph/wiring.json, czyli graf strukturalny dla każdego symbolu, wyodrębniany przez tree-sitter: definicje, referencje oraz krawędzie wywołań między nimi.
Ten podział jest istotny, ponieważ tylko jedna połowa wymaga modelu. graft build opiera się wyłącznie na tree-sitter i nigdy nie wywołuje LLM (large language model), dzięki czemu jest deterministyczny i nie generuje kosztów. graft build --deep dodaje pisemne podsumowania oraz sedno dla każdego symbolu; są to wywołania modelu, za które ponoszone są opłaty.
Wsparcie dla języków jest podzielone na poziomy, a poziom określa stopień zaufania do grafu wywołań. TypeScript, JavaScript, Python, Go oraz Java posiadają obsługę rozpoznawania międzyplikowego z uwzględnieniem zakresów (scope-aware). Rust, C, C++, C#, Ruby, PHP, Kotlin, Scala, Swift, Elixir, Solidity, OCaml, Zig oraz Dart otrzymują symbole wraz z ogólnymi krawędziami wywołań, co oznacza, że krawędź może wynikać z dopasowania nazw, a nie z rozwiązanej referencji. Krawędzie o jakości kompilatora można włączyć opcjonalnie za pomocą --lsp oraz serwera językowego, takiego jak rust-analyzer lub gopls.
Instalacja Graft i przypięcie wersji
Graft wymaga Node.js w wersji 20 lub nowszej i jest udostępniany na licencji MIT. Według stanu na sierpień 2026 r. aktualne wydanie to 0.10.1, a pierwsza opublikowana wersja, 0.1.0, pochodzi z lipca 2026 r. Należy traktować to oprogramowanie jako wczesne.
npm install -g @nanonets/graft@0.10.1
npm ls -g @nanonets/graftnpm ls -g powinno wyświetlić @nanonets/graft@0.10.1. Wersję tę należy przypiąć celowo. Polecenie npm install -g @nanonets/graft bez parametrów rozwiązuje tag latest w momencie uruchomienia, co w przypadku projektu publikującego kilka wydań minor w miesiącu powoduje, że we wtorek narzędzie może różnić się od tego, które współpracownik zainstalował w poniedziałek. Przypięta wersja zapewnia spójność flag CLI oraz formatu grafu dla wszystkich użytkowników, dzięki czemu aktualizacja następuje dopiero po podjęciu takiej decyzji.
Następnie należy podłączyć narzędzie do posiadanego repozytorium:
cd /path/to/your/repo
graft init --dry-run
graft initgraft init pyta, który z agentów programistycznych ma zostać podłączony, a następnie buduje graf. Należy najpierw uruchomić --dry-run i zapoznać się z listą plików, które zostaną zmodyfikowane, ponieważ niektóre z nich znajdują się poza repozytorium. graft init jest idempotentne i nie nadpisuje istniejących konfiguracji, więc ponowne uruchomienie jest bezpieczne.
Według stanu na sierpień 2026 r. integracja obejmuje Claude Code, Cursor, Codex, GitHub Copilot, Google Gemini, Kiro, Windsurf oraz AdaL. Claude Code otrzymuje najgłębszą integrację: wpis serwera MCP, pasek stanu pokazujący rozmiar i nieaktualność grafu, hooki post-edit przebudowujące graf oraz plik umiejętności w .claude/. Pozostałe agenty otrzymują instrukcję lub plik reguł informujący o dostępności narzędzi. „Wsparcie” oznacza zatem, że Graft tworzy konfigurację połączenia, więc agent ignorujący własny plik reguł zignoruje również mapę. Jest to typowa przyczyna, dla której agenty ignorują napisane dla nich instrukcje, co ma zastosowanie również w tym przypadku.
Co trafia do repozytorium, a co pozostaje poza git
Po graft init należy spodziewać się następujących elementów:
graft/: graf węzłów markdown orazgraft/.graph/wiring.json. Dodane automatycznie do.gitignore..mcp.json: rejestruje serwer MCP typu graft, aby Claude Code mógł go uruchomić..claude/settings.json: scalone w miejscu, dodające pasek stanu oraz hooki post-edit.AGENTS.md,GEMINI.md,.github/copilot-instructions.md,.cursor/rules/graft.mdc,.kiro/steering/graft.md,.windsurf/rules/graft.mdoraz.adal/skills/graft/SKILL.md: sekcje ograniczone znacznikami, dołączone do plików odpowiadających wybranym agentom.~/.codex/config.toml,~/.codex/hooks.jsonoraz~/.codex/hooks/graft/graft-hooks.cjs: pliki globalne dla całego systemu, zapisywane tylko w przypadku wyboru Codex.graft init --no-globalpomija je, agraft init --no-hookspomija samą warstwę pośredniczącą (shim) hooka.
Graf jest pamięcią podręczną, podobnie jak node_modules. Nie należy go commitować. Generuje się ponownie z kodu w kilka sekund, zmienia się przy niemal każdej edycji, a jego commitowanie zamienia poprawkę w jednej linii w diff obejmujący kilkaset plików, którego nikt nie będzie przeglądał. Zamiast tego należy commitować konfigurację połączeń, w tym AGENTS.md oraz .mcp.json. Członek zespołu klonuje repozytorium, uruchamia graft build i generuje własny lokalny graf.
Sprawdź, czy reguła ignorowania została dodana przed pierwszym commitem:
grep -n graft .gitignore
git status --shortgrep powinno wyświetlić linię zawierającą graft/, a git status --short nie powinno wyświetlić nic w sekcji graft/. Jeśli pliki z graft/ pojawiają się w tym wyniku, oznacza to, że wpis ignorowania jest nieobecny lub został nadpisany w innym miejscu. Napraw to przed wykonaniem commita, ponieważ git śledzi plik po jego dodaniu, a późniejsza edycja .gitignore nie spowoduje usunięcia go z indeksu.
Jeśli wolisz zarejestrować serwer MCP ręcznie lub przypiąć go do konkretnej wersji, która została zainstalowana, wpis jest krótki:
{
"mcpServers": {
"graft": {
"command": "npx",
"args": ["-y", "@nanonets/graft@0.10.1", "mcp"]
}
}
}Narzędzia wyszukiwania wywoływane przez agenta zamiast grep
Graft udostępnia sześć narzędzi za pośrednictwem MCP. graft_find_code zwraca ranking węzłów dla opisu zadania, wraz z plikiem i linią. graft_file_api zwraca wszystkie sygnatury w pliku bez treści funkcji. graft_trace_calls analizuje wywołujących lub wywoływanych na kilku poziomach głębokości. graft_find_all zwraca trafienia wyrażeń regularnych pogrupowane według symboli. graft_repo_map umożliwia wstępne zapoznanie się z nieznanym repozytorium. graft_check_freshness raportuje, czy graf jest nadal zgodny z kodem.
Każde z nich posiada odpowiednik CLI, co pozwala sprawdzić, co faktycznie otrzymuje agent:
graft map .
graft ask "where do we validate the refresh token"
graft skeleton src/auth/session.ts
graft callers validateRefreshToken
graft callers validateRefreshToken --direction out
graft grep "refresh_token" --jsongraft ask powinno wyświetlić ranking węzłów z odwołaniami file:line zamiast zawartości plików. Na tym polega cały mechanizm: agent otrzymuje wskaźnik i otwiera jeden plik, zamiast czytać dziesięć w celu znalezienia właściwego. graft viz otwiera interaktywną przeglądarkę na localhost, jeśli chcesz samodzielnie przejrzeć graf. Jeśli graft ask nie zwraca nic użytecznego dla pytania, na które potrafisz odpowiedzieć w trzydzieści sekund, graf jest nieaktualny lub używany język znajduje się w szerokim poziomie wsparcia, więc mapa nie pomoże również agentowi.
Jeden koszt jest łatwy do przeoczenia. Sześć definicji narzędzi jest wstrzykiwanych do system promptu każdego zapytania przez całą sesję. Płacisz za to niezależnie od tego, czy agent korzysta z mapy, czy nie. W przypadku repozytorium na tyle małego, by zmieściło się w kontekście, stała opłata może być wyższa niż oszczędność wynikająca z eksploracji.
Co dzieje się z grafem po zmianie kodu
Odświeżenie strukturalne jest tanie i automatyczne. Graft odczytuje drzewo robocze, a nie git, więc edycja, której nie zatwierdzono, oraz edycja dodana do przechowalni (staged) są dla niego równie widoczne. Zapytanie powoduje ponowne przetworzenie tylko tych plików, których statystyki uległy zmianie, co według dokumentacji projektu generuje około 3 ms narzutu, a przebudowa na koniec cyklu dotyczy tylko plików, w których przesunięto kod. Ustaw GRAFT_NO_REFRESH=1 lub przekaż --no-refresh, aby uzyskać odpowiedź z grafu na dysku bez ponownego parsowania. Przekaż --no-reuse, aby wymusić pełne, „zimne” parsowanie wszystkiego, co jest zalecane po aktualizacji samego Graft.
Część wygenerowana przez model zachowuje się inaczej i to ona może po cichu przestać działać poprawnie. Podsumowania i kluczowe punkty (cruxes) są buforowane. Każdy węzeł rejestruje skrót zawartości swoich źródeł, więc gdy plik źródłowy ulega zmianie, węzeł jest oznaczany jako nieaktualny, zamiast być prezentowanym jako bieżący. Ta flaga pomaga tylko wtedy, gdy coś na nią zareaguje. Odśwież za pomocą graft build --deep, co ponownie zużywa tokeny modelu.
Uczyń nieaktualność widoczną:
graft check .
echo $?Kod wyjścia 0 oznacza, że graf jest zgodny z kodem. Kod wyjścia 1 oznacza rozbieżność. Uruchamiaj to w hooku pre-push lub na gałęzi w CI, aby półroczna mapa nie udzielała pewnych odpowiedzi na temat kodu, który został przepisany w marcu.
Analiza opublikowanych wyników testów wydajnościowych
Główne założenie Graft to „do 4 razy taniej i 3 razy szybciej, przy zachowaniu lub poprawie poprawności działania”. Dane te pochodzą z własnych testów projektu, opublikowanych w pliku README. Poniżej przedstawiono dwa pełne raporty z tych testów.
The data behind this chart
[
{
"label": "Controlled sweep",
"run_count": 162,
"token_saving_pct": 42,
"tool_call_saving_pct": 46,
"correctness_pct": 93,
"baseline_correctness_pct": 93
},
{
"label": "SWE-bench Verified",
"run_count": 50,
"token_saving_pct": 23,
"tool_call_saving_pct": 25,
"correctness_pct": 66,
"baseline_correctness_pct": 54
}
]Kontrolowany test obejmuje 162 przebiegów dla dwóch repozytoriów, z których jednym jest sam Graft, przy trzech próbach na zadanie. Raport wskazuje na 42% mniejsze zużycie tokenów oraz o 46% mniej wywołań narzędzi. Test SWE-bench Verified obejmuje 50 instancji z użyciem tego samego modelu dla obu wariantów i wykazuje mniejsze oszczędności: 23% tokenów oraz 25% wywołań narzędzi. Trzeci test polegał na odtworzeniu pięciu scalonych pull requestów dla PocketBase przy koszcie 11.02 USD w porównaniu do 13.91 USD dla wersji bazowej.
Wszystkie te dane należy traktować jako testy dostawcy. Dwa czynniki ograniczają ich wartość informacyjną. Kontrolowany test obejmuje własne repozytorium Graft, pod które autorzy optymalizowali narzędzie. SWE-bench Verified to publiczny zbiór problemów z popularnych projektów open-source w języku Python, a publiczne zbiory danych są naturalnie celem optymalizacji narzędzi, niezależnie od intencji twórców. Żaden z tych testów nie odnosi się do prywatnego monorepo, które posiada własną specyfikę nazewnictwa i martwy kod.
Kwestia poprawności wymaga ponownej analizy. W kontrolowanym teście wynik nie uległ zmianie: 93% z użyciem mapy wobec 93% bez niej. Wzrost do 66% z 54% występuje wyłącznie w teście SWE-bench Verified. Narzędzie, które redukuje koszty tokenów przy zachowaniu jakości, jest korzystnym rozwiązaniem. Należy jednak unikać łączenia wyników poprawności z SWE-bench z wynikami oszczędności tokenów z kontrolowanego testu w jedno twierdzenie.
Zmierz własną deltę tokenów, zanim w nią uwierzysz
Jedyną istotną liczbą jest ta pochodząca z własnego repozytorium. Ta metoda zajmuje jedno popołudnie.
Wybierz zadanie, które można powtórzyć dokładnie w ten sam sposób. Pytanie jest lepsze niż edycja, ponieważ edycja zmienia repozytorium, a drugie uruchomienie nie jest już tym samym eksperymentem. „Który moduł wymusza limit szybkości (rate limit) na ścieżce logowania” to właściwy format.
Włącz telemetrię i skieruj ją na własny terminal:
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_METRICS_EXPORTER=console
claudeEksporter konsolowy drukuje rekordy metryk w momencie ich zbierania. Interesującym Cię rekordem jest claude_code.token.usage, który posiada atrybut type o wartości input, output, cacheRead lub cacheCreation. Orientacja pojawia się w input oraz cacheRead, ponieważ to tam trafia zawartość plików. Zsumuj te dwie wartości.
Uruchom zadanie trzy razy, za każdym razem w nowej sesji, z podłączoną mapą. Następnie usuń wpis graft z .mcp.json i uruchom zadanie kolejne trzy razy. Porównaj mediany zamiast pojedynczych uruchomień, ponieważ czas pracy agenta wykazuje duże wahania, a jedno niefortunne uruchomienie może wskazać wynik sprzeczny z prawdą. Zapisz również liczbę wywołań narzędzi (tool-call count): wywołania narzędzi są mechanizmem, a tokeny efektem, więc oszczędność tokenów przy braku spadku liczby wywołań narzędzi oznacza, że zmieniło się coś innego.
Następnie odejmij koszty, których benchmark nie wykazuje. graft build --deep zużywa tokeny modelu przy każdym pełnym odświeżeniu. Sześć schematów narzędzi jest przesyłanych w każdym żądaniu. Jeśli agenci działają na wynajmowanym serwerze, ustawienie twardego limitu wydatków agenta zmienia to z niespodzianki w budżet, a co faktycznie raportuje telemetria agenta kodującego opisuje, co opuszcza maszynę po włączeniu eksportera.
Kiedy mapa bazy kodu przestaje być pomocna?
- Repozytorium mieści się już w kontekście. Pojedyncza, niewielka usługa nie wymaga mapy, a za każdym razem płacisz za przetwarzanie sześciu schematów narzędzi. Jeśli agent znajduje dowolny plik w jednym lub dwóch wywołaniach narzędzi, zrezygnuj z niej.
- Język znajduje się w szerokiej kategorii wsparcia. Ogólne krawędzie wywołań oznaczają, że
graft callersmoże pominąć wywołującego lub wygenerować go na podstawie kolizji nazw. Potwierdź wynik za pomocągraft grep, zanim zaufasz zakresowi wpływu zmian. - Graf stał się nieaktualny i nikt tego nie zauważył.
graft checkkończy działanie z kodem wyjścia 1 w przypadku rozbieżności, co jest użyteczne tylko wtedy, gdy jest uruchamiane automatycznie. To zadanie dla hooka lub kroku CI, a nie nawyk użytkownika. - Monorepo wymaga ograniczenia zakresu. Monorepo oparte na jednym repozytorium git jest automatycznie dzielone przez pliki obszarów roboczych,
go.mod,pyproject.tomllubCargo.toml, agraft ask "..." --in services/billing/zawęża zapytanie do jednego podprojektu. Ta sama intuicja, która prowadzi do zagnieżdżonych plików AGENTS.md dla każdego pakietu, ma zastosowanie do mapy. - Agent ignoruje powiązania. Obserwuj wywołania narzędzi w rzeczywistej sesji, zanim stwierdzisz, że mapa jest używana. Agent wciąż uruchamiający
grepsygnalizuje, że nigdy nie odczytał pliku reguł.
FAQ
Should I commit the graft/ folder to git?
No. graft build adds graft/ to your .gitignore automatically, because the graph is a regenerable cache like node_modules. It changes on nearly every edit, so committing it buries real diffs under hundreds of generated files. Commit the wiring that tells agents the map exists, AGENTS.md and .mcp.json among them, and let each teammate run graft build locally. Verify with grep -n graft .gitignore and git status --short before your first commit, because git keeps tracking a file once it has been added, and editing .gitignore afterwards does not untrack it.
Does Graft cost money to run?
The structural half does not. graft build, graft ask, graft check and the six MCP retrieval tools are tree-sitter operations that never call a model. graft build --deep is the paid half: it writes the plain-English summaries and per-symbol cruxes through an LLM, configured with GRAFT_PROVIDER, GRAFT_API_KEY and GRAFT_MODEL, plus GRAFT_BASE_URL for any OpenAI-compatible endpoint. You can run Graft with structure only and never spend a token on the graph itself.
How much will a codebase map actually save on my repository?
Nobody can tell you without measuring. The project reports 42% fewer tokens on its own 162-run sweep and 23% on SWE-bench Verified, both against a baseline with no map. Both are vendor benchmarks, one of them run partly on Graft's own repository, and neither describes your private code. Run one repeatable question three times with the map and three times without, with CLAUDE_CODE_ENABLE_TELEMETRY=1 and OTEL_METRICS_EXPORTER=console set, then compare the median of claude_code.token.usage for the input and cacheRead types.
What happens to the graph when I refactor?
Structure re-parses itself. Graft stats the working tree and re-parses only the files that changed, so a rename is picked up on the next query at roughly 3 ms of overhead, and it sees uncommitted work because it reads files rather than git history. The model-written summaries are what goes stale: each node stores a content hash of its sources, and a changed source marks the node stale instead of rewriting it. Run graft check . to see the drift, then graft build --deep to refresh the written half.
Which coding agents can use Graft today?
As of August 2026 graft init wires Claude Code, Cursor, Codex, GitHub Copilot, Google Gemini, Kiro, Windsurf and AdaL. Claude Code gets the most: an MCP server entry in .mcp.json, a statusline, post-edit hooks and a skill file under .claude/. Codex gets an AGENTS.md section plus machine-wide entries under ~/.codex/, which graft init --no-global skips. The others receive a rules or steering file. Any other MCP client can use the server directly by registering the command npx -y @nanonets/graft@0.10.1 mcp.