Az AI-ügynökök képesek olyan kódot generálni, amely lefordul.
Ez azonban még mindig nem az a mérce, amit szeretnél. A mérce az olyan kód, amely nem importál olyasmit, amit soha nem használ, nem any-cast-olja ki magát a típusrendszerből, nem hagyja figyelmen kívül a hibavisszatérési értékeket, és nem éget bele olyan hitelesítő adatokat, amelyeket a gosecnek el kellene kapnia az átnézés előtt.
Az AI-modellek régi Stack Overflow-válaszokon tanulnak, és az ott megismert mintákat szállítják, beleértve az elavult API-kat, a hiányzó típusannotációkat és azokat a függvényeket, amelyek technikailag helyesek, de túl nagyok ahhoz, hogy biztonságosan át lehessen nézni őket. Szükséged van egy linterre a folyamatban. Nem javaslatként, hanem kapuként.
Ez az útmutató három ökoszisztéma konfigurációját fedi le (Python a Ruff-fal, TypeScript/JavaScript az ESLint v10 flat configgal, és Go a golangci-linttel), kifejezetten azokra a hibamintákra hangolt szabályokkal, amelyeket az AI bevezet. Ezután bemutatja, hogyan tehető a kapu sokkal nehezebben megkerülhetővé, hogy az ügynök ne tudja egyszerűen a --no-verify kapcsolóval átugrani a helyi hookokat anélkül, hogy egy másik réteg elkapná.
A beállítás rétegzett: az IDE-szintű lintelés soron belül kapja el a problémákat, ahogy az ügynök ír, a pre-commit hookok elkapnak mindent, ami eljut egy commit-kísérletig, a CI pedig elkap mindent, ami helyileg átmegy. Minden réteg független, és kiválaszthatod a stackedre vonatkozó nyelvi szakaszokat. A betartató réteg ugyanúgy működik, függetlenül attól, melyik nyelvet linteled.
Röviden
- A Ruff (Python), az ESLint v10 (TS/JS) és a golangci-lint (Go) mindegyikének vannak olyan szabályai, amelyek elkapják az AI leggyakoribb hibáit
- Az alábbi konfigurációk kommentálva vannak; minden szabálynak megvan az oka
- A Lefthook kezeli a pre-commit kaput; a Cursor afterFileEdit hookja soron belül futtatja a lintet
- Négy betartató réteg sokkal nehezebbé teszi, hogy az AI-ügynökök a --no-verify kapcsolóval megkerüljék a kaput
- A CI a végső védőháló: az ügynökök nem tudnak --no-verify kapcsolót átadni a GitHub Actionsnek
Hogyan konfiguráljuk a Ruffot Python AI-kódhoz
A Ruff a megfelelő Python-linter az AI-asszisztált kódbázisokhoz. Elég gyors ahhoz, hogy minden fájlmentéskor lefuthasson anélkül, hogy bármit blokkolna, lefedi mind a stílust, mind a valódi logikai hibákat, és ugyanabban a binárisban formázó viselkedést is szállít (a Black helyettesítésére). Az alábbi szabályok azokat a konkrét hibamintákat célozzák, amelyeket az AI-modellek a leggyakrabban vezetnek be Pythonban.
A Ruff telepítése
pip install ruff
# or via uv (faster for new projects):
uv add --dev ruff
Ennyi. Nincs plugin-ökoszisztéma, nincs peer-függőségi egyeztetés.
A pyproject.toml konfiguráció
[tool.ruff]
line-length = 88
target-version = "py311"
[tool.ruff.lint]
select = [
"E", # pycodestyle — style consistency
"F", # pyflakes — catches unused imports (the most common AI artifact)
"I", # isort — import ordering (AI frequently reorders imports incorrectly)
"N", # pep8-naming — naming conventions
"UP", # pyupgrade — flags deprecated APIs (AI trains on old Stack Overflow answers)
"S", # flake8-bandit — security rules: subprocess.shell=True, eval(), hardcoded creds
"ANN", # type annotation enforcement (AI frequently omits return type annotations)
]
ignore = [] # intentional: do not add sweeping ignores in AI-assisted codebases
[tool.ruff.lint.per-file-ignores]
"tests/**" = ["S101"] # allow assert in tests
Az F szabályok azonnal megtérülnek. Az AI-kód olyan csomagokhoz generál import utasításokat, amelyeket végül nem használ, és az F401 (nem használt import) mindegyiket elkapja. Az UP szabályok elkapják a 3.10 előtti Python-válaszokból tanult elavult API-mintákra irányuló hívásokat; az UP006 és az UP007 önmagában is tucatnyi szükségtelen típusellenőrzési mintát jelez. Az S (Bandit) szabályok elkapják a biztonsági hibákat: a hitelesítő adatoknak tűnő, beégetett szövegeket (S105/S106), a subprocess(shell=True) általi shell-injekciót (S603/S607), a gyenge kriptográfiai választásokat (S324).
Az ignore = [] szándékos. Minden kivétel, amit ehhez a listához adsz, egy olyan AI-hibaosztály, amelynek az engedélyezése mellett döntöttél.
A Ruff futtatása
ruff check . # lint only — see what's wrong
ruff check --fix . # auto-fix safe violations (imports, formatting)
ruff format . # format the codebase (replaces Black)
A --fix alapértelmezetten alkalmazza a Ruff biztonságos javításait, például a nem használt importok eltávolítását vagy az egyértelmű formázási és lintelési korrekciók elvégzését. A Ruffnak vannak nem biztonságos javításai is, de ezekhez kifejezett beleegyezés szükséges, és gondosabban át kell nézni őket. Nézz át kézzel mindent, amit a Ruff nem tud biztonságosan megjavítani.
Hogyan konfiguráljuk az ESLint v10-et TypeScript és JavaScript AI-kódhoz
Az ESLint v10 elhagyta a régi .eslintrc.* konfigurációs formátumot. Minden mostantól flat config az eslint.config.mjs fájlban. Ha olyan oktatóanyagot találsz, amely .eslintrc.json vagy .eslintrc.js fájlt használ, az az ESLint v8-at vagy v9-et célozza, ahol a szintaxis más. Használd az alábbit.
Az ebben a konfigurációban szereplő @typescript-eslint szabályok azokat a konkrét hibamódokat célozzák, amelyek ismételten felbukkannak az AI által generált TypeScriptben: az any kibúvót, a monolitikus függvényeket, amelyeket nehéz átnézni, és a beégetett értékeket, amelyeknek konstansoknak kellene lenniük.
Az ESLint v10 telepítése TypeScript-támogatással
npm install --save-dev eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
# or with pnpm:
pnpm add -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin
Az ESLint v10.5.0 az aktuális verzió 2026 júniusában. A @typescript-eslint csomagoknak illeszkedniük kell a TypeScript-verziódhoz; a kompatibilitási mátrixért nézd meg a README-t.
Az eslint.config.mjs konfiguráció
import tseslint from '@typescript-eslint/eslint-plugin';
import tsParser from '@typescript-eslint/parser';
export default [
{
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: tsParser,
parserOptions: { project: './tsconfig.json' },
},
plugins: { '@typescript-eslint': tseslint },
rules: {
// AI defaults to `any` to bypass the type system — this blocks it
'@typescript-eslint/no-explicit-any': 'error',
// AI generates variables it declares but never uses
'@typescript-eslint/no-unused-vars': 'error',
// AI writes functions that work but are too long to review safely
'max-lines-per-function': ['error', { max: 50 }],
// AI overloads function signatures; this forces decomposition
'max-params': ['error', 2],
// AI hardcodes values that should be named constants
'no-magic-numbers': ['error', { ignore: [0, 1, -1] }],
// AI writes files that are too large to reason about in a single review
'max-lines': ['error', { max: 250 }],
// AI leaves console.log debugging in production code
'no-console': 'warn',
},
},
];
A max-lines-per-function: 50 szabály a legagresszívebb dolog ebben a konfigurációban. Egy AI-asszisztált kódbázisban az első futtatáskor folyamatosan bele fogsz ütközni. Ez a lényeg. Bele kell ütköznöd. Az 50 sort meghaladó függvények az elsők, amelyek lehetetlenné válnak az értelmezésre, amikor nagy mennyiségben nézel át AI-kimenetet.
A max-params: 2 szabály kikényszeríti a dekompozíciót. Az AI-modellek olyan kódbázisokon tanulnak, ahol az ötargumentumú függvények normálisak; a szabály ellenáll ennek azzal, hogy megköveteli az ügynöktől egy options objektum használatát, ami jobb tervezés és könnyebben olvasható.
Az ESLint futtatása
npx eslint . # lint
npx eslint . --fix # auto-fix safe issues
npx eslint . --max-warnings 0 # CI mode — treats warnings as errors
Használd a --max-warnings 0 kapcsolót a CI-lépésedben. Ez a no-console figyelmeztetéseket „technikailag feljegyezve" állapotból „valóban blokkoló" állapotba lépteti elő.
Opcionális: szigorúbb szabályok az AI által generált fájlokhoz
Ha a csapatod fájlelnevezési konvenciót használ az AI által generált kód jelölésére (*.ai.ts, *-generated.ts vagy hasonló), kifejezetten ezekre a fájlokra alkalmazhatsz szigorúbb szabályokat:
// Add to eslint.config.mjs after the main config object
{
files: ['**/*.ai.ts', '**/*.ai.tsx', '**/*-generated.ts'],
rules: {
'max-lines': ['error', { max: 100 }], // tighter file ceiling
'complexity': ['error', 5], // McCabe complexity limit
},
}
Hogyan konfiguráljuk a golangci-lintet Go AI-kódhoz
A golangci-lint a szabványos multi-linter-futtató Go-hoz. A gosec, errcheck, staticcheck és 40+ további linter mellett érkezik, amelyek egyetlen YAML-fájlból konfigurálhatók. Az AI által generált Go-kódhoz a kritikus szabályok a hibavisszatérési értékek ellenőrzése és a biztonsági minták felismerése: ez az a két hibakategória, amelyet az AI-modellek a legkövetkezetesebben elmulasztanak Go-ban.
A golangci-lint telepítése
# Official binary installer:
curl -sSfL https://golangci-lint.run/install.sh | sh -s -- -b "$(go env GOPATH)/bin" v2.12.2
# or via Homebrew:
brew install golangci-lint
A .golangci.yml konfiguráció
version: "2"
linters:
enable:
- gosec # security: flags hardcoded creds (G101), file path injection (G304), weak crypto (G401)
- unused # flags unused vars and functions — a common AI artifact in Go
- errcheck # AI frequently ignores error returns — this blocks it
- govet # catches subtle correctness bugs AI introduces
- staticcheck # comprehensive static analysis
- revive # style: catches non-idiomatic Go patterns AI writes
- misspell # AI occasionally misspells in comments and string literals
settings:
gosec:
severity: medium
confidence: medium
errcheck:
check-type-assertions: true # check `val, ok := x.(Type)` patterns
check-blank: true # catch `_ = someErr` error suppression
run:
timeout: 3m
issues-exit-code: 1
A Go hibakezelési mintája tervezésénél fogva explicit: minden függvény, amely meghibásodhat, egy error értéket ad vissza. Az AI-modellek értik ezt, de alulsúlyozzák; kihagyják a hibaellenőrzéseket a nem kritikus kódutakon. Az errcheck ezt a kihagyást lintelési hibává teszi.
A gosec a biztonsági linter. Az AI-kódnál elkapja azokat a mintákat, amelyeket az AI a 2020 előtti Go-oktatóanyagokból szedett fel: a nem biztonságos véletlenszám-generálást (G404), a nem biztonságos hash-függvényeket (G401), a fájljogosultsági problémákat (G306). Ezek azok a hibák, amelyeket nem kapsz el a kódátnézés során, mert szintaktikailag normálisnak tűnnek.
A golangci-lint futtatása
golangci-lint run ./... # lint all packages
golangci-lint run --fix ./... # auto-fix where possible
Hogyan kössük be a lintert a pre-commit hookokba
Egy pre-commit hook minden git commit előtt lefuttatja a lintet, és blokkolja a commitot, ha a lint elbukik. Ez azt jelenti, hogy az AI-ügynök nem tud olyan kódot commitolni, amely megbukik a beállított szabályaidon. Először ki kell javítania a szabálysértéseket.
A Lefthook az ajánlott opció. Platformfüggetlen, gyors, és olyan konfigurációs mintája van, amely kifejezetten az AI-ügynökök betartatásával működik (a következő szakaszban tárgyaljuk).
Lefthook
npm install --save-dev lefthook
npx lefthook install
lefthook.yml:
pre-commit:
parallel: true
commands:
lint-python:
glob: "*.py"
run: ruff check {staged_files} --fix
lint-js-ts:
glob: "*.{js,ts,tsx}"
run: npx eslint {staged_files} --fix
lint-go:
glob: "*.go"
run: golangci-lint run {staged_files}
fail_text: |
Lint failed. For AI Agents: fix all lint violations before committing.
Do not use --no-verify to bypass this gate.
A fail_text üzenetet az AI-ügynökök olvassák, amikor egy commit elbukik. A mintát dokumentálja Liam Bigelow írása a Lefthook lintbetartatásáról Claude Code-hoz. Ez önmagában nem állít meg egy elszánt ügynököt, de megadja neki a helyes következő utasítást („javítsd ki a lintszabálysértéseket"), ahelyett, hogy rábíznánk egy megkerülő megoldás kitalálását.
Alternatíva: pre-commit (csak Python beállításokhoz)
Ha csak Python-stacken vagy, és a pre-commit keretrendszert részesíted előnyben:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.15.17
hooks:
- id: ruff-check
args: [--fix]
- id: ruff-format
Cursor: soron belüli lintelés az afterFileEdit hookon keresztül
Ha Cursort használsz, azonnal kiválthatod a lintet, amikor az AI módosít egy fájlt, még mielőtt egyáltalán megkísérelne egy commitot. Hozd létre a .cursor/hooks.json fájlt a projekted gyökerében:
{
"hooks": {
"afterFileEdit": [
{
"match": "*.py",
"run": "ruff check {file} --fix"
},
{
"match": "*.{ts,tsx,js}",
"run": "npx eslint {file} --fix"
},
{
"match": "*.go",
"run": "golangci-lint run {file}"
}
]
}
}
Ez minden alkalommal elindul, amikor a Cursor AI-ja módosít egy fájlt. Az ügynök soron belül kap lint-visszajelzést, mielőtt befejezettnek tekintené a feladatot, így a legtöbb szabálysértés kijavul, mielőtt elérné a pre-commit kaput.
Hogyan tegyük a kaput nehezebben megkerülhetővé az AI-ügynökök számára
Négy betartató réteg sokkal nehezebbé teszi, hogy egy AI-ügynök a --no-verify kapcsolóval átugorja a pre-commit kaput. Mindegyik más támadási felületet céloz: a CLAUDE.md-ben lévő irányelvet, egy Claude Code deny szabályt, egy PreToolUse hookot és egy CI-védőhálót. Kezeld ezeket rétegzett beállításként, ne négy független garanciaként.
Az AI-ügynökök néha átadják a --no-verify kapcsolót a git commitnak, hogy átugorják a pre-commit hookokat, amikor a lint elbukik, és az ügynök úgy döntött, hogy a hibák „nem kapcsolódnak a változtatásaihoz". A döntés nem mindig téves, de nem szabad hagynod, hogy az ügynök egyoldalúan hozza meg. A lintkapu lényege éppen az, hogy egy ember állította be az irányelvet; az ügynök dolga az, hogy teljesítse, ne pedig kikerülje.
Íme az egyes rétegek és a támadási felület, amelyet lefednek.
1. réteg: dokumentáld az irányelvet a CLAUDE.md-ben
## Linting Policy
NEVER use `git commit --no-verify`. All commits must pass pre-commit hooks.
Pre-commit hooks run lint. Fix lint violations before committing. Do not treat
lint failures as unrelated to your changes — they may not be, and you don't get
to decide that.
A Claude Code a munkamenet indításakor olvassa a CLAUDE.md-t. Ez nem betartatás; az ügynök még mindig megkísérelheti a megkerülést. De megszünteti a „nem tudtam róla" lehetőséget, és világos irányelvet állít fel, amelyet az ügynöknek aktívan kell megsértenie, ami kevésbé valószínű, mint hogy egy megkerülő megoldást találjon ki a hallgatásból.
2. réteg: Claude Code deny szabály
Add hozzá a .claude/settings.json-höz:
{
"permissions": {
"deny": [
"Bash(git commit --no-verify*)"
]
}
}
Ez blokkolja az explicit hívást. Egy korlátozás: a deny szabály prefixillesztést használ, így csak a commit közvetlenül utáni --no-verify-et kapja el. Egy kellően kreatív ügynök másképp strukturálhatná a hívást. Ne hagyatkozz erre egyedül.
3. réteg: PreToolUse hook
Telepítsd a block-no-verify csomagot:
npm install --save-dev block-no-verify
Majd konfiguráld PreToolUse hookként a Claude Code beállításaiban. Ez minden eszközhívás előtt elindul, és megvizsgálja az argumentumokat a --no-verify után hat git alparancson keresztül, nem csak a commitnál. Nem nullával lép ki, hogy blokkolja a hívást, mielőtt az lefutna.
A kézikönyv itt: pydevtools.com nyíltan fogalmaz erről: „a hookréteg az egyetlen, amely megbízhatóan kikényszeríti a szabályt." Használd ezt a többi réteggel együtt; ne kezelj egyetlen helyi hookot sem teljes garanciaként.
4. réteg: CI-védőháló
A CI a szerveren fut, ahol az ügynöknek nincs shellje, amelybe kapcsolókat adhatna át:
# .github/workflows/lint.yml
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint Python
run: |
pip install ruff
ruff check . --output-format github
- name: Lint JS/TS
run: npx eslint . --max-warnings 0
- name: Lint Go
uses: golangci/golangci-lint-action@v9
with:
version: v2.12.2
Az AI-ügynökök nem tudnak --no-verify kapcsolót átadni a CI-nek. A GitHub Actions attól függetlenül fut, amit az ügynök helyileg tett. Ha egy commit valahogy mégis átment elbukott linttel, a CI elkapja, mielőtt összeolvadna.
Ez a végső védőháló.
Bónusz: ESLint MCP szerver
Ha Claude Code-ot használsz, van egy proaktív réteg, amely csökkenti, hogy egyáltalán milyen gyakran ütközöl bele a kapuba.
Az ESLint MCP szerver (@eslint/mcp) közvetlenül az ügynök eszközhurkába integrálja az ESLintet. Az ügynök a feladat során, még a commit megkísérlése előtt lekérdezheti az ESLintet. Telepítsd globálisan:
npm install -g @eslint/mcp@latest
Add hozzá a .claude/settings.json-höz:
{
"mcpServers": {
"eslint": {
"command": "npx",
"args": ["@eslint/mcp@latest"]
}
}
}
Ezzel a beállítással az ügynök a feladat során lekérdezheti az ESLintet. Az ügynök soron belül kap lint-visszajelzést, és néhány szabálysértés kijavítható, mielőtt elérnék a hookot. Ez nem helyettesíti a kaput, hanem csökkenti a kapun a zajt.
Gyakran ismételt kérdések
Mind a három lintert konfigurálnom kell, ha csak egy nyelven dolgozom?
Nem. Állítsd be a lintert az elsődleges nyelvedhez és a betartató réteget. Ha a stacked csak TypeScript, konfiguráld az ESLintet, és hagyd ki a Ruffot és a golangci-lintet. Az ügynök-megkerülés megelőzéséről szóló szakasz attól függetlenül érvényes, hogy melyik nyelvet linteled.
Tönkreteszik ezek a konfigurációk a meglévő kódbázisomat az első futtatáskor?
Szinte biztosan, és szándékosan. Futtasd a ruff check --fix . vagy az npx eslint . --fix parancsot, hogy először automatikusan kijavítsd a biztonságos szabálysértéseket. Ami az automatikus javítás után marad, az a kézi átnézési lista: a no-explicit-any cast-ok, az 50 sort meghaladó függvények, a hiányzó hibakezelés. Dolgozd át ezeket fokozatosan. Ne adj hozzá ignore szabályokat, hogy elkerüld a velük való foglalkozást.
A Biome jelenleg az ESLint helyettesítője?
A Biome v2.5.0 (2026 júniusában jelent meg) versenyképes a formázás és az alapvető lintszabályok terén. Gyorsabb az ESLintnél, és nulla konfigurációs ráfordítással jár, ha a bun x ultracite@latest init paranccsal telepíted. Az olyan csapatok számára, amelyek egyetlen eszközt szeretnének, és nincs szükségük a teljes @typescript-eslint szabálymélységre, a Biome ésszerű választás. Az ebben az útmutatóban szereplő AI-specifikus szabályokhoz (max-params, no-magic-numbers, max-lines-per-function AI-célzott küszöbértékekkel) az ESLint a @typescript-eslinttel még mindig nagyobb lefedettséggel rendelkezik. Mindkettőt futtathatod: a Biome-ot a formázáshoz és az alapvető linteléshez, az ESLintet az AI-specifikus szabályokhoz.
Mi van, ha az AI-ügynököm folyamatosan újragenerálja ugyanazokat a lintszabálysértéseket?
Az ügynök megkerüli a szabályt ahelyett, hogy kijavítaná a mögöttes problémát. A no-explicit-any esetén ez azt jelenti, hogy egy típusállítást ad hozzá ahelyett, hogy meghatározná a tényleges típust. A max-lines-per-function esetén azt jelenti, hogy kiemel egy segédfüggvényt, amely semmi hasznosat nem csinál, de a sorszámot a küszöb alá viszi. Egyik megoldás sem megy át a kódátnézésen. A lintszabály elkapta a tünetet; a gyökérok az ügynök promptja. Finomítsd a promptot, hogy meghatározza a típuskorlátozást vagy az elvárt dekompozíciót; az ügynök megbízhatóbban követi az explicit struktúrairányítást, mint az implicit szabályokat. Ha bonyolultabb ügynökbeállítást futtatsz, a munka egy dedikált al-ügynökre szűkítése, amelynek az utasításaiba bele van sütve a korlátozás, általában jobban tart, mint egyetlen széles prompt.
Az ESLint MCP szerver helyettesíti a pre-commit kaput?
Nem. Csökkenti, hogy milyen gyakran generál az ügynök olyan kódot, amely megbukik a kapun. A kapu továbbra is minden commitnál lefut. Az MCP szerver soron belüli ellenőrzése és a pre-commit hook betartatása egymást kiegészítik, ezért egyiket se távolítsd el.