Stary kod na nowym stosie. Z dowodem, że liczy tak samo.
code-modernization to oficjalny plugin Anthropic do Claude Code. Tu znajdziesz: kiedy go użyć, jak go zainstalować, które komendy uruchomić po kolei i co sprawdzić przy każdej decyzji. Na koniec dwa przykłady: Xbase++ i C++Builder.
Autor: Tomek Wojciechowski · Ostatnia aktualizacja:
Kiedy go użyć, a kiedy wystarczy zwykły prompt.
- Nikt nie wie, jak to działa Tryb „Understand it first”
- Brak dokumentacji, autor odszedł, każdy boi się zmian. Dostajesz ocenę, mapę, reguły biznesowe i plan, a kod zostaje nietknięty. Od tego warto zacząć, jeśli nie wiesz, co dalej: ocena sama poleci jedną z dróg poniżej.
- Stara wersja tego samego stosu uplift
- .NET Framework 4.8 na .NET 8, Java 8 na 17, Spring Boot 2 na 3, Python 2 na 3. Kod zostaje, poprawiasz tylko to, co psuje nowa wersja. Dowód: ten sam zestaw testów przechodzi na obu wersjach.
- Stary język transform
- Xbase++, C++Builder, Delphi, COBOL, PHP 5 na C#, Javę, Pythona albo Rust. Przepisujesz moduł po module, a stary system w tym czasie dalej pracuje.
- Stara architektura reimagine
- Monolit na REST API z osobnym frontem albo kilka usług. Najpierw specyfikacja wyciągnięta z kodu i zatwierdzona architektura, potem szkielety usług z testami akceptacyjnymi.
- Kiedy nie Zwykły Claude Code wystarczy
- Skrypt na kilkaset linii przepiszesz szybciej zwykłym promptem. Przeniesienie aplikacji bez zmian na nowy serwer albo zakup gotowego produktu nie zmieniają kodu, więc nie ma czego budować.
Dlaczego plugin, a nie „przepisz to na C#”
- Zwykły prompt nie ma kontroli. Model przepisuje to, co zrozumiał, a testy pisze ten sam model. Nikt nie sprawdza, czy nowy kod liczy jak stary.
- Plugin wyciąga reguły z dowodem. Każda reguła biznesowa ma cytat plik:linia, sprawdza ją drugi agent, a podejrzane zatwierdza człowiek.
- Nic nie powstaje bez zgody. Plan musi zostać podpisany, zanim cokolwiek zostanie zbudowane, a testy każdego modułu zatwierdzasz przed napisaniem kodu.
- Dowód liczy skrypt, nie model. Stary i nowy kod dostają te same dane, skrypt porównuje wynik bajt po bajcie. Do tego co najmniej 10 nowych wejść i celowa usterka, która musi zaczerwienić testy.
- Stan zostaje w plikach. Kolejne komendy czytają
analysis/, a nie rozmowę. Druga osoba albo nowa sesja ruszy dalej odmodernize-status.
Instalacja i pierwsze uruchomienie.
Potrzebujesz Claude Code i Pythona 3.8+ dostępnego jako python3. Opcjonalnie: scc albo cloc do metryk. Najmocniejszy dowód dostaniesz, gdy na tej samej maszynie da się zbudować i uruchomić stary program.
1. Osobny katalog roboczy
Nie pracuj w repozytorium starego kodu. Plugin podłączy je dowiązaniem.
mkdir ~/modernizacja && cd ~/modernizacja 2. Stary kod tylko do odczytu
W .claude/settings.json katalogu roboczego:
{
"permissions": {
"allow": ["Read(**)", "Edit(analysis/**)", "Edit(modernized/**)"],
"deny": ["Edit(/legacy/**)", "Edit(//Users/ja/legacy/faktury/**)"],
"additionalDirectories": ["/Users/ja/legacy/faktury"]
}
} Pierwszy deny blokuje dowiązanie legacy/, drugi prawdziwą ścieżkę kodu (reguła pasuje do ścieżki dowiązania, nie do celu). preflight sprawdzi, czy reguła jest.
3. Instalacja pluginu
claude
/plugin marketplace add anthropics/claude-plugins-official
/plugin install code-modernization@claude-plugins-official 4. Start
/code-modernization:modernize faktury --source /Users/ja/legacy/faktury Plugin policzy język i rozmiar kodu, a potem zada dwa pytania w okienkach:
- Co chcesz zrobić? Nowsza wersja tego samego stosu / inny język moduł po module / nowa architektura / najpierw zrozumieć.
- Co musi zostać prawdą? Stary system działa w trakcie / zachowanie 1:1 razem z dziwactwami / poprawiamy znane błędy / najpierw przegląd bezpieczeństwa.
Przy przebudowie dopyta jeszcze, w co system ma się zmienić. Odpowiedzi trafią do analysis/faktury/INTENT.md, a na ekranie zobaczysz dokładną komendę preflight z wypełnionymi argumentami i pytanie, czy ją uruchomić.
Ściąga: komenda, kiedy, co dostajesz.
Wszystkie komendy mają prefiks /code-modernization:. Każda kończy się linią z następnym krokiem i odświeża analysis/<nazwa>/REPORT.html (jedna strona ze stanem prac, działa offline). Czasy według README, dla systemów rzędu dziesiątek tysięcy linii.
| Komenda | Kiedy | Co dostajesz | Czas |
|---|---|---|---|
modernize <nazwa> --source <ścieżka> | Zawsze na start (argumenty opcjonalne) | INTENT.md, gotowa następna komenda | 1 min |
modernize-preflight <nazwa> [stos] [--source ścieżka] | Pierwszy krok | PREFLIGHT.md: 5 odpowiedzi, próbny build, brakujące źródła | 3–4 min |
modernize-assess <nazwa> | Co to za system | ASSESSMENT.md: rozmiar, złożoność, dług, bezpieczeństwo, rekomendowana droga | 5–8 min |
modernize-assess --portfolio <katalog> | Kilka systemów naraz | Ranking systemów na jednej stronie | — |
modernize-map <nazwa> | Jak to jest zbudowane | TOPOLOGY.html: zależności, przepływ danych, punkty wejścia | 5–15 min |
modernize-extract-rules <nazwa> [moduły] | Przed przepisaniem | BUSINESS_RULES.md: karty Given/When/Then z plik:linia | 5–15 min |
modernize-review <nazwa> [flagged|p0|all] | Gdy są oflagowane reguły | RULE_REVIEWS.json: Twoje werdykty | Twój czas |
modernize-brief <nazwa> [stos] | Przed budową | MODERNIZATION_BRIEF.md: fazy, architektura, blok zatwierdzenia | ok. 5 min |
modernize-uplift <nazwa> [z] [do] | Nowsza wersja tego samego stosu | Katalog zmian, pilot, playbook, reszta partiami | pilot ok. 15 min |
modernize-transform <nazwa> [moduł] [stos] | Inny język, moduł po module | modernized/<nazwa>/<moduł>/, testy, EQUIVALENCE.json | 15–30 min |
modernize-reimagine <nazwa> [wizja] | Nowa architektura | Specyfikacja, architektura, szkielety usług z testami | — |
modernize-verify <nazwa> [moduł] | Po każdej budowie | VERIFICATION.md: werdykt na moduł | — |
modernize-harden <nazwa> | Przegląd bezpieczeństwa | SECURITY_FINDINGS.md i łatka do przejrzenia | — |
modernize-status <nazwa> | Gdy nie wiesz, co dalej | Postęp, co jest nieaktualne, komenda do wklejenia | sekundy |
Typowa kolejność przy przepisaniu: modernize → preflight → assess → map → extract-rules → review → brief → transform → verify. Podbicie wersji może pominąć reguły: preflight → assess → uplift → verify. Przy „najpierw zrozumieć” kończysz na brief.
Co robisz Ty: sześć decyzji i co sprawdzić przy każdej.
Plugin nigdy nie decyduje w tych miejscach za Ciebie. Każda decyzja to konkretny plik do przeczytania albo okienko z pytaniem.
- 1 · preflight Okienka z 5 pytaniami → PREFLIGHT.md
- Czy to cały system, czy wycinek (i kto z zewnątrz z niego korzysta)? Czy da się tu zbudować i odpalić testy? Czy jest nietypowy build: wewnętrzne repozytorium paczek, generator kodu? Czy ktoś już próbował i co poszło źle? Czego nie wolno ruszać? Na każde pytanie można odpowiedzieć „nie wiem”.
- 2 · review BUSINESS_RULES.md → RULE_REVIEWS.json
- Dostajesz w okienkach reguły P0 z podejrzeniem błędu, pytaniem do eksperta albo niską pewnością, po cztery naraz, z cytatem kodu. Oceniasz, czy reguła jest poprawna. Regułę oznaczoną jako błędną plan pokaże jako otwarte pytanie, a testy nie przyjmą jej za wzorzec.
- 3 · brief MODERNIZATION_BRIEF.md, sekcja 8
- Czytasz cel, architekturę docelową (diagram C4), fazy i otwarte pytania z sekcji 7. Zatwierdzasz w bloku
Approved by / Date / Approval covers: Phase 1 only | Full plan. Brak sprzeciwu to nie zgoda. Zmieniając brief, sterujesz budową. - 4 · transform Plan modułu i plik testów
- Przed kodem dostajesz plan modułu, a potem plik testów charakteryzujących z numerami reguł w nazwach. Sprawdź, czy testy obejmują reguły P0 tego modułu. Dopiero po Twojej zgodzie powstaje kod.
- 5 · verify fresh-cases.json, BASELINE.md, VERIFICATION.md
- Każdą różnicę między starym a nowym kodem akceptujesz sam, z powodem:
approvedInputswfresh-cases.jsonalbo tabela „Approved differences” wBASELINE.md. Werdykt PROVEN to dowód, a nie zgoda:VERIFICATION.mdpodpisuje osoba z imienia i nazwiska. - 6 · harden SECURITY_FINDINGS.md i łatka
- Przegląd bezpieczeństwa starego systemu (OWASP, CWE, podatne zależności, sekrety). Łatkę wdraża inżynier bezpieczeństwa, nie plugin. Usunięcie danych logowania trafia do osobnej łatki poza gitem.
Prezentacja szkoleniowa.
21 slajdów, około 30 minut. Na slajdach kilka słów, pod podglądem fakty do opowiedzenia. Pełny ekran to widok na projektor. Widok prelegenta otwiera drugie okno z notatkami, następnym slajdem i zegarem. Oba okna przełączają się razem.
Do opowiedzenia
- Temat: plugin
code-modernizationdo Claude Code. Autor: Anthropic, oficjalny katalog wtyczek, wersja 1.0.0 z października 2026. - Plan: gdzie go użyć, dlaczego zamiast zwykłego promptu, instalacja, komendy po kolei, decyzje człowieka, dwa przykłady (Xbase++ i C++Builder).
Sterowanie: strzałki, spacja, Page Up/Down (pilot do prezentacji), Home/End. N pokazuje notatki na pełnym ekranie, gdy masz jeden monitor.
Przykład 1: faktury z Xbase++ na .NET 10.
Scenariusz szkoleniowy, nie wdrożenie u klienta. Program do faktur z końca lat 90.: Xbase++, pliki DBF z indeksami, ekrany @ SAY/GET, wydruki na drukarkę igłową.
- Co Stos docelowy
- ASP.NET Core na .NET 10, PostgreSQL, front w React z TypeScriptem.
- Dlaczego Ten stos, a nie inny
- Typ
decimalliczy pieniądze bez błędów binarnych, .NET 10 ma wsparcie LTS do listopada 2028, a programistów C# łatwo znaleźć. Przeglądarka zamiast terminala znosi instalację na każdym stanowisku. - Jak Droga i pierwszy moduł
- transform, czyli moduł po module, podczas gdy stary program dalej wystawia faktury. Pierwszy moduł: wyliczenie i wydruk faktury, bo ma jasne wejście (pozycje) i wyjście (kwoty, wydruk).
- Gdzie Stary program do porównań
- Xbase++ działa na Windows. Maszyna wirtualna z działającym programem pozwala porównywać na żywo i dojść do PROVEN. Bez niej zostają nagrane wydruki i najwyżej PARTLY PROVEN.
- Alternatywa Zostajemy na Xbase++
- Producent ma własną ścieżkę z DBF na SQL (dokumentacja Alaska Software). Wtedy wybierasz uplift.
Komendy
/code-modernization:modernize faktury --source /Users/ja/legacy/faktury
/code-modernization:modernize-preflight faktury "C# .NET 10" --source /Users/ja/legacy/faktury
/code-modernization:modernize-assess faktury
/code-modernization:modernize-map faktury
/code-modernization:modernize-extract-rules faktury
/code-modernization:modernize-review faktury
/code-modernization:modernize-brief faktury "C# .NET 10, ASP.NET Core, PostgreSQL, React"
/code-modernization:modernize-transform faktury wydruk-faktury "C# .NET 10"
/code-modernization:modernize-verify faktury wydruk-faktury PROCEDURE ZapiszFakture()
LOCAL nNetto := 0, nVat
SELECT POZYCJE
SET FILTER TO POZYCJE->ID_FAKT == FAKTURY->ID
GO TOP
DO WHILE ! EOF()
nNetto += ROUND( POZYCJE->ILOSC * POZYCJE->CENA, 2 )
SKIP
ENDDO
nVat := ROUND( nNetto * 0.23, 2 ) // stawka w kodzie
SELECT FAKTURY
REPLACE NETTO WITH nNetto, VAT WITH nVat
COMMIT
RETURN // RULE-007: VAT od sumy netto, nie od pozycji
public static Totals Compute(
IReadOnlyList<Line> lines, decimal vatRate)
{
var net = lines.Sum(l => Money(l.Qty * l.Price));
return new Totals(net, Money(net * vatRate));
}
// ROUND() w Xbase++ zaokrągla połówkę od zera,
// Math.Round w .NET domyślnie do parzystej
static decimal Money(decimal v) =>
Math.Round(v, 2, MidpointRounding.AwayFromZero); Karta reguły z BUSINESS_RULES.md
### RULE-007: VAT liczony od sumy netto faktury
Priorytet: P0 · Źródło: FAKTURY.PRG:41–52
Given faktura z pozycjami 3 × 33,33 zł netto, stawka 23%
When program zapisuje fakturę
Then netto = 99,99 zł, VAT = 23,00 zł
And VAT nie jest sumą VAT-ów pozycji (3 × 7,67 = 23,01 zł) Co wyłapie dowód
- Zaokrąglanie 0,125 → 0,13 albo 0,12
ROUND()w Xbase++ zaokrągla połówkę od zera,Math.Roundw .NET domyślnie do parzystej. Poprawka to jeden parametr:MidpointRounding.AwayFromZero.- Usunięte rekordy SET DELETED ON
DELETEw DBF tylko oznacza rekord, usuwa go dopieroPACK. Naiwny import do PostgreSQL wskrzesza anulowane faktury.- Daty SET EPOCH, puste daty
- Dwucyfrowe lata rozwijane według
SET EPOCH, puste pole daty zamiastNULL. - Polskie znaki CP852, sortowanie
- Dane w CP852 (albo Mazovii, jeśli pamiętają Clippera), indeksy sortujące po bajtach: „Ł” za „Z”. Utrzymanie albo zmianę tego zachowania zatwierdza się w
review.
Przykład 2: stanowisko ważenia z C++Buildera na Rust i Tauri.
Też scenariusz szkoleniowy. Aplikacja VCL na hali: timer co sekundę czyta wagę z portu RS-232, liczy wartość towaru, zapisuje ważenie do Firebirda i drukuje etykietę z QuickReport. Cała logika siedzi w obsłudze zdarzeń formularza.
- Co Stos docelowy
- Rdzeń w Rust (port szeregowy, logika, kwoty w
rust_decimal), okno w Tauri 2 z interfejsem w TypeScripcie, PostgreSQL w centrali. - Dlaczego Ten stos, a nie inny
- Logika ważenia staje się biblioteką, którą da się przetestować bez wagi i bez okna. Jeden mały instalator zamiast runtime'u VCL i sterowników bazy na każdym stanowisku.
- Jak Droga i pierwszy moduł
- transform. Pierwszy moduł: parsowanie ramki i wyliczenie wartości, bo da się je porównać na nagranych danych. Ekran i wydruk w kolejnych fazach.
- Gdzie Stary program do porównań
- Maszyna wirtualna z Windows, a zamiast wagi plik z ramkami nagranymi raz z prawdziwego urządzenia, łącznie z uszkodzonymi i niestabilnymi odczytami. Etykiety porównuje się jako dane przekazane do wydruku, nie jako piksele.
- Alternatywa Zostajemy na C++Builderze
- Uplift do aktualnego RAD Studio (BDE na FireDAC,
AnsiStringna Unicode) przezmodernize-uplift. Embarcadero ma do tego własne centrum migracji.
Komendy
/code-modernization:modernize waga --source /Users/ja/legacy/waga
/code-modernization:modernize-preflight waga "Rust, Tauri 2" --source /Users/ja/legacy/waga
/code-modernization:modernize-assess waga
/code-modernization:modernize-map waga
/code-modernization:modernize-extract-rules waga
/code-modernization:modernize-review waga
/code-modernization:modernize-brief waga "Rust, Tauri 2, PostgreSQL"
/code-modernization:modernize-transform waga wazenie "Rust"
/code-modernization:modernize-verify waga wazenie void __fastcall TWagaForm::Timer1Timer(TObject *Sender)
{
AnsiString r = ComPort1->ReadStr(); // "ST,GS,+0012.345kg"
if (r.Pos("ST") != 1) return; // tylko stabilny odczyt
// działa, bo FormCreate ustawia DecimalSeparator = '.'
double kg = StrToFloat(r.SubString(7, 9));
double cena = Query1->FieldByName("CENA_KG")->AsFloat;
double wartosc = RoundTo(kg * cena, -2);
ZapiszWazenie(kg, wartosc);
QuickRep1->Print();
} use rust_decimal::{Decimal, RoundingStrategy};
/// Tylko stabilny odczyt: "ST,GS,+0012.345kg"
pub fn kg_z_ramki(r: &str) -> Option<Decimal> {
let r = r.strip_prefix("ST,")?;
r.get(3..12)?.trim_start_matches('+').parse().ok()
}
/// RoundTo z RTL: połówka do parzystej
pub fn wartosc(kg: Decimal, cena: Decimal) -> Decimal {
(kg * cena).round_dp_with_strategy(
2, RoundingStrategy::MidpointNearestEven)
} - Zaokrąglanie bankierskie RoundTo(2.5, 0) = 2
RoundTozaokrągla połówki do parzystej, af64::roundw Rust od zera. Odwrotnie niż w przykładzie 1. Poprawka:MidpointNearestEvenwrust_decimal.- Ukryta globalna reguła DecimalSeparator
- Parsowanie ramki działa tylko dlatego, że
FormCreateustawia kropkę jako separator dziesiętny. Na polskich ustawieniach Windows bez tej linii każdy odczyt kończy się wyjątkiem. - Daty i teksty TDateTime, AnsiString
TDateTimeto liczba dni od 30.12.1899 zapisana jakodouble. TekstyAnsiStringsą w Windows-1250. Test na granicy: ważenie o północy.
Koszt i pułapki.
- Limit planu 50–200 agentów
- Tyle odpalał w testach najcięższy krok,
extract-rules. Każdy krok z wieloma agentami mówi przed startem, ilu uruchomi, a przy dużym przebiegu pyta o zgodę. Zaczynaj od jednego modułu. - Reguły nie są deterministyczne Wyciąga je model
- Dwa przebiegi mogą znaleźć inne reguły.
BUSINESS_RULES.mdprzeglądasz jak każdy inny tekst, nie traktujesz go jak wyniku kompilacji. - Git Plugin niczego nie commituje
analysis/imodernized/commitujesz sam. Kopia robocza przy uplift ma własną lokalną historię, żeby różnica była czytelna.- Skrypty i CI claude -p
- Sesja bez okna przestaje czekać na pracę w tle po 10 minutach. Ustaw
CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS=0, żeby długie kroki zdążyły się skończyć. - Sekrety Maskowane w raportach
- Znalezione klucze trafiają do raportów jako
AKIA****, pełne wartości tylko doSECRETS.local.mdpoza gitem. - Telemetria Same liczby
- Plugin wysyła tylko liczby (bez kodu, nazw i ścieżek). Wyłączysz ją przez
CODE_MODERNIZATION_TELEMETRY=0.
Macie program, którego nikt nie chce ruszać?
Zaczynamy od jednego modułu: ocena, reguły, plan i pilot z dowodem równoważności na Waszym kodzie. Krótka rozmowa wystarczy, żeby sprawdzić, czy ma to u Was sens. Odpowiadamy w 24 h.