POWRÓT DO BLOGA
AI Implementation 7 lipca 2026

Vibe coding z Claude Code: fabryka aplikacji zamiast kolejnego demo (skill do skopiowania)

16 min Czechu

Każdy blog o vibe codingu pokaże ci demo, w którym wszystko działa. Żaden nie pokaże momentu, w którym AI melduje „gotowe”, kontener nie wstaje, a połowa endpointów zwraca puste odpowiedzi.

Ten tekst jest o tej drugiej połowie. O systemie, który ją zamyka.

Andrej Karpathy rzucił „vibe coding” w tweecie z 2 lutego 2025 - rok później sam nazwał go „przemyśleniem spod prysznica”. W międzyczasie słownik Collinsa zdążył ogłosić to przemyślenie Słowem Roku 2025. Między memem a słownikiem urosła jednak realna praktyka - u mnie w postaci 250-liniowego skilla, który buduje aplikacje od pomysłu do działającego kontenera w jedną sesję. Ten skill dostaniesz niżej w całości, do skopiowania.

W SKRÓCIE
  • Adopcja przestała być tematem: 84% deweloperów używa AI lub to planuje, a AI generuje już 75% nowego kodu w Google. Tematem jest zaufanie: 66% programistów frustruje kod „prawie dobry”.
  • Najdroższy moment vibe codingu to fałszywe „gotowe”. Agent Replita skasował produkcyjną bazę i twierdził, że nie da się jej przywrócić. Dało się.
  • Rozwiązaniem nie jest lepszy prompt, tylko twarda definicja ukończenia: kontenery healthy, test E2E przeszedł, screenshot obejrzany. Bez tego sesja się nie kończy.
  • Oddaję swój produkcyjny skill /nowa-apka: wywiad, sprawdzone klocki (React+nginx+Fastify+Docker), playbook 17 pułapek i wymuszony dowód działania - plik do wklejenia 1:1.
  • Dowód zamiast obietnic: pilotem skilla powstał gantt-studio - aplikacja z wykresem Gantta i drag&drop, smoke test 6/6, w jedną sesję.

Co o vibe codingu mówi każdy blog (i czego nie dopowiada)

Liczby adopcji są znane i robią wrażenie. Stack Overflow przepytał w 2025 ponad 49 tysięcy deweloperów: 84% używa narzędzi AI albo planuje ich użycie. Raport DORA od Google Cloud mówi o 90% profesjonalistów i medianie dwóch godzin pracy z AI dziennie. Sundar Pichai jesienią 2024 raportował, że AI generuje ponad 25% nowego kodu Google - pod koniec kwietnia 2026 mówił już o 75%. W zimowym naborze Y Combinatora co czwarty startup miał ponad 95% kodu napisanego przez modele, a szef YC Garry Tan ogłosił, że kto tak nie pracuje, „może po prostu zostać z tyłu”.

Blogi kończą cytat w tym miejscu. Te same raporty mają jednak drugą połowę: 46% deweloperów nie ufa dokładności tego, co AI wypluwa, a 66% jako główną frustrację wskazuje kod „prawie dobry”. W badaniu DORA 30% przyznaje, że ufa kodowi z AI mało albo wcale - choć używa go codziennie.

Cała branża używa narzędzia, któremu nie dowierza. To nie jest paradoks. To jest brak procesu.

Brudny sekret: AI świetnie udaje, że skończyło

Pisałem niedawno o tym, że detektor nie mierzy prawdy, tylko styl. W kodowaniu z AI obowiązuje bliźniacza zasada: model nie raportuje stanu projektu. Raportuje tekst, który brzmi jak raport o stanie projektu.

Mój ulubiony przykład kosztował kogoś bazę danych. W lipcu 2025 agent AI Replita, podczas ogłoszonej blokady zmian, skasował produkcyjną bazę firmy SaaStr z danymi około 1200 menedżerów. Po fakcie poinformował, że przywrócenie danych jest niemożliwe. Rollback okazał się jak najbardziej możliwy - agent po prostu stwierdził coś, czego nie sprawdził. Replit po incydencie wdrożył twardą separację środowisk dev i prod.

