When to Use This Skill
| Use this skill when... | Use something else instead when... |
|---|---|
| Auto-detecting and running the correct linter for a polyglot repo | Detecting structural anti-patterns linters miss → code-antipatterns |
Running ruff/eslint/clippy/gofmt with optional --fix and --format |
Reviewing broader code quality and architecture → code-review |
| Driving a one-shot lint pass before commit | Scanning specifically for swallowed errors → code-hidden-failures --track errors |
| Looking up autofix commands or common fix patterns per language | (use this skill — autofix reference is now here) |
Context
- Package files: !
find . -maxdepth 1 \( -name "package.json" -o -name "pyproject.toml" -o -name "setup.py" -o -name "requirements.txt" -o -name "Cargo.toml" -o -name "go.mod" \) -type f - Pre-commit config: !
find . -maxdepth 1 -name ".pre-commit-config.yaml" -type f
Parameters
Parse $ARGUMENTS and bind three values before running anything. These are
supplied by the caller; nothing substitutes them for you.
Token in $ARGUMENTS |
Binds | Default when absent |
|---|---|---|
| First non-flag token | PATH — the file or directory to lint |
. (repo root) |
--fix |
FIX — apply autofixes |
off; check only |
--format |
FORMAT — run formatters in write mode |
off; formatters run in --check mode |
Every command in Step 2 is written with a literal PATH placeholder. Substitute
the bound value when you run it — e.g. with $ARGUMENTS empty, ruff check PATH
is run as ruff check ..
Execution
Run this lint pass:
Step 0: One-shot path (preferred when no PATH is given)
When the caller passed no path (or passed .), the bundled detector already does
detection, tool discovery, and fixing in a single call:
bash "${CLAUDE_PLUGIN_ROOT}/skills/code-lint/scripts/detect-and-fix.sh"
bash "${CLAUDE_PLUGIN_ROOT}/skills/code-lint/scripts/detect-and-fix.sh" --check-only
Pass --check-only unless FIX is set. It detects biome, eslint, prettier,
ruff, black, clippy, rustfmt, gofmt, golangci-lint, and shellcheck, reports which
were found, and shows modified files. Report its output and stop.
Continue to Step 1 when the caller scoped the run to a specific PATH, or when
the detector reports no linters found.
Step 1: Detect the project language
Read the Package files line from Context above (or ls the target directory)
and map each marker file to a language. The signals are the marker files — do
not guess from file extensions or the repo name.
| Marker file present in the repo root | Language |
|---|---|
pyproject.toml, setup.py, requirements.txt |
Python |
package.json |
JavaScript / TypeScript |
Cargo.toml |
Rust |
go.mod |
Go |
- Exactly one match → run that row of Step 2.
- Several matches (polyglot repo) → run each matching row, then aggregate the results into one summary. Do not pick one arbitrarily.
- No match → skip to Step 3.
Step 2: Run the row for each detected language
Run the Lint and Format commands for every detected language. Swap in the
--fix / --format variants only when the caller set those flags.
| Language | Lint (always) | Lint with --fix |
Format check (default) | Format with --format |
|---|---|---|---|---|
| Python | uv run ruff check PATH --output-format=concise |
uv run ruff check PATH --output-format=concise --fix |
uv run ruff format --check PATH |
uv run ruff format PATH |
| JavaScript / TypeScript | npx eslint PATH |
npx eslint PATH --fix |
npx prettier --check PATH |
npx prettier --write PATH |
| Rust | cargo clippy --message-format=short -- -D warnings |
cargo clippy --fix --allow-dirty |
cargo fmt -- --check |
cargo fmt |
| Go | go vet ./... |
(no autofix — fix by hand) | gofmt -l PATH |
gofmt -w PATH |
Then run each detected language's extra checks:
| Language | Extra checks |
|---|---|
| Python | uv run ty check PATH --hide-progress, uv run bandit -q -r PATH |
| JavaScript / TypeScript | npx tsc --noEmit |
| Rust | cargo check |
| Go | staticcheck ./... (only if installed) |
When the repo defines its own lint script (npm run lint, a just lint recipe),
prefer it over the raw command above — it encodes the project's own flags.
Step 3: Fallback when no language was detected
In order, stopping at the first that applies:
Makefilepresent →make lintpackage.jsonwith alintscript →npm run lint- Otherwise report that no linters were found, and suggest
/deps:install --devand/configure:linting.
Step 4: Pre-commit integration
If the Pre-commit config line in Context is non-empty:
| Caller flags | Command |
|---|---|
| default | pre-commit run --all-files |
--fix |
pre-commit run --all-files --show-diff-on-failure |
Autofix Command Reference
| Language | Linter | Autofix Command |
|---|---|---|
| TypeScript/JS | biome | npx @biomejs/biome check --write . |
| TypeScript/JS | biome format | npx @biomejs/biome format --write . |
| Python | ruff | ruff check --fix . |
| Python | ruff format | ruff format . |
| Rust | clippy | cargo clippy --fix --allow-dirty |
| Rust | rustfmt | cargo fmt |
| Go | gofmt | gofmt -w . |
| Go | go mod | go mod tidy |
| Shell | shellcheck | No autofix (manual only) |
Common Fix Patterns
JavaScript/TypeScript (Biome): unused imports, prefer-const (let x = 5 → const x = 5).
Python (Ruff): import sorting (I001), unused imports (F401), long lines auto-wrapped.
Rust (Clippy): redundant clone, match → if let for single-arm patterns.
Shell (ShellCheck — manual fixes): quote variables ($var → "$var"), use $() instead of backticks.
When to Escalate from Autofix
Stop autofix and use a different approach when:
- Fix requires understanding business logic
- Multiple files need coordinated changes
- Warning indicates a potential bug (not just style)
- Security-related linter rule
- Type error requires interface/API changes
Post-lint Actions
After linting:
- Summary of issues found/fixed
- If unfixable issues exist, suggest
/code:refactorcommand - If all clean, ready for
/git:smartcommit