Czemu używam AI

Przez cały ten czas uważałem, że LLMy to zło, ale od kiedy wyszedł Fable 5 i przetestowałem go, mój pogląd się zmienił. Dostałem kod, który wreszcie wymagał tylko średnich poprawek. Nie mówię tu o błędach, a o jakości kodu. Moje standardy są wysokie, chcę dostać kod, który spełnia dobre praktyki programowania, jest czytelnyoptymalny. Im bardziej rozrasta się projekt, tym trudniej go „utrzymać”, dlatego wierzę w czysty kod. Łatwiej jest skalować coś, co jest napisane porządnie, bez obaw o błędy, które będą kosztować realne pieniądze w biznesie.

SeqPlanKit

Jak zwykle, gdy korzystam z nowego narzędzia/biblioteki — tak i tutaj — zrobiłem research, jak najlepiej korzystać z AI. Przeczytałem wręcz za dużo papierów na ten temat i poszukałem skillów/serwerów MCP, które pomogą mi w pracy. Niestety nic nie było w stanie zaspokoić moich oczekiwań względem jakości, dlatego stworzyłem własny toolkit dla Claude Code.

Założenie jest proste: tracisz tokeny i czekasz dłużej na generację kodu, który będzie mniejszym bólem głowy przy późniejszym przeglądaniu. To pozwala również na większą autonomię całego procesu, mniej ręcznego zarządzania projektem, żeby na pewno robił to, o co go prosimy.

Działa to tak:

  • Jeden krok naraz, każdy w nowym agencie. Każdy krok czyta kod stworzony przez poprzedni krok, więc żaden interfejs nie jest zgadywany, a kontekst nigdy nie halucynuje rozwiązań dookoła zamrożonych kontraktów (które jednak powinny wyglądać inaczej, co wyszło w trakcie wykonywania planu, ale LLM się do tego nie przyzna), stworzonych tylko po to, żeby praca mogła odbyć się równolegle.
  • Bramka po każdym kroku, commit na zielono i rejestr na dysku. Jeżeli testy będą robione tylko na końcu egzekucji planu, to LLM będzie zgadywać, gdzie jest błąd, i jest ryzyko, że zrobi regresję tylko po to, żeby test przeszedł.
  • Lepszy przegląd. Dwa równoległe tory tylko do odczytu, jeden zakotwiczony w planie, drugi nieznający planu. Zwykły przegląd pozwala zobaczyć, co poszło nie tak zgodnie z planem. Ślepy przegląd widzi, co poszło nie tak z jakością kodu.
  • Na równoległość trzeba zasłużyć, czasami rzeczywiście można przyśpieszyć pracę, zrównoleglając coś, co nie wpływa na inne kroki planu. Podczas wykonania /plan-work użytkownik może wybrać, czy planner ma szukać zrównolegleń, ale to, czy one wystąpią, i tak zależy od dość rygorystycznych kryteriów.

Plan nie powstaje w próżni. Najpierw skill /summary-codebase czyta kod i zapisuje mapę repozytorium do summary/, z odnośnikami do plików i linii kodu. To sprawia, że plan jest stworzony pod kod, który istnieje, a nie pod kod, który LLM sobie wyobraził. To nie jest to samo, co robi graphify, moje podsumowanie kodu jest zorientowane na funkcjonalność.

Przed planem stoi jeszcze backlog. /todo zapisuje pracę do NextThingsToDo.md jako numerowane bloki zadań i, gdy zadanie wymaga klaryfikacji lub ma braki albo konflikty z innymi, prowadzi dialog z użytkownikiem. Plan powstaje dopiero z takiego bloku, więc decyzja „co robimy” jest podjęta i zapisana, zanim ktokolwiek zacznie rozpisywać kroki. To chroni nas przed napisaniem planu z promptu, którego LLM nie zrozumiał, zrozumiał źle lub w którym po prostu zrobiliśmy błąd.

Backlog, który ma dużo zadań, może mieć je w złej kolejności albo w konflikcie ze sobą, a niektóre czasami da się połączyć w jedno. /todo-untangle przechodzi go względem prawdziwego drzewa: klasyfikuje wpisy, zakotwicza je z powrotem w istniejących plikach, układa kolejność i przenumerowuje. /brainstorm puszcza kilku agentów, którzy pozwalają znaleźć luki i rozszerzenia. Szuka dobrych pomysłów, które można dodać do przyszłego planu. Oczywiście wszystko jest konsultowane z użytkownikiem.

Przegląd i naprawa chodzą w cyklach. Oba tory zgłaszają uwagi, naprawiacz zamyka je w kodzie i testach — nigdy w planie, żeby nie dało się „naprawić” problemu przez przepisanie kryterium — po czym cała drabinka bramek leci od nowa i przegląd rusza jeszcze raz na świeżym diffie. Pętla kończy się, gdy nie zostaje nic powyżej ustalonego progu wagi błędu (blocker/major/minor), albo gdy wyczerpie się limit cykli (co nie powinno się nigdy zdarzyć, ale LLMy to czarna skrzynka); wtedy przebieg zatrzymuje się i mówi wprost, co zostało „nie tak”.

Zestaw korzysta z trzech serwerów MCP. Serena daje nawigację i edycję po symbolach przez LSP, więc agent czyta jedną funkcję zamiast całego pliku i podmienia jej ciało zamiast przepisywać plik. Graphify trzyma graf zależności i odpowiada na pytania o architekturę oraz o zasięg zmiany, zanim ktokolwiek ją wprowadzi. caveman pozwala zaoszczędzić tokeny poprzez pisanie w zwięzłym, ale dokładnym stylu, przy okazji zmniejszając context rot.

Nie każde zadanie potrzebuje całego łańcucha. /ship to jednorazowa pętla wokół jednego SPEC.md: najpierw przemiela pomysł pytaniami, potem pisze specyfikację (mini-plan) i dopiero wtedy buduje, zadanie po zadaniu. Reszta narzędzi działa pojedynczo i wszędzie: /audit — przegląd po budowie prowadzony przez agenta, który jej nie budował, /revise — wrzucenie ręcznej poprawki albo raportu świeżego buga do specyfikacji, razem z testem regresyjnym, który najpierw musi paść, /systematic-debugging — odtwórz, wyizoluj, udowodnij mechanizm, dopiero potem napraw — skill, który służy do naprawiania ręcznie znalezionych bugów.

Osobno stoi /test-hardening. Tutaj kod uznaje się za poprawny, a audytowane są testy: szukane są asercje, które przejdą na wszystkim, testy sprawdzające implementację zamiast zachowania i braki w przypadkach brzegowych. /test-hardening-execute wprowadza te poprawki po jednej, a każda musi się udowodnić — test ma paść na celowo zepsutym kodzie, zanim wejdzie do repozytorium. Zielony zestaw testów, który niczego nie łapie, jest gorszy niż jego brak, bo daje fałszywe poczucie bezpieczeństwa.

Cały łańcuch — od mapy repozytorium, przez plan i bramkowaną egzekucję, po przegląd i zapis przebiegu — odpala jeden skrypt seqkit-run.sh. Na końcu masz kod, który da się przeczytać, i log przebiegu, który da się zaudytować.