Skala mniejsza, mechanizm ten sam, znam z własnych sesji: „Wszystko działa, aplikacja gotowa do użycia” - a kontener nie przechodzi healthchecka, bo skrypt startowy ma windowsowe końce linii. Model nie kłamał złośliwie. Wygenerował najbardziej prawdopodobne zakończenie sesji, w której dużo się udało.

Do tego dochodzi jakość samego kodu. Veracode sprawdził w 2025 ponad sto modeli na 80 zadaniach: 45% rozwiązań wprowadzało znane podatności, a nowsze modele wcale nie były bezpieczniejsze od starszych. Osobne badanie z USENIX Security policzyło, że 19,7% paczek, które modele każą instalować, nie istnieje - i że 43% tych halucynacji powtarza się na tyle regularnie, że ktoś może je złośliwie zarejestrować.

Wniosek z tych liczb nie brzmi „porzuć vibe coding”. Brzmi: przestań wierzyć deklaracjom i zacznij wymagać dowodów. Dokładnie do tego służy reszta tego tekstu.

Fabryka zamiast rękodzieła: czym jest skill

Na blogu masz już pojęciowy przewodnik po vibe codingu i proces budowy aplikacji zespołem agentów w frameworku S.H.I.P.. Ten tekst rozwiązuje inny problem: powtarzalność. Tamte podejścia uczą budować aplikacje. Tu dostajesz fabrykę, która robi je seryjnie - i nie melduje „gotowe” bez dowodu.

Nośnikiem fabryki jest mechanizm skills w Claude Code. Skill to plik SKILL.md w katalogu .claude/skills/ - instrukcja wielokrotnego użytku, którą narzędzie wykonuje po wpisaniu /nazwa-skilla. Obok skills Claude Code ma jeszcze subagentów (osobne konteksty do zadań), hooki (automatyczne reakcje na zdarzenia) i MCP (podłączanie zewnętrznych narzędzi) - wszystko opisane w oficjalnej dokumentacji. Zaplecze dojrzało do poważnej pracy razem z rynkiem: Anthropic podał w lutym 2026, że sam Claude Code przekroczył 2,5 mld USD rocznego tempa przychodów.

Różnica między promptem a skillem jest prosta: prompt mówi modelowi, co zbudować. Skill mówi, kiedy wolno mu skończyć. Prompt piszesz za każdym razem trochę inaczej i za każdym razem od nowa płacisz za te same błędy. Skill wchłania każdą opłaconą lekcję na stałe - kolejne aplikacje dziedziczą wszystkie poprzednie blizny.

Definicja ukończenia, której nie da się obejść

Serce mojego skilla to trzy warunki zapisane w manifeście. Sesja nie ma prawa się skończyć, zanim nie spełni wszystkich trzech:

  1. docker compose ps pokazuje wszystkie serwisy healthy - nie „powinno działać”, tylko działa według maszyny;
  2. smoke test E2E przeszedł - skrypt w kontenerze otwiera aplikację jak użytkownik, klika główną ścieżkę i robi screenshoty;
  3. screenshoty zostały obejrzane - model ma otworzyć każdy plik i potwierdzić własnymi „oczami”, że na ekranie jest to, co miało być.

Do tego bezpiecznik na zapętlenie: trzy nieudane podejścia do tego samego błędu oznaczają twardy stop i przejście na systematyczną diagnostykę - dowody przed hipotezami, zamiast zgadywania czwarty raz z rzędu.

Ten zestaw brzmi banalnie, dopóki nie policzysz, ile razy przyjąłeś od AI „gotowe” bez żadnego z tych trzech dowodów. Definicja ukończenia to najtańszy element całego systemu - a znaczy więcej niż wybór modelu.

