Skip to content
Back to skills

Linter Integration

BSecurity

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.

  • 5 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added May 28, 2026
developmentjavascripttypescriptpythongojavabashnodegitapisecurity

Works with

  • api

Security analysis

B88/100
  • criticalSends environment variables or credentials to an external URL

Pro shows the line behind each finding and how to fix it

Scanned May 28, 2026

npx -y skills add AppVerk/av-marketplace --skill linter-integration --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Linter Integration?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Linter Integration
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/appverk-linter-integration/badge)](https://www.skillsdirectory.com/skills/appverk-linter-integration)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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:**

```bash
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

```bash
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)"

# Count Python files
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

```bash
echo "=== Python Linter Configuration ==="

# Ruff (preferred)
[ -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"

# Mypy
[ -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"

# Flake8
[ -f ".flake8" ] && echo "FOUND: .flake8"
[ -f "setup.cfg" ] && grep -q "\[flake8\]" setup.cfg 2>/dev/null && echo "FOUND: [flake8] in setup.cfg"

# Pylint
[ -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"

# Black
[ -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

```bash
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)"

# Count TS/JS files
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

```bash
echo "=== TypeScript/JavaScript Linter Configuration ==="

# ESLint
[ -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)"

# Prettier
[ -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"

# Check package.json for eslint/prettier config
[ -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)

```bash
# Check if ruff is configured
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:**

```bash
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)

```bash
# Check if mypy is configured
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:**

```bash
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)

```bash
# Only run if configured (don't mix with ruff)
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)

```bash
# Only run if explicitly configured
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)

```bash
# Detect ESLint config type
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:**

```bash
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)

```bash
# Only run if tsconfig.json exists
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:**

```bash
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)

```bash
# Only check if prettier is configured
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:

```json
{
  "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

```bash
# Minimal ruff checks that most projects should pass
ruff check . --select=E,W,F --ignore=E501 --output-format=json 2>/dev/null

# Permissive mypy
mypy . --ignore-missing-imports --no-strict-optional --show-error-codes 2>/dev/null
```

### TypeScript Defaults

```bash
# Basic tsc check only
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

1. **ruff** (if configured) - Comprehensive, fast
2. **mypy** (if configured) - Type checking
3. **flake8** (if configured, no ruff) - Legacy style
4. **pylint** (if configured, no ruff) - Deep analysis

### TypeScript/JavaScript

1. **tsc** (if tsconfig.json) - Type checking
2. **eslint** (if configured) - Style and quality
3. **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:

```json
{
  "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:

- [ ] Detected project type (Python/TypeScript/both)
- [ ] Found linter configuration files
- [ ] Ran linters with project configuration (not defaults)
- [ ] Parsed output into unified format
- [ ] Categorized issues by severity
- [ ] Identified blocking issues (errors)
- [ ] Generated summary with top issues
- [ ] Used fallback only when no config exists

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.