Spec-driven development: jak psát zadání, které AI agent opravdu zrealizuje

Spec-driven development: jak psát zadání, které AI agent opravdu zrealizuje

Agent dodává mlhavý kód, protože dostává mlhavé zadání. Praktický recept, jak přetavit Jira ticket na binární akceptační kritéria, three-tier boundaries a self-verification.

Jakub Kontra
Jakub Kontra
Developer

Ten moment, kdy agent hlásí „done" a build padá

Scéna, kterou znáš. Dostal jsi jira ticket na backend věc – nic složitého, přidat do platebního flow retry logiku, když se webhook od PSP nedoručí. Hodíš to agentovi, necháš ho běžet, jdeš na kafe. Vrátíš se, diff vypadá rozumně, testy zelené, agent hrdě hlásí „implementation complete, all tests passing". Pushneš to, CI padá na integrační úrovni. Otevřeš kód a zjistíš, že si agent vymyslel endpoint /webhooks/retry, který v naší API vůbec neexistuje, přidal feature flag, který nikdo nechtěl, a dva testy, co mu dělaly problém, prostě smazal s komentářem „removed obsolete test".

A tohle není problém blbého modelu. Model není blbý. Blbé bylo zadání.

Failure mode není halucinace, ale mlhavost

Prompt engineering odpovídá na otázku jak to agentovi říct. Spec engineering stanoví, co má na konci být – a proti čemu se to měří.

Když ladíš prompt, pořád píšeš narativní instrukce pro stroj, který si zbytek domyslí. Spec je kontrakt, proti kterému se dá výsledek měřit binárně. Jira ticket ve stylu „přidat retry pro webhooky" je guesswork zabalený do věty. Agent udělal přesně to, co mu dovolila mlhavost ticketu: kde jsi neřekl, tam si domyslel; kde jsi napsal „retry logika", vybral si mezi třemi interpretacemi tu nejsnazší. Primární failure mode současných agentů – Augment Code o tom mluví v sérii spec-first postů z konce 2025 – není halucinace, ale úroveň volnosti, kterou jsi v zadání povolil.

Spec jako kontrakt, ne dokument

Sean Grove z OpenAI na AI Engineer World's Fair v červnu 2025 řekl jednu větu: kód je 10–20 % hodnoty, kterou programátor dodává. Zbytek, 80–90 %, je structured communication – schopnost napsat spec, který jednoznačně popisuje, co má vzniknout. Jeho rada zní stroze: „start with the specification." OpenAI Model Spec má klauzule s unikátními ID a příkladové prompty, které fungují jako unit testy pro samotný spec.

Kent Beck v Pragmatic Engineer podcastu 2025 k tomu přidává, že TDD je u AI agentů „superpower", ale zároveň varuje, že agenti testy mažou, aby je protlačili do zeleného. Spec opřený jen o testy nestačí. Potřebuješ kontrakt na více vrstvách – strojově ověřitelný, s binárními akceptačními kritérii a explicitními mantinely. Ne word dokument, který napíšeš na začátku a dva sprinty ho nikdo nečte.

Jak vypadá ticket, který agent nemůže pokazit

Vezmi si idempotentní POST endpoint pro retry platebního webhooku. V narativní podobě by ticket zněl: „Přidej endpoint, který přijme webhook event ID a spustí retry, ať to není duplicitní." Agent si z toho vybere, co chce.

Přetav to na binární kritéria. Místo „funguje správně" napíšeš: POST /webhooks/{event_id}/retry vrací 202, když event existuje a je ve stavu failed. Vrací 409, když je ve stavu succeeded nebo processing. Vrací 404, když event ID neexistuje. Vrací 429, když stejné event ID přijde víckrát než třikrát za 60 sekund. Idempotency key je event_id – druhé volání do 5 minut vrací cached response, ne nový retry. Každý z těch řádků je kontrola, kterou buď splníš, nebo ne. Addyho framework z „How to write a good spec for AI agents" to trefuje: Returns 401 when unauthenticated ano, Works correctly nikdy.

Pod akceptační kritéria připoj three-tier boundaries, jak je razí Addy Osmani. Rozdělení má tři vrstvy, protože agent potřebuje vědět tři věci: defaulty, kde eskalovat a kde je tvrdý zákaz. Bez té třetí vrstvy si totiž přidá, co uzná za vhodné.

Always do: používej existující WebhookEventRepository. Loguj přes structlog s event_id v kontextu. Integrační test patří do tests/integration/webhooks/. A idempotency klíč řeš přes redis-cache, který je už nakonfigurovaný.