Klocki, które się nie sypią

Drugi filar skilla to architektura z klocków, które przeżyły wiele projektów. Nie dlatego, że są modne - dlatego, że są przewidywalne:

  • React + Vite + Tailwind budowane do statycznych plików, serwowane przez nginx - dev-server w kontenerze na Windows potrafi zjeść godziny na problemach z odświeżaniem; statyczny build jest nudny i właśnie dlatego dobry;
  • nginx proxy'uje /api do backendu - jeden origin, więc cała klasa problemów CORS znika zanim powstanie;
  • Fastify na node:22-slim - lekki start i wbudowana walidacja schematów;
  • dane w named volumes Dockera, nigdy w folderach montowanych z dysku Windows - prawa dostępu i wydajność NTFS to pułapki, które wychodzą dopiero pod obciążeniem;
  • healthchecki i limity pamięci w compose od pierwszego dnia - kontener bez healthchecka to kontener, o którym nic nie wiesz;
  • odpowiedzi AI w aplikacji zawsze przez walidację schematu, z retry i deterministycznym fallbackiem - plan JSON od modelu bez walidacji to losowe wysypki w losowych miejscach.

Każdy z tych wyborów ma w skillu jednozdaniowe uzasadnienie. Świadomie nie ma tam niczego, co wymaga dłuższej obrony.

Pułapki, za które zapłaciłem sesjami

Najcenniejsza część skilla to playbook 17 pułapek środowiska Windows + Docker + Git Bash, wklejany automatycznie do CLAUDE.md każdego nowego projektu. Kilka blizn z tej listy:

  • Git Bash przepisuje ścieżki. /data/raport.json cicho zamienia się w C:/Program Files/Git/data/raport.json - i debugujesz ducha. Jedna zmienna środowiskowa (MSYS_NO_PATHCONV=1) kończy temat na zawsze.
  • Windowsowe końce linii zabijają kontener. Skrypt .sh zapisany z CRLF wywala się komunikatem „no such file or directory”, który nic nie mówi. Plik .gitattributes z jedną linią zamyka sprawę.
  • curl -d z polskimi znakami psuje żądanie. Dane z diakrytykami idą zawsze przez --data-binary @plik.json, inaczej długość treści się nie zgadza.
  • Weryfikacja UI musi mieszkać w kontenerze. Rozszerzenie przeglądarkowe agenta nie widzi localhosta - smoke test odpala się Puppeteerem wewnątrz sieci Dockera i zostawia screenshoty jako dowód.
  • Świeży obraz bazowy to ruletka. Na obrazie node pobranym w dniu pilota Chromium padał na starcie protokołu debugowania. Buduje się na obrazach sprawdzonych albo przypiętych do konkretnej wersji, nie na „latest z dziś”.
  • crypto.randomUUID() działa tylko w bezpiecznym kontekście. Przez http:// po sieci lokalnej pada, a operacje „cicho nie działają” - w kodzie frontendu zawsze jest fallback.
  • Zapis stanu tylko atomowo (plik tymczasowy + podmiana) i rekoncyliacja niedokończonych zadań po restarcie - inaczej frontend czeka w nieskończoność na joby, które nigdy się nie skończą.

Kopiując skill, nie kopiujesz tekstu. Dziedziczysz moje porażki, żeby nie płacić za nie własnymi sesjami.

Skill /nowa-apka - skopiuj i używaj

Poniżej pełny, produkcyjny plik - ten sam, którym buduję aplikacje u siebie, nie wersja spreparowana pod artykuł.

Instalacja (2 minuty):

  1. Utwórz katalog .claude/skills/nowa-apka/ - w katalogu domowym (skill globalny) albo w konkretnym projekcie.
  2. Zapisz poniższą treść jako SKILL.md w tym katalogu.
  3. W nowej sesji Claude Code wpisz /nowa-apka z opisem pomysłu, np. /nowa-apka prosty tracker nawyków z wykresami - albo --szybki, gdy chcesz zero pytań i domyślne klocki.

Wymagania: Claude Code, Docker Desktop, na Windows dodatkowo Git Bash. Klucz OpenRouter tylko wtedy, gdy budowana aplikacja ma używać AI w środku.

---
name: nowa-apka
description: Scaffolder nowej aplikacji - od pomysłu do DZIAŁAJĄCEGO PoC w kontenerach Docker w jednej sesji. Krótki wywiad (typ, AI, dane, render), potem szkielet ze sprawdzonych klocków (React+Vite+Tailwind za nginx, Fastify na node:22-slim, opcjonalny Chromium+puppeteer-core, compose z healthcheckami, named volumes), CLAUDE.md projektu z wgranym playbookiem pułapek Windows+Docker, git init, uruchomienie i smoke test E2E w kontenerze ze screenshotem jako dowodem. Argumenty - opis pomysłu (start bez pytań wstępnych), `--szybki` (zero pytań, domyślne klocki), bez argumentu (pełny wywiad).
argument-hint: [opis pomysłu] [--szybki] [--bez-ai]
---

# /nowa-apka - od pomysłu do działającego PoC

## Manifest

Jedna sesja = działający kontener z dowodem, nie szkielet z TODO. Skill kończy się dopiero wtedy, gdy:
1. `docker compose ps` pokazuje wszystkie serwisy **healthy**,
2. smoke test E2E przeszedł, a screenshot z wnętrza kontenera został obejrzany (Read),
3. w projekcie leży CLAUDE.md z playbookiem pułapek i komendami dev-loop.

Deklaracja „powinno działać" = skill NIE jest skończony.

**Czego NIE robi:** auth, backupy, limity produkcyjne, CI - to bramka `/mvp`. Publikacja - to `/wdroz`.

## Krok 0 - parsowanie argumentów

- `<opis pomysłu>` - pomiń pytania, na które opis odpowiada; dopytaj tylko o luki (max 1 runda AskUserQuestion).
- `--szybki` - zero pytań: webapp UI+API, bez AI, dane w SQLite, bez renderu.
- `--bez-ai` - wymusza brak integracji AI niezależnie od opisu.
- bez argumentu - pełny wywiad (Krok 1).

## Krok 1 - wywiad (AskUserQuestion, max 2 rundy)

Pytaj TYLKO o decyzje zmieniające architekturę:

1. **Typ**: webapp UI+API / czyste API / narzędzie wewnętrzne z prostym UI / strona statyczna.
2. **AI w środku**: OpenRouter (`anthropic/claude-sonnet-5` + fallback deterministyczny) / brak.
3. **Dane**: SQLite w named volume (domyślne) / Postgres / pliki JSON w named volume (wzorzec jobów).
4. **Render/media**: worker Chromium+puppeteer-core (HTML→PNG/PDF/scrape) / brak.

Resztę decyzji (porty, struktura katalogów, nazwy) podejmij sam i wypisz w podsumowaniu architektury. Nie pytaj o rzeczy z sensownym domyślnym.

## Krok 2 - architektura ze sprawdzonych klocków

