Spec-Driven Development w Claude Code, dlaczego nie piszę już promptów typu 'zrób mi X'
Pięcioetapowy proces planowania feature'a zanim padnie pierwsza linijka kodu. Mniej iteracji, mniej błędów, mniej refactoru. Konkretny przykład na blogu który właśnie czytasz.

Większość ludzi używa Claude Code jak chatbota. Wpisują "dodaj endpoint /api/users", patrzą co wyjdzie, poprawiają, wpisują dalej. To działa na małych zmianach. Na większych rzeczach kończy się refactorem co dwa godziny i ze stosem zatangrowanych plików.
Ostatnio pracuję inaczej, z SDD (Spec-Driven Development). Zamiast jednego prompta z opisem feature'a, prowadzę agenta przez pięć etapów. Każdy etap to plik w .kiro/specs/<feature-name>/, każdy wymaga aprobaty zanim agent ruszy dalej.
Brzmi jak overhead. W praktyce, oszczędza godziny.
Pięć etapów SDD
/kiro:spec-init <nazwa-feature> # wstępny szkic intencji
/kiro:spec-requirements <nazwa> # konkretne wymagania (EARS format)
/kiro:spec-design <nazwa> # architektura, interfejsy, schematy
/kiro:spec-tasks <nazwa> # rozbicie na wykonalne zadania
/kiro:spec-impl <nazwa> # właściwa implementacja TDDKażdy etap czyta poprzedni i odsyła swój output do approval. Bez ręcznego "lecisz dalej" agent nie ruszy.
Etap 1: spec-init, co właściwie chcemy zbudować
Wynik to plik spec.json plus krótki opis. Tu nie chodzi o szczegóły, tylko o intencję. Cel, użytkownik, sukces.
{
"feature": "portfolio-blog",
"phase": "initialized",
"approvals": {
"init": false,
"requirements": false,
"design": false,
"tasks": false
}
}Brak aprobaty → następny etap zwraca błąd. To jest celowy gate.
Etap 2: spec-requirements, EARS format
Tu zaczyna się robota. Agent generuje wymagania w formacie EARS (Easy Approach to Requirements Syntax), jeden z najprostszych formatów do precyzyjnego opisu zachowania:
Wymaganie 1: Strona listy artykułów
WHEN użytkownik wchodzi na /blog
THE SYSTEM SHALL wyświetlić listę opublikowanych artykułów
sortowanych malejąco po dacie publikacji.
WHEN lista zawiera więcej niż 10 artykułów
THE SYSTEM SHALL podzielić wyniki na strony po 10
i wyświetlić paginację.Każde wymaganie ma numer (1.1, 1.2, ...) i jest cytowane w późniejszych etapach. Gdy w designie pojawia się decyzja architektoniczna, ma referencję do konkretnego wymagania które ją uzasadnia.
To eliminuje "a może by jeszcze X?" w połowie implementacji. Jeśli X nie ma w wymaganiach, nie robimy.
Etap 3: spec-design, architektura zanim padnie kod
Output to design.md: schematy, type interfaces, lista komponentów, diagram Mermaid jeśli sensowny.
// Example interface from blog spec design
interface PostMeta {
title: string;
description: string;
slug: string;
date: string;
tags: string[];
readingTime: string;
draft: boolean;
}
interface BlogPost extends PostMeta {
rawContent: string;
}Agent na tym etapie podejmuje decyzje technologiczne: która biblioteka MDX, czy SSG czy ISR, jak parsujemy frontmatter. Każda decyzja ma uzasadnienie w research.md.
Przykład z bloga, wybór next-mdx-remote/rsc zamiast @next/mdx:
@next/mdx wymaga rejestracji wszystkich plików .mdx jako stron Next.js. Dla file-based blog z dynamicznymi slugami to nieelastyczne. next-mdx-remote v6 ma RSC-compatible export, możemy ładować plik MDX runtime z dowolnej lokalizacji.
To uzasadnienie zostaje w specu na zawsze. Za miesiąc nie pamiętam dlaczego wybrałem to a nie tamto, sprawdzam i wiem.
Etap 4: spec-tasks, atomowe zadania z markerami parallel
Tu robi się ciekawiej. Agent rozbija implementację na zadania, każde z numerem. Te które mogą być wykonywane równolegle dostają marker (P):
- [ ] 2.1 (P) Zdefiniować TypeScript types dla blogu
- [ ] 2.2 (P) Zaimplementować funkcje odczytu i parsowania artykułów
- [ ] 2.3 (P) Zdefiniować konfigurację MDX pluginsTrzy zadania, niezależne od siebie, można odpalić równolegle. Później:
- [ ] 4. Zaimplementować stronę listy artykułów /blog
- Wymaga gotowych Task 2.2 i Task 3 (PostCard, Pagination)Zadanie 4 wymaga 2.2 + 3.x, agent wie że nie ruszy zanim nie skończą poprzednie. To pozwala uruchomić agentów równolegle bez race conditions.
Etap 5: spec-impl, implementacja z TDD
Ostatni etap. Agent przechodzi przez listę tasków i implementuje. Dla każdego pisze kod, weryfikuje, oznacza [x]. Jeśli coś się sypie, wraca do designu, nie hackuje.
Tu pojawiają się błędy które na poprzednich etapach nie były widoczne. Przykład z bloga: TypeScript nie umiał wywnioskować typu [plugin, options] jako tuple dla rehype/remark plugins. Rozwiązanie, escape hatch przez Record<string, any>. To zostało udokumentowane w spec'u jako lesson learned.
Co zyskujesz, czego tracisz
Zyski:
- Mniej iteracji w implementacji. Wiesz co ma powstać zanim coś powstaje.
- Lepszy code review. Reviewer czyta spec + diff, nie tylko diff.
- Przyszły ja zna kontekst. Za pół roku otwierasz
.kiro/specs/feature/design.mdi widzisz dlaczego zrobiłeś to tak a nie inaczej. - Bezpieczniejsza paralelizacja. Markery (P) pozwalają odpalić wielu agentów równolegle.
Koszt:
- Wolniejszy start. Pierwszy commit pojawia się dopiero po requirements + design + tasks. To 30-60 min planowania.
- Overkill na małe rzeczy. Dla zmiany jednej linijki nie odpalasz spec-init.
Kiedy SDD ma sens
Moja reguła kciuka:
| Skala zmiany | Podejście |
|---|---|
| Bug fix, jedna funkcja | Bezpośredni prompt |
| Nowy komponent UI | Może spec-design sam |
| Cały feature (nowa strona, integracja, model danych) | Pełne SDD |
| Refactor większy niż jeden plik | Pełne SDD |
Generalna heurystyka: jeśli planowanie zajmuje ci więcej czasu niż 5 minut, użyj SDD. Kompletny spec wymusi ten plan na piśmie.
Gdzie to żyje
W projekcie tworzy się katalog .kiro/specs/<feature-name>/ z plikami:
.kiro/specs/portfolio-blog/
├── spec.json # status approvali
├── requirements.md # 10 wymagań w EARS
├── design.md # architektura + interfejsy
├── research.md # uzasadnienia wyborów
└── tasks.md # 8 tasków z markeramiWszystko commituję do gita. Spec jest częścią kodu, nie dokumentacją obok.
Ten artykuł powstał w ramach feature'a portfolio-blog zaplanowanego przez SDD. Pełny spec jest w repo, od inicjacji do tasków, ze wszystkimi decyzjami architektonicznymi.
Jeśli chcesz spróbować, Claude Code ma plugin kiro z gotowymi komendami /kiro:spec-*. Wystarczy zainstalować i odpalić /kiro:spec-init <twój-feature>.