| name | linter-integration |
| description | Auto-detects and runs project-specific linters, formatters, and typecheckers. Supports Python (ruff, mypy, black, flake8, pylint) and TypeScript (eslint, tsc, prettier). Uses existing project configuration. |
| allowed-tools | Read, Grep, Glob, Bash(ruff:*), Bash(mypy:*), Bash(black:*), Bash(flake8:*), Bash(pylint:*), Bash(eslint:*), Bash(tsc:*), Bash(npx:*), Bash(prettier:*), Bash(uv:*), Bash(npm:*), Bash(pnpm:*), Bash(yarn:*), Bash(command:*), Bash(jq:*), Bash(cat:*), Bash(head:*), Bash(python:*), Bash(node:*) |
Linter Integration - Auto-Detect & Run Project Tools
Automatically detects and runs project-configured linters, formatters, and typecheckers to ensure code quality review uses the project's own standards.
Core Principle
Use the project's existing configuration. Don't impose external rules - run linters with the configs that the project already has.
Prerequisites Check
ALWAYS run this check first:
echo "=== Linter Tools Availability ==="
echo "--- Python ---"
command -v ruff >/dev/null 2>&1 && echo "OK: ruff $(ruff --version 2>/dev/null | head -1)" || echo "MISSING: ruff"
command -v mypy >/dev/null 2>&1 && echo "OK: mypy $(mypy --version 2>/dev/null)" || echo "MISSING: mypy"
command -v black >/dev/null 2>&1 && echo "OK: black $(black --version 2>/dev/null | head -1)" || echo "OPTIONAL: black"
command -v flake8 >/dev/null 2>&1 && echo "OK: flake8" || echo "OPTIONAL: flake8"
command -v pylint >/dev/null 2>&1 && echo "OK: pylint" || echo "OPTIONAL: pylint"
echo "--- TypeScript/JavaScript ---"
command -v npx >/dev/null 2>&1 && echo "OK: npx (npm)" || echo "MISSING: npx"
command -v eslint >/dev/null 2>&1 && echo "OK: eslint (global)" || echo "INFO: eslint (check local)"
command -v tsc >/dev/null 2>&1 && echo "OK: tsc (global)" || echo "INFO: tsc (check local)"
echo "--- Utilities ---"
command -v jq >/dev/null 2>&1 && echo "OK: jq" || echo "OPTIONAL: jq (JSON formatting)"
Project Type Detection
Step 1: Detect Python Project
echo "=== Python Project Detection ==="
[ -f "pyproject.toml" ] && echo "FOUND: pyproject.toml (modern Python project)"
[ -f "setup.py" ] && echo "FOUND: setup.py (legacy Python project)"
[ -f "setup.cfg" ] && echo "FOUND: setup.cfg"
[ -f "requirements.txt" ] && echo "FOUND: requirements.txt"
[ -f "uv.lock" ] && echo "FOUND: uv.lock (uv managed)"
[ -f "poetry.lock" ] && echo "FOUND: poetry.lock (Poetry managed)"
python_files=$(find . -name "*.py" -not -path "./.venv/*" -not -path "./venv/*" -not -path "./.git/*" 2>/dev/null | wc -l)
echo "Python files found: $python_files"
Step 2: Detect Python Linter Configs
echo "=== Python Linter Configuration ==="
[ -f "ruff.toml" ] && echo "FOUND: ruff.toml"
[ -f ".ruff.toml" ] && echo "FOUND: .ruff.toml"
grep -q "\[tool.ruff\]" pyproject.toml 2>/dev/null && echo "FOUND: [tool.ruff] in pyproject.toml"
[ -f "mypy.ini" ] && echo "FOUND: mypy.ini"
[ -f ".mypy.ini" ] && echo "FOUND: .mypy.ini"
grep -q "\[tool.mypy\]" pyproject.toml 2>/dev/null && echo "FOUND: [tool.mypy] in pyproject.toml"
[ -f ".flake8" ] && echo "FOUND: .flake8"
[ -f "setup.cfg" ] && grep -q "\[flake8\]" setup.cfg 2>/dev/null && echo "FOUND: [flake8] in setup.cfg"
[ -f "pylintrc" ] && echo "FOUND: pylintrc"
[ -f ".pylintrc" ] && echo "FOUND: .pylintrc"
[ -f "pyproject.toml" ] && grep -q "\[tool.pylint\]" pyproject.toml 2>/dev/null && echo "FOUND: [tool.pylint] in pyproject.toml"
[ -f "pyproject.toml" ] && grep -q "\[tool.black\]" pyproject.toml 2>/dev/null && echo "FOUND: [tool.black] in pyproject.toml"
Step 3: Detect TypeScript/JavaScript Project
echo "=== TypeScript/JavaScript Project Detection ==="
[ -f "package.json" ] && echo "FOUND: package.json"
[ -f "tsconfig.json" ] && echo "FOUND: tsconfig.json (TypeScript)"
[ -f "jsconfig.json" ] && echo "FOUND: jsconfig.json (JavaScript)"
ts_files=$(find . \( -name "*.ts" -o -name "*.tsx" \) -not -path "./node_modules/*" -not -path "./.git/*" 2>/dev/null | wc -l)
js_files=$(find . \( -name "*.js" -o -name "*.jsx" \) -not -path "./node_modules/*" -not -path "./.git/*" 2>/dev/null | wc -l)
echo "TypeScript files found: $ts_files"
echo "JavaScript files found: $js_files"
Step 4: Detect TypeScript Linter Configs
echo "=== TypeScript/JavaScript Linter Configuration ==="
[ -f ".eslintrc" ] && echo "FOUND: .eslintrc"
[ -f ".eslintrc.js" ] && echo "FOUND: .eslintrc.js"
[ -f ".eslintrc.cjs" ] && echo "FOUND: .eslintrc.cjs"
[ -f ".eslintrc.json" ] && echo "FOUND: .eslintrc.json"
[ -f ".eslintrc.yml" ] && echo "FOUND: .eslintrc.yml"
[ -f "eslint.config.js" ] && echo "FOUND: eslint.config.js (flat config)"
[ -f "eslint.config.mjs" ] && echo "FOUND: eslint.config.mjs (flat config)"
[ -f ".prettierrc" ] && echo "FOUND: .prettierrc"
[ -f ".prettierrc.json" ] && echo "FOUND: .prettierrc.json"
[ -f ".prettierrc.js" ] && echo "FOUND: .prettierrc.js"
[ -f "prettier.config.js" ] && echo "FOUND: prettier.config.js"
[ -f "prettier.config.mjs" ] && echo "FOUND: prettier.config.mjs"
[ -f "package.json" ] && grep -q '"eslintConfig"' package.json && echo "FOUND: eslintConfig in package.json"
[ -f "package.json" ] && grep -q '"prettier"' package.json && echo "FOUND: prettier config in package.json"
Python Linting
Ruff (Preferred - Fast, All-in-One)
if [ -f "ruff.toml" ] || [ -f ".ruff.toml" ] || grep -q "\[tool.ruff\]" pyproject.toml 2>/dev/null; then
echo "Running ruff with project configuration..."
ruff check . --output-format=json 2>/dev/null
else
echo "Running ruff with default rules..."
ruff check . --select=E,W,F,I,N,UP,B,A,C4,SIM --output-format=json 2>/dev/null
fi
Parse ruff JSON output:
ruff check . --output-format=json --output-file /tmp/ruff-results.json 2>/dev/null
After scan: Read /tmp/ruff-results.json with the Read tool. Key fields to extract per finding: .code, .filename, .location.row, .location.column, .message, .fix (check if not null for auto-fixable issues).
Mypy (Type Checking)
if [ -f "mypy.ini" ] || [ -f ".mypy.ini" ] || grep -q "\[tool.mypy\]" pyproject.toml 2>/dev/null; then
echo "Running mypy with project configuration..."
mypy . --show-error-codes --no-error-summary 2>/dev/null
else
echo "Running mypy with permissive defaults..."
mypy . --ignore-missing-imports --show-error-codes --no-error-summary 2>/dev/null
fi
Parse mypy output:
mypy . --show-error-codes --no-error-summary 1>/tmp/mypy-results.txt 2>/dev/null
After scan: Read /tmp/mypy-results.txt with the Read tool and analyze the type error results.
Flake8 (Legacy but Common)
if [ -f ".flake8" ] || grep -q "\[flake8\]" setup.cfg 2>/dev/null; then
echo "Running flake8 with project configuration..."
flake8 . --format=json 2>/dev/null
fi
Pylint (Comprehensive but Slow)
if [ -f "pylintrc" ] || [ -f ".pylintrc" ] || grep -q "\[tool.pylint\]" pyproject.toml 2>/dev/null; then
echo "Running pylint with project configuration..."
pylint --output-format=json . --output=/tmp/pylint-results.json 2>/dev/null
fi
After scan: Read /tmp/pylint-results.json with the Read tool. Key fields: .[].type (severity), .[].path, .[].line, .[].column, .[].symbol, .[].message.
TypeScript/JavaScript Linting
ESLint (Primary)
if [ -f "eslint.config.js" ] || [ -f "eslint.config.mjs" ]; then
echo "Running ESLint with flat config..."
npx eslint . --format=json 2>/dev/null
elif [ -f ".eslintrc.js" ] || [ -f ".eslintrc.json" ] || [ -f ".eslintrc.yml" ] || [ -f ".eslintrc" ]; then
echo "Running ESLint with legacy config..."
npx eslint . --format=json 2>/dev/null
else
echo "No ESLint config found, skipping..."
fi
Parse ESLint JSON output:
npx eslint . --format=json -o /tmp/eslint-results.json 2>/dev/null
After scan: Read /tmp/eslint-results.json with the Read tool. Key fields: .[].filePath, .[].errorCount, .[].warningCount, .[].messages[].severity (2=error, 1=warning), .[].messages[].line, .[].messages[].ruleId, .[].messages[].message.
TypeScript Compiler (tsc)
if [ -f "tsconfig.json" ]; then
echo "Running TypeScript type check..."
npx tsc --noEmit 1>/tmp/tsc-results.txt 2>&1
fi
After scan: Read /tmp/tsc-results.txt with the Read tool and filter for error lines.
Parse tsc errors:
npx tsc --noEmit 1>/tmp/tsc-errors.txt 2>&1
After scan: Read /tmp/tsc-errors.txt with the Read tool and filter for lines matching the pattern filename(line,col): error.
Prettier (Formatting Check)
if [ -f ".prettierrc" ] || [ -f ".prettierrc.json" ] || [ -f "prettier.config.js" ]; then
echo "Checking Prettier formatting..."
npx prettier --check . 1>/tmp/prettier-results.txt 2>&1
fi
After scan: Read /tmp/prettier-results.txt with the Read tool to identify files with formatting issues.
Unified Output Format
Normalize all linter outputs to this format:
{
"tool": "ruff|mypy|eslint|tsc|flake8|pylint|prettier",
"config_source": "pyproject.toml|.eslintrc.json|default",
"summary": {
"files_checked": 142,
"errors": 5,
"warnings": 23,
"info": 12
},
"issues": [
{
"severity": "ERROR|WARNING|INFO",
"file": "src/service.py",
"line": 42,
"column": 10,
"code": "E501",
"rule": "line-too-long",
"message": "Line too long (120 > 88 characters)",
"fix_available": true,
"category": "style|type|import|complexity|security"
}
]
}
Fallback: No Linter Config
When no project configuration exists, use sensible defaults:
Python Defaults
ruff check . --select=E,W,F --ignore=E501 --output-format=json 2>/dev/null
mypy . --ignore-missing-imports --no-strict-optional --show-error-codes 2>/dev/null
TypeScript Defaults
npx tsc --noEmit 1>/tmp/tsc-defaults.txt 2>&1
After scan: Read /tmp/tsc-defaults.txt with the Read tool and filter for lines containing error TS.
Priority Order
Run tools in this order (stop if comprehensive tool found):
Python
- ruff (if configured) - Comprehensive, fast
- mypy (if configured) - Type checking
- flake8 (if configured, no ruff) - Legacy style
- pylint (if configured, no ruff) - Deep analysis
TypeScript/JavaScript
- tsc (if tsconfig.json) - Type checking
- eslint (if configured) - Style and quality
- prettier (if configured) - Formatting only
Error Categories
Map linter codes to categories:
Ruff/Flake8 Prefixes
| Prefix | Category | Severity |
|---|
| E | Style (pycodestyle errors) | ERROR |
| W | Style (pycodestyle warnings) | WARNING |
| F | Logic (pyflakes) | ERROR |
| I | Imports (isort) | WARNING |
| N | Naming (pep8-naming) | WARNING |
| UP | Upgrades (pyupgrade) | INFO |
| B | Bugs (flake8-bugbear) | ERROR |
| C4 | Comprehensions | INFO |
| SIM | Simplify | INFO |
ESLint Severity
| Value | Meaning | Our Severity |
|---|
| 2 | error | ERROR |
| 1 | warn | WARNING |
| 0 | off | - |
TypeScript Errors
| Pattern | Category | Severity |
|---|
| TS2304 | Cannot find name | ERROR |
| TS2339 | Property does not exist | ERROR |
| TS7006 | Implicit any | WARNING |
| TS2345 | Argument type mismatch | ERROR |
Integration Report
After running linters, generate summary:
{
"linter_results": {
"python": {
"ruff": {
"config": "pyproject.toml [tool.ruff]",
"errors": 3,
"warnings": 15,
"top_issues": ["E501 (5)", "F401 (3)", "I001 (7)"]
},
"mypy": {
"config": "pyproject.toml [tool.mypy]",
"errors": 2,
"top_issues": ["Missing return type (2)"]
}
},
"typescript": {
"tsc": {
"config": "tsconfig.json",
"errors": 1,
"top_issues": ["TS2339 (1)"]
},
"eslint": {
"config": ".eslintrc.json",
"errors": 0,
"warnings": 8,
"top_issues": ["@typescript-eslint/no-unused-vars (5)"]
}
}
},
"blocking_issues": [
{
"tool": "mypy",
"file": "src/api/handler.py",
"line": 45,
"message": "Incompatible return type"
}
],
"recommendations": [
"Fix 3 type errors before merge",
"Consider enabling stricter ruff rules"
]
}
Red Flags - STOP if you
- Run linters without checking for project configuration first
- Override project linter settings with your own preferences
- Ignore linter errors marked as blocking
- Mix conflicting tools (e.g., ruff + flake8 for same checks)
When these occur: Go back and use project configuration.
Final Checklist
Before completing linter integration, verify: