JavaScript / TypeScript
- ESLint z twoją wspólną konfiguracją
- Prettier do formatowania
- typescript-eslint dla reguł lintingu świadomych TypeScriptu
tsc --noEmitdo sprawdzania typów
Bramy jakości kodu wspomagane przez AI to warstwowa weryfikacja: agent naprawiający błędy lintingu i typów w trakcie pisania, bezgłowy przegląd skanujący każdy diff pull requesta, zanim spojrzy na niego człowiek, oraz ciągłe monitorowanie, które wywala build przy regresji pokrycia lub złożoności. Każda warstwa łapie mechaniczne defekty przepuszczone przez poprzednią, w Cursorze, Claude Code i Codeksie.
Pewien null prześlizgnął się przez przegląd, trafił na produkcję w piątek i wybudził cię o drugiej w nocy. Diff wyglądał w porządku — zatwierdziło go trzech recenzentów — ale nikt nie zauważył niezabezpieczonego response.data.user.id na ścieżce, która uruchamia się wyłącznie przy logowaniu przez SSO. Piątek wcześniej pewien PR wprowadził wyciek pamięci w obsłudze sesji: przeszedł wszystkie testy, recenzent zatwierdził go po rzucie oka, a linter nie miał nic do powiedzenia. Do poniedziałku serwis zjadał 4GB RAM i crashował co sześć godzin.
Przegląd przez człowieka to niewłaściwe narzędzie do obu tych spraw. Styl, dziury w typach, zapytania N+1, brakująca walidacja danych wejściowych, nieobsłużone odrzucenia i powolne wycieki zasobów — to właśnie wyłapuje za każdym razem agent wpięty w bramę jakości, zanim jakikolwiek człowiek otworzy PR. Ten artykuł buduje taką bramę w Cursorze, Claude Code i Codeksie, aby recenzenci poświęcali uwagę architekturze i intencji zamiast udawać linter.
.cursor/rules, CLAUDE.md lub AGENTS.md), względem którego każdy agent sprawdza własny wyniktsc --noEmit na każdym pliku edytowanym przez agenta — z poprawnym schematem kluczowanym zdarzeniem i ścieżką pliku ze stdinChcesz wyłapywać defekty tak wcześnie i tak tanio, jak to możliwe, a żadna pojedyncza warstwa nie wystarcza sama w sobie. To oznacza trzy, z których każda wyłapuje to, co przepuściła poprzednia:
Reszta tego artykułu buduje każdą z warstw. Warstwy 1 i 2 są tam, gdzie te trzy narzędzia się różnią, więc korzystają z <Tabs>.
Wszystkie trzy narzędzia czytają plik reguł na poziomie projektu i stosują go do wszystkiego, co generują. Format i lokalizacja pliku się różnią; treść jest niemal identyczna. Trzymaj go w kontroli wersji, aby cały zespół — i każdy agent — pracowali według tego samego standardu. Pisz go jako sprawdzalne warunki, a nie aspiracje: limit linii i sufit złożoności da się zweryfikować, „pisz czysty kod” nie.
---description: Enterprise Code Quality StandardsalwaysApply: true---## Style- 2-space indentation, max line length 100- Every exported function has a JSDoc block- No `any` without a `// eslint-disable-next-line` and a reason- No magic numbers - use named constants
## Size and complexity- No function longer than 50 lines; no file longer than 300- Cyclomatic complexity under 10 per function
## Architecture- Data access goes through the repository layer, never inline SQL in handlers- Services receive dependencies via constructor injection- All outbound HTTP calls go through the shared `httpClient` wrapper- Error handling follows our Result<T, E> pattern (no bare try/catch)
## Performance- Paginate any endpoint that returns a list- No queries inside loops — batch with `IN (...)` or a join- Memoize pure functions that run on every render
## Security- Parameterized queries only- Validate request bodies with the Zod schema in `schemas/`- Never log tokens, passwords, or full request bodies## Coding Standards
### Style- ESLint config: `.eslintrc.json`; Prettier: `.prettierrc`- TypeScript strict mode; no `any` without an inline justification comment- No `console.log` in committed code — use the `logger` module
### Quality gates- Coverage floor: 80% on changed lines- Cyclomatic complexity limit: 10 (enforced by `eslint-plugin-complexity`)- No function over 50 lines; no file over 300- Every TODO references a ticket: `// TODO(PROJ-1234): ...`
### Before you finish a task- Run `npm run lint && npm run typecheck && npm test`- Add or update tests for new behavior- If a check fails, fix it before moving on — do not report done with a red gate- Update the relevant doc in `docs/` if you changed a public API## Project standards
Codex reads AGENTS.md from the repo root (and merges nested ones insubdirectories). Same rules as the other tools — keep them in sync.
### Style- 2-space indentation, max line length 100, Prettier-formatted- TypeScript strict; no `any` without a justification comment- Use `typescript-eslint` rules, not legacy formatting lint
### Quality gates- 80% coverage on changed lines; complexity limit 10- All new code ships with tests; no lint warnings in new code- Parameterized queries only; validate inputs with Zod
### After every code modification1. Run the file's test suite2. Run the linter on the changed files3. Run type checking4. If any check fails, fix it before proceedingNajczęstszym błędem jest tutaj konfiguracja hooka, która po cichu nigdy się nie uruchamia. Claude Code zagnieżdża tablice hooków pod nazwą zdarzenia (PostToolUse, PreToolUse) wewnątrz obiektu hooks najwyższego poziomu — goła tablica hooks na najwyższym poziomie się nie załaduje. Matcher to wyrażenie regularne uruchamiane na tool_name, więc musi mieć postać Write|Edit z tą wielkością liter. Hooki nie otrzymują też edytowanej ścieżki w zmiennej środowiskowej; czytają JSON ze stdin i wyciągają .tool_input.file_path.
Umieść logikę w skrypcie, aby konfiguracja pozostała czytelna:
{ "hooks": { "PreToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "node scripts/quality-check.js" } ] } ], "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/format-and-lint.sh" } ] } ] }}#!/usr/bin/env bashset -euo pipefail
# The edited path arrives as JSON on stdin, not as an env var.FILE_PATH=$(jq -r '.tool_input.file_path // empty')[ -z "$FILE_PATH" ] && exit 0
npx prettier --write "$FILE_PATH"npx eslint --fix "$FILE_PATH"
# Type-check only TS files; tsc does the type checking, not a linter.case "$FILE_PATH" in *.ts|*.tsx) npx tsc --noEmit ;;esacPreToolUse to brama, która może odmówić zapisu, zanim ten nastąpi — użyj jej do kontroli polityki, które mają zatrzymać edycję (chroniona ścieżka, zakazany import). PostToolUse to przebieg naprawczy. $CLAUDE_PROJECT_DIR to jedna z nielicznych prawdziwych zmiennych hooków (obok $CLAUDE_ENV_FILE dla SessionStart i $CLAUDE_CODE_REMOTE); otocz ją cudzysłowami, aby ścieżki ze spacjami przetrwały.
W Cursorze odpowiednikiem jest pętla auto-naprawy: gdy błędy ESLint trafiają do panelu Problems, agent je naprawia i uruchamia ponownie, aż będzie czysto. Codex stosuje ten sam krok eslint --fix w swoim sandboksie, gdy poprosisz go o „make lint pass” w ramach zadania.
JavaScript / TypeScript
tsc --noEmit do sprawdzania typówPython
Java
Go
Najużyteczniejszym nawykiem w edytorze jest zabijanie any w chwili, gdy kontroler typów na nie wskaże — any to dziura, przez którą przegląda cała brama. Pętla auto-naprawy Cursora robi to przy włączeniu, ale prompt działa we wszystkich trzech narzędziach.
Czysty wynik wygląda tak — rzutowanie staje się nazwanym, sprawdzalnym kontraktem:
interface UserResponse { id: string; status: 'active' | 'inactive'; metadata: Record<string, unknown>;}
const data = response.data as UserResponse;To tutaj brama zarabia na swoje utrzymanie. Konfiguracja jest naprawdę trójnarzędziowa: każde narzędzie uruchamia bezgłowego agenta na diffie PR i publikuje uwagi.
Wbudowanym przeglądem PR w Cursorze jest BugBot. Włącz go z integracji GitHub w panelu, a następnie wrzuć .cursor/BUGBOT.md do katalogu głównego repo, aby sterować tym, co oznacza (zobacz wytyczne przeglądu poniżej). Po połączeniu BugBot automatycznie komentuje inline na PR.
Dodaj serwer MCP GitHuba (zdalny HTTP — nie ma wbudowanego skrótu github, a transport oraz URL są wymagane):
claude mcp add --transport http github https://api.githubcopilot.com/mcp/# Auth via OAuth on first use, or pass a token:# --header "Authorization: Bearer $GITHUB_PAT"Konkretnie do automatyzacji PR zainstaluj aplikację GitHub App, aby można było wzmiankować Claude’a na PR-ach:
/install-github-appUżyj Codex Cloud code review: połącz repo w panelu Codex Cloud i włącz automatyczny przegląd dla pull requestów. Codex czyta AGENTS.md w poszukiwaniu twoich standardów i publikuje komentarze przeglądu. Do doraźnego przeglądu lokalnego uruchom bezgłowy krok codex exec pokazany w następnej sekcji.
Zarówno .cursor/BUGBOT.md w Cursorze, jak i prompt podany Claude Code lub Codeksowi zyskują na jawnej liście kontrolnej. Skup ją na tym, co ludzie regularnie przeoczają:
# .cursor/BUGBOT.md (or paste into the review prompt)
## Security (block on any of these)- Hardcoded credentials, tokens, or API keys- Unparameterized SQL or string-concatenated queries- Unvalidated request bodies reaching the database- Missing auth check on a protected route- User input rendered without escaping (XSS)
## Correctness- Unhandled promise rejections / missing `await`- Null/undefined dereferences on optional fields- N+1 query patterns (a query inside a `.map`/loop)
## Quality- New code without tests- Functions over 50 lines or complexity over 10- Logging that includes sensitive dataWrzuć to do dowolnego repo. Uruchamia się na pull requestach i publikuje uwagi agenta. Zwróć uwagę na actions/checkout@v6 — @v3 jest wycofany i wymusza uruchamianie akcji JavaScript na nieobsługiwanym środowisku Node.
BugBot działa jako hostowana integracja GitHub, więc nie ma żadnego YAML-a CI do utrzymywania — po włączeniu przegląda PR-y automatycznie. Skorzystaj z zakładki Claude Code lub Codex, jeśli zamiast tego chcesz, aby krok przeglądu mieszkał w twoim własnym pliku workflow.
name: AI Code Reviewon: [pull_request]
jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - name: AI review env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} run: | git diff origin/${{ github.base_ref }}...HEAD > diff.patch claude -p "Review the diff in diff.patch against .cursor/BUGBOT.md. \ Report only real defects as 'file:line — issue — fix', \ grouped by Security / Correctness / Quality. \ If nothing is wrong, say 'No blocking issues.'" \ --output-format json > review.jsonname: AI Code Reviewon: [pull_request]
jobs: review: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 with: fetch-depth: 0 - name: AI review env: CODEX_API_KEY: ${{ secrets.OPENAI_API_KEY }} run: | git diff origin/${{ github.base_ref }}...HEAD > diff.patch codex exec --sandbox read-only -c approval_policy=never \ "Review diff.patch against AGENTS.md. Report only real \ defects as 'file:line — issue — fix', grouped by \ Security / Correctness / Quality."Ten nieinteraktywny przegląd nie może wyświetlić nowego monitu o zatwierdzenie. Używaj approval_policy=never tylko z zaufaną tożsamością CI o minimalnych uprawnieniach; read-only pozostaje egzekwowaną granicą sandboxa, a każda akcja wymagająca szerszego dostępu kończy się błędem.
Dla codziennych pull requestów trzymaj przegląd wąsko i świadomie wobec stacku. Wartością jest krótka lista prawdziwych defektów, a nie rzetelny esej.
Zmiana na ścieżce płatności albo we współdzielonej abstrakcji zasługuje na więcej niż przebieg rutynowy. Ten prompt dodaje wymiary, które rutynowy celowo pomija — architekturę, utrzymywalność, testowalność — i każe agentowi sklasyfikować każdą uwagę, żebyś mógł ją przetriażować.
Gdy jeden przebieg daje płytką, zlepioną odpowiedź — częsta awaria przy dużym lub nieznanym diffie — uruchom wymiary jako osobne konwersacje. Każda soczewka dostaje pełną uwagę modelu, a te, które wrócą puste, po prostu wyrzucasz.
Uruchom każdą soczewkę jako osobną konwersację w trybie Agent dla większej głębi:
Lens 1 - Correctness: Review /src/services/payment.ts changes.Assume every input is adversarial. Find every way this code couldproduce incorrect results, crash, or behave unexpectedly.Lens 2 - Performance: Same file. Assume 10,000 requests per second.Find bottlenecks, memory leaks, and unnecessary allocations.Lens 3 - Security: Same file. You are a penetration tester.Find every way to exploit this code.Użyj pod-agentów do uruchomienia wielu soczewek przeglądu równolegle:
claude "Review the changes in the current git diff through five lenses.For each lens, provide separate findings:
1. CORRECTNESS: Logic errors, edge cases, race conditions2. PERFORMANCE: N+1 queries, memory leaks, unnecessary computation3. SECURITY: Injection, auth bypass, data exposure4. MAINTAINABILITY: Complexity, naming, documentation gaps5. TESTABILITY: Missing tests, untestable patterns, flaky test risks
Rank all findings by severity and present the top 10 across all lenses."Perform a five-lens code review on the changes in this PR:1. Correctness: Will this produce wrong results for any valid input?2. Performance: Will this degrade under production load?3. Security: Can this be exploited by a malicious user?4. Maintainability: Will the next developer understand and modify this safely?5. Testability: Are there edge cases that the tests do not cover?
Post findings as inline PR comments at the relevant lines.Prawdziwe monitorowanie oznacza prawdziwe narzędzia, a nie model przypominający sobie liczby. SonarQube (lub SonarCloud) to standard: liczy pokrycie, złożoność cyklomatyczną i duplikację przy każdym buildzie oraz śledzi trend. Wepnij go w ten sam workflow:
# add to .github/workflows/ai-review.yml - name: SonarQube scan uses: SonarSource/sonarqube-scan-action@v6 env: SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} with: args: > -Dsonar.qualitygate.wait=trueFlaga qualitygate.wait=true blokuje PR, jeśli brama jakości Sonara dla projektu nie przejdzie (na przykład pokrycie nowego kodu poniżej 80% albo nowy problem o krytyczności blocker). To twój punkt egzekwowania — konkretny, zmierzony i taki, którego agent nie zagada.
Aby uzyskać odpowiedź na pytanie „co AI o tym sądzi?”, podaj agentowi wyniki Sonara, zamiast prosić go o wymyślanie metryk:
Comiesięczny przegląd kondycji obejmuje to, czego brama działająca per PR strukturalnie nie zobaczy: dryf. Uruchamiaj go w sesji, w której agent faktycznie może mierzyć — raport pokrycia na dysku, git log, skan martwego kodu, skan duplikacji — i napisz mu to wprost. Zapytany na sucho model chętnie wyprodukuje wiarygodnie wyglądający dashboard liczb, których nigdy nie policzył, a to gorsze niż brak dashboardu.
Procent pokrycia nie mierzy jakości; mierzy, które linie się wykonały. Oto liczby, które ruszają się, gdy brama naprawdę działa:
| Metryka | Co ujawnia | Cel |
|---|---|---|
| Wynik mutacyjny | Testy rzeczywiście łapią błędy, nie tylko wykonują kod | > 75% |
| Średni czas wykrycia | Jak szybko błędy są znajdowane po wprowadzeniu | < 1 sprint |
| Wskaźnik uciekających defektów | Błędy, które docierają do produkcji | < 2% zmian |
| Czas reakcji na przegląd | Jak długo PR czeka na przegląd | < 4 godziny |
| Wskaźnik przeróbek | PR wymagające > 2 rund przeglądu | < 15% |
| Niezawodność buildu | Wskaźnik sukcesu pipeline CI | > 95% |
Wynik mutacyjny warto postawić jako pierwszy, bo to jedyna metryka na tej liście, której nie da się ograć pisaniem kolejnych testów niczego nie sprawdzających.
Częstą regresją na produkcji jest zapytanie lub endpoint, które działają świetnie podczas przeglądu i padają pod obciążeniem. Wpisz testy obciążeniowe w bramę za pomocą k6 — progi są prawdziwe i sprawiają, że test sam przechodzi lub nie przechodzi.
Wygenerowany test koduje progi jako warunki bramy, więc regresja zmienia krok CI na czerwony:
import http from 'k6/http';import { check } from 'k6';
export const options = { stages: [ { duration: '2m', target: 200 }, { duration: '5m', target: 200 }, { duration: '2m', target: 0 }, ], thresholds: { http_req_duration: ['p(95)<500'], http_req_failed: ['rate<0.01'], },};
export default function () { const res = http.post( `${__ENV.BASE_URL}/api/checkout`, JSON.stringify({ cartId: 'c_1', paymentMethodId: 'pm_1', idempotencyKey: `${__VU}-${__ITER}` }), { headers: { 'Content-Type': 'application/json' }, tags: { name: 'checkout' } }, ); check(res, { 'status 200': (r) => r.status === 200 });}Brama, którą uruchamia jedno repozytorium, to prywatny nawyk. Rozprowadzenie jej oznacza, że same standardy stają się wersjonowanym artefaktem:
Stwórz współdzielony pakiet konfiguracji
Jeden pakiet — w twoim monorepo albo opublikowany w npm — zawierający konfiguracje ESLint, TypeScript i Prettier oraz pliki reguł AI.
Dystrybuuj przez zarządzanie pakietami
Każdy projekt rozszerza współdzieloną konfigurację. Lokalne nadpisania muszą być udokumentowane i zatwierdzone, a nie po cichu dodane.
Egzekwuj w CI
Pipeline sprawdza, czy współdzielone konfiguracje nie zostały nadpisane bez zatwierdzenia.
Wskaż regułom AI współdzielony standard
.cursor/rules, CLAUDE.md i AGENTS.md odwołują się do współdzielonego dokumentu standardów, zamiast każdy dryfować z własną kopią.
Przeglądaj kondycję co miesiąc
Uruchamiaj przegląd kondycji bazy kodu cyklicznie i porównuj zespoły ze współdzielonymi benchmarkami, tak by regresja była linią trendu, a nie incydentem.
Gdy powyższe prompty okażą się przydatne, zapisz je jako wielokrotnego użytku polecenia slash. Plik .claude/commands/security-audit.md staje się poleceniem /security-audit w interaktywnej sesji Claude Code (podkatalogi dodają przestrzenie nazw — .claude/commands/review/pr.md to /review:pr). Wywołaj je w REPL:
> /security-auditprzy czym plik polecenia zawiera twój prompt skupiony na OWASP. Cursor udostępnia tę samą ideę przez zapisane prompty; Codex przez workflow w AGENTS.md i niestandardowe prompty.