| Klocek | Wybór | Dlaczego (opłacone doświadczeniem) |
|---|---|---|
| Frontend | React 19 + Vite + Tailwind v4 + Zustand, build statyczny | dev-server w Dockerze na Windows = problemy z HMR/polling; build jest przewidywalny |
| Serwowanie | nginx:alpine z proxy `/api` → `backend:3000` | jeden origin = zero CORS |
| Backend | node:22-bookworm-slim + Fastify | lekki, szybki start, schematy walidacji wbudowane |
| Render | apt `chromium` + `puppeteer-core` w obrazie backendu | NIE obraz ghcr/puppeteer - pułapki pptruser-vs-volume i podwójny Chrome |
| Dane | named volume (np. `app_data:/data`) | NIGDY bind-mount NTFS dla danych - prawa, wydajność, fsync |
| Compose | `init: true`, `shm_size: 1gb` (gdy Chromium), `mem_limit: 3g`, healthchecki | zombie-procesy, crash Chromium bez shm, ochrona RAM hosta |
| Porty | `127.0.0.1:81XX:80` | Chrome łączy się z 127.0.0.1; 8080 bywa zajęty - sprawdź zajętość |
| Joby/stan | katalogi z JSON, zapis atomowy tmp+rename, polling co 1 s | proste, odporne; SSE/WebSocket dopiero gdy potrzebne |
| AI | OpenRouter, klucz w `backend/.env`, walidacja odpowiedzi AJV + retry + fallback deterministyczny | plan JSON od AI bez walidacji = losowe wysypki |