Ask first: jakákoli změna v tabulce webhook_events, přidání nové dependence do pyproject.toml.

Never do: nemaž existující testy. Netvoř nové endpointy mimo /webhooks/*. Nepřidávej feature flagy. Nezaváděj nový retry mechanismus – tenacity je v projektu.

Nad tím ještě self-verification. Agent si po implementaci pustí ruff check, mypy, pytest tests/integration/webhooks/ -v a do zprávy o dokončení musí zkopírovat výstup z terminálu. Ne „all tests passing", ale zkopírovaný výstup z terminálu. Addy k tomu přidává LLM-as-a-Judge pro nečíselná kritéria typu čitelnost a konzistence se stylem kódu. Dává to smysl u věcí, kde nejde napsat assert.

Poslední vrstva, kterou Claude Code podporuje nativně: SPEC.md workflow. Claude Code se tě přes AskUserQuestion doptá, vygeneruje SPEC.md, a execution běží ve fresh sessioně, kde agent nevidí tvoje původní narativní brebentění – jen kontrakt. Autor specu a exekutor jsou oddělení.

Nástroje, které dnes fungují

Pokud si máš dnes vybrat jeden nástroj, vezmi GitHub Spec Kit. Vyšel v září 2025, má přes 40 000 stars, drží commandy /specify, /plan, /tasks a podporuje 30+ agentů včetně Claude Code, Copilotu a Cursoru. Je to nejblíž standardu, co teď máš, a nevynutí si platformu navíc.

AWS Kiro (preview v červenci 2025, GA v listopadu 2025) je agentic IDE postavené na SDD, kde je spec source of truth. Pokud žiješ v AWS, stojí za zkoušku. Pokud ne, přidáváš si platformu kvůli metodice, kterou v Claude Code zvládneš s SPEC.md taky. Cursor rules (always, agent-requested, manual) jsou lightweight verze three-tier boundaries – na menší projekt stačí, na větší chceš SPEC.md per-feature, ne jen globální .cursorrules.

Martin Fowler v „Exploring Gen AI: Spec-Driven Development" rozlišuje tři varianty: spec-first (spec vznikne první, kód z něj), spec-anchored (spec existuje paralelně, slouží jako kotva) a spec-as-source (spec je jediný autoritativní artefakt, kód se regeneruje). Většina týmů skončí u spec-anchored a tvaruje si to na sebe.

Fowlerovo varování, které ti nikdo neřekne

Fowlerův experiment ze srpna 2025 ukázal, že i s detailním specem agenti „přidali unrequested features, měnili assumptions mid-stream, hlásili success při failed buildu". Beck k tomu přidává, že agenti mažou testy, které failují.

Self-verification se zkopírovaným terminálovým výstupem tě chrání proti falešnému „all tests passing". LLM-as-a-Judge pokrývá to, co neověříš assertem. Simon Willison navrhuje YAML conformance suites jako strojově parsovatelný kontrakt mezi specem a agentem – validátor, ne důvěra. A Willisonovo pravidlo zní: nepushuj kód, který bys neuměl vysvětlit někomu jinému. Když agent dodá něco, čemu sám nerozumíš, spec byl volný.

Hybridní přístup pobije čistou ideologii vibe-codingu i spec-as-source puritánství. Znamená spec jako kontrakt, human judgment a pojistky.

V pondělí ráno udělej tohle

Agent není junior, kterému děláš code review po každém souboru. Je to dodavatel. Splní přesně to, co má v kontraktu, a ani čárku víc. Jestli tě štve, co ti vrací, přestaň psát lepší prompty a začni psát kontrakty, které nejdou splnit jinak než správně.

Jedna konkrétní změna na pondělí: vezmi nejbližší ticket, který plánuješ hodit agentovi, a než ho pošleš, přepiš akceptační kritéria na binární. Každé „funguje" nahraď konkrétním status kódem, error message nebo stavem v DB. Přidej tři řádky „Never do". Nech agenta v response zkopírovat výstup pytest. V prvním diffu to poznáš.

SDD je páka. Převrací důkazní břemeno: už nehlídáš ty, musí dodat agent. Fowler má pravdu v tom, že to není zadarmo – pojistky a revize tě něco stojí.

Pokud chceš tenhle workflow zavést v týmu od základu – CLAUDE.md, hooks, šablony specifikací a code review postupy – provozuju on-site školení přesně na tohle. me@jakubkontra.com