**Wybór portu:** `docker ps --format '{{.Ports}}'` + `netstat -ano | findstr :81` - pierwszy wolny z zakresu 8181-8199. Windows ma też wykluczone zakresy portów: `netsh int ipv4 show excludedportrange protocol=tcp` (port „zajęty" bez procesu).

Przedstaw architekturę w 5-8 liniach (serwisy, port, wolumeny, przepływ) ZANIM zaczniesz pisać pliki.

## Krok 3 - scaffold

Struktura (dostosuj do wywiadu):

```
<projekt>/
  docker-compose.yml
  CLAUDE.md                  # instrukcje projektu + playbook pułapek (sekcja niżej)
  .gitignore                 # node_modules, .env, dist, out
  .gitattributes             # *.sh text eol=lf  (CRLF w skryptach = kontener pada)
  frontend/
    Dockerfile               # multi-stage: node:22 build -> nginx:alpine
    nginx.conf               # proxy /api -> backend:3000
    src/...                  # React+Vite+Tailwind
  backend/
    Dockerfile
    .env.example             # OPENROUTER_API_KEY=..., nigdy realny klucz w repo
    src/server.js            # Fastify + /health + logger
    e2e-smoke.cjs            # smoke E2E (uruchamiany w kontenerze)
```

Kanoniczne szablony (dostosuj nazwy/porty):

**docker-compose.yml**
```yaml
services:
  frontend:
    build: ./frontend
    ports:
      - "127.0.0.1:8181:80"
    depends_on:
      backend:
        condition: service_healthy
    restart: unless-stopped
  backend:
    build: ./backend
    init: true
    env_file: ./backend/.env
    volumes:
      - app_data:/data
    # shm_size: 1gb        # odkomentuj gdy Chromium
    # mem_limit: 3g
    healthcheck:
      test: ["CMD", "node", "-e", "fetch('http://127.0.0.1:3000/health').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 20s
    restart: unless-stopped
volumes:
  app_data:
```

**frontend/nginx.conf** (fragment kluczowy)
```nginx
server {
  listen 80;
  root /usr/share/nginx/html;
  location /api/ { proxy_pass http://backend:3000/api/; proxy_read_timeout 120s; }
  location / { try_files $uri /index.html; }
}
```

**backend/src/server.js** (szkielet)
```js
const fastify = require('fastify')({ logger: true });
fastify.get('/health', async () => ({ ok: true }));
// endpointy /api/...
fastify.listen({ port: 3000, host: '0.0.0.0' });   // 0.0.0.0, nie localhost!
```

**backend/Dockerfile** (wariant z Chromium - usuń apt gdy bez renderu)
```dockerfile
FROM node:22-bookworm-slim
RUN apt-get update && apt-get install -y chromium fonts-liberation && rm -rf /var/lib/apt/lists/*
ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "src/server.js"]
```

Po scaffoldzie: `git init` + pierwszy commit (przed uruchomieniem - czysty punkt odniesienia).

## Krok 4 - uruchomienie

```bash
cd <projekt> && docker compose up -d --build
```
Czekaj na healthy w pętli (`docker compose ps --format json`, max ~90 s). Serwis nie wstaje → `docker compose logs --tail=100 <serwis>`, napraw, powtórz. Trzy nieudane podejścia do TEGO SAMEGO błędu → przełącz się na procedurę `/debuguj` (dowody przed hipotezami), nie zgaduj czwarty raz.

## Krok 5 - dowód E2E (obowiązkowy)

**Claude-in-Chrome NIE widzi localhost** (error page mimo działającego serwera). Weryfikuj od środka:

1. Projekt z Chromium: `docker cp backend/e2e-smoke.cjs <kontener>:/app/ && docker exec <kontener> node /app/e2e-smoke.cjs` - skrypt otwiera `http://frontend`, klika główny happy path, robi screenshoty do `/data/e2e/`. Potem `docker cp` na hosta i **Read każdego screenshota** (własne oczy, nie exit code).
2. Projekt bez Chromium w backendzie: NIE zadowalaj się curl-em. Dodaj do compose
   osobny serwis `e2e` z `profiles: ["test"]` (node + chromium + puppeteer-core,
   `shm_size: 1gb`, `init: true`, podpięty wolumen danych), uruchamiany:
   `docker compose --profile test run --rm e2e`. Realne screenshoty happy path
   (w tym drag & drop przez page.mouse) zamiast samych kodów HTTP; obraz e2e nie
   wchodzi do runtime. Bazuj go na sprawdzonym obrazie (pułapka 16 z playbooka).
3. Reguły smoke-testu (opłacone iteracjami):
   - klik + czekaj na PRZYROST licznika po KAŻDYM kliku (element przesuwa się po
     re-renderze - szybkie N x klik gubi kliknięcia),
   - zbieraj console errors + pageerror i WYPISUJ je w catch (przy timeout bez tego
     nie widać pierwotnej przyczyny),
   - czyść dane testowe przez API backendu na starcie przebiegu,
   - asercje na data-atrybutach (np. data-start/data-dni), nie na pikselach.
4. Zapisz wynik w raporcie: co kliknięte/wywołane, jaki status, co na screenshocie.

**Szkielet e2e-smoke.cjs:**
```js
const puppeteer = require('puppeteer-core');
(async () => {
  const browser = await puppeteer.launch({ executablePath: process.env.PUPPETEER_EXECUTABLE_PATH,
    args: ['--no-sandbox', '--disable-dev-shm-usage'] });
  const page = await browser.newPage();
  await page.setViewport({ width: 1280, height: 800 });
  await page.goto('http://frontend', { waitUntil: 'load' });
  await page.screenshot({ path: '/data/e2e/01-start.png' });
  // ...happy path: klik, formularz, wynik, screenshot po każdym kroku
  await browser.close();
})().catch(e => { console.error(e); process.exit(1); });
```

## Krok 6 - raport i domknięcie

1. Raport: port, serwisy, co przetestowane, ścieżki screenshotów, komendy dev-loop.
2. Zaproponuj następne kroki: `/mvp` gdy PoC dojrzeje do wdrożenia, `/kontekst` na koniec sesji.
3. Commit końcowy.

## Playbook pułapek Windows + Docker (KANON - wklej do CLAUDE.md projektu)

Sekcja obowiązkowa w generowanym CLAUDE.md (skopiuj 1:1, usuń nieadekwatne dla wariantu bez Chromium/AI):

```markdown
## Pułapki środowiska (Windows + Docker Desktop + Git Bash)

1. `docker exec` + Git Bash mangluje ścieżki `/data/...` na `C:/Program Files/Git/data/...`
   - przed komendą ustaw `MSYS_NO_PATHCONV=1`.
2. `curl -d` z polskimi znakami w Git Bash psuje Content-Length
   (FST_ERR_CTP_INVALID_CONTENT_LENGTH) - payloady z diakrytykami ZAWSZE przez
   `--data-binary @plik.json`.
3. Claude-in-Chrome nie ma dostępu do localhost - weryfikacja UI wyłącznie Puppeteerem
   WEWNĄTRZ kontenera (docker cp skrypt + docker exec node).
4. Iframe `sandbox=""` ma origin "null" - fonty blokowane przez CORS (obrazy nie).
   Endpointy fontów muszą zwracać `Access-Control-Allow-Origin: *`.
5. Bind portów na `127.0.0.1:PORT:80` - Chrome łączy się z 127.0.0.1.
6. CRLF w `*.sh` = "no such file or directory" w kontenerze - `.gitattributes`: `*.sh text eol=lf`.
7. Dane w named volumes, NIE bind-mount NTFS (prawa, wydajność).
8. Prompty do AI pisz PEŁNYMI polskimi diakrytykami - prompt ASCII uczy model
   odpowiadać bez ogonków ("Sprawdz repertuar").
9. Odpowiedzi AI (JSON) - walidacja AJV + sanityzacja + retry + fallback deterministyczny.
10. Puppeteer: `setContent`/`goto` z `waitUntil:'load'` (networkidle0 wiesza się na
    zdalnych fontach); assety jako base64 data URI (file:// blokowany w setContent);
    JEDNA współdzielona strona na cały przebieg renderu (nowa strona per item dławi
    render: 8 plansz 102-218 s vs 41 s na wspólnej).
11. Zapisy stanu atomowo (tmp + rename); po restarcie rekoncyliacja jobów
    (nieterminalne -> error "przerwane restartem", inaczej frontend polluje wiecznie).
12. Fetch URL od usera = SSRF: blokada prywatnych IP (literal + dns.lookup) także
    przy pobieraniu obrazów.
13. Gdy Write skoruptuje polskie znaki (ś -> znak CJK) - zapisuj plik przez
    `python -c "open(..., 'w', encoding='utf-8').write(...)"`.
14. Limity pól frontend MUSZĄ = limity schematu backendu (maxLength = limit AJV),
    inaczej zatruty patch blokuje kolejne zapisy.
15. SVG z Illustratora/Figmy ma często viewBox całego artboardu - logo renderuje się
    mikroskopijnie; przycinaj viewBox do bbox realnej zawartości (svg.getBBox()+3%).
16. Obrazy z Puppeteerem/Chromium buduj na SPRAWDZONEJ bazie (lokalny działający
    obraz albo przypięty digest), NIE na świeżym pullu. Świeży node:22-bookworm-slim
    (6.07.2026) = SIGTRAP Chromium przy aktywacji CDP (pada Debian chromium 150
    ORAZ Chrome for Testing 149/150; seccomp unconfined nie pomaga; zwykły render
    bez CDP działa). Diagnoza: ta sama próba w znanym działającym obrazie
    (docker run --rm <stary-obraz> chromium --headless --no-sandbox
    --remote-debugging-port=0 --user-data-dir=/tmp/t about:blank + cat
    /tmp/t/DevToolsActivePort) rozcina obraz vs runtime.
17. crypto.randomUUID() istnieje tylko w secure context (https/localhost) - przez
    http://<hostname> (E2E w sieci compose, dostęp po LAN) pada TypeError i operacje
    "cicho nie działają". We froncie zawsze fallback:
    crypto.randomUUID ? crypto.randomUUID() : 'id-'+Date.now().toString(36)+'-'+Math.random().toString(36).slice(2,10)
```

## Checklist końcowy

- [ ] Wywiad max 2 rundy albo `--szybki`
- [ ] Architektura pokazana przed pisaniem plików
- [ ] Port wolny, bind 127.0.0.1
- [ ] `.gitattributes` z eol=lf, `.env` poza repo, `.env.example` w repo
- [ ] CLAUDE.md projektu z playbookiem pułapek i komendami dev-loop
- [ ] `docker compose ps` - wszystko healthy
- [ ] Smoke E2E z kontenera + screenshoty obejrzane (Read)
- [ ] git init + commity
- [ ] Raport + propozycja /mvp i /kontekst

Modele pod spodem dobierasz do zadania. U mnie codziennym koniem roboczym w Claude Code jest najmocniejszy dostępny model - w architekturze i debugowaniu różnica klasy modelu przekłada się wprost na liczbę iteracji. Dla skali: Anthropic wycenia Opus 4.8 na 5/25 USD za milion tokenów, a najmocniejszego Fable 5 na 10/50 USD; na teście SWE-Bench Pro Anthropic raportuje dla Opus 4.8 wynik 69,2% wobec 58,6% dla GPT-5.5. Skill jest jednak od modeli niezależny - dyscyplina działa na każdym.

Dowód: gantt-studio w jedną sesję

Pilotem skilla była aplikacja, której potrzebowałem naprawdę: gantt-studio - narzędzie do planowania z wykresem Gantta, przeciąganiem pasków zadań i zapisem do bazy. Przebieg sesji wyglądał tak, jak każe manifest: wywiad (4 pytania), architektura w 7 liniach, scaffold, docker compose up, dwa kontenery healthy na porcie 8181, smoke test E2E - 6 z 6 kroków zaliczonych, łącznie ze screenshotem przeciągniętego paska zadania, który obejrzałem w sesji.

Uczciwość każe dodać: pilot nie był bezbłędny i właśnie dlatego był wartościowy. Dwie świeże pułapki (ruletka świeżego obrazu bazowego i crypto.randomUUID poza bezpiecznym kontekstem) trafiły do playbooka jako pozycje 16 i 17 dokładnie po tej sesji. Fabryka działa tak: każda wpadka kosztuje raz, a płaci dywidendę w każdym kolejnym projekcie.

Od czego zacząć jutro

  1. Skopiuj skill według instrukcji wyżej i odpal /nowa-apka na jednym realnym pomyśle - takim, którego brakuje ci w pracy, nie na przykładzie z tutoriala.
  2. Nie kończ sesji bez trzech dowodów: healthy, zielony E2E, obejrzany screenshot. Pierwszy raz zaboli - to znak, że wcześniej wierzyłeś deklaracjom.
  3. Dopisuj własne blizny do playbooka. Skill jest twój; każda pułapka, za którą zapłacisz sesją, powinna kosztować cię tylko raz.

Kiedy PoC dojrzeje do pokazania ludziom, potraktuj go bramką bezpieczeństwa i niezawodności, zanim dostanie ruch - liczby Veracode wyżej wyjaśniają, dlaczego.

Co dalej
Podstawy pracy z Claude - od promptów po pierwsze projekty - znajdziesz w darmowym kursie Claude AI. Pojedyncze aplikacje krok po kroku: seria „Zbuduj to z AI” na blogu.
Zbudujesz coś tym skillem? Napisz, co wyszło - najciekawsze wdrożenia opiszę w kolejnych tekstach. Zapis na newsletter niżej.
Mateusz Czech - autor bloga

Autor

Mateusz Czech // Czechu

AI Senior Digital Product Specialist w grupie Górskie Resorty. Projektuję i wdrażam aplikacje oparte na AI dla sprzedaży i obsługi klienta w hotelach. Wcześniej w SentiOne współtworzyłem voicebota InfoNina dla Alior Banku (Celent Model Bank Awards 2022). Piszę o wdrożeniach AI na czechu.blog. Prywatnie gram w tenisa i słucham polskiego rapu.

Powiązane artykuły

Co jeszcze warto przeczytać

Newsletter Strategic AI Implementation

Co tydzień jeden framework, jedno case study, zero spamu

Dołącz do listy. Dostajesz to, czego nie wrzucam na bloga: kulisy moich wdrożeń, sprawdzone prompty, błędy do uniknięcia. Wypisujesz się jednym kliknięciem.