Collect MegaLinter lint errors for the current repository. Use when the user wants to know
Scanned 9/2/2026
Install to Claude Code
npx -y skills add ulises-jeremias/agent-toolkit --skill megalinter-check --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Megalinter Check?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ulises-jeremias-megalinter-check-agent-toolkit)More formats (shields.io, HTML) on the badges page.
---
name: megalinter-check
description: Collect MegaLinter lint errors for the current repository. Use when the user wants to know
if the code passes linting, why the MegaLinter CI job fails, or before/after fixing lint errors. Two
modes - watch a CI job (GitHub Actions, GitLab CI, Azure Pipelines, Bitbucket Pipelines) and parse its
logs, or run MegaLinter locally with Docker (full run or fast parallel standalone linter runs).
licence: MegaLinter by OX Security, Copyright 2026 - https://megalinter.io/
argument-hint: '[mode: watch|local] [PR/job URL or linter keys]'
allowed-tools: Bash, Read, Grep, Glob, Write, Agent, AskUserQuestion
user-invocable: true
origin:
type: upstream
upstream:
repository: oxsecurity/megalinter
path: skills/megalinter-check
ref: v10.0.0
commit: 15e5b45552097e318c93de385779ce3b1084052c
license: AGPL-3.0
version: v10.0.0
role: check
trust:
tier: reviewed
reviewed_at: '2026-08-14'
reviewed_by: ulises-jeremias
reviewed_provenance: sha256:97d6d7aae49cce61bf82c11ab768c0b471ff19a45aa6eb550905a8d6424f2c62
maintenance:
status: active
last_activity: '2026-08-08'
last_checked: '2026-08-14'
distribution:
mode: vendored
redistribution_allowed: true
attribution_file: LICENSE
security:
scripts: false
shell: true
network: true
requires_secrets: false
mcp: []
hooks: []
dangerous_permissions: []
cve_policy: not-applicable
updates:
strategy: pull-request
cadence: weekly
---
# MegaLinter check
Collect the current MegaLinter errors and produce a compact error list that the `megalinter-fix` skill can consume.
## Choose a mode
- **Watch mode** — a MegaLinter CI job exists for the current branch/PR (running or completed): parse its logs. No Docker needed.
- **Local mode** — no CI job available, or the user wants a pre-push check: run MegaLinter with Docker via `npx mega-linter-runner`.
- **Targeted re-check** (local, after fixes): re-run only the previously-failing linters in parallel standalone images.
## Watch mode
1. Detect the provider from `git remote get-url origin` and the CI config files present.
2. Load the matching provider guide from this skill's directory — **only the one you need**:
- GitHub Actions → `providers/github.md`
- GitLab CI → `providers/gitlab.md`
- Azure Pipelines → `providers/azure.md`
- Bitbucket Pipelines → `providers/bitbucket.md`
3. Follow the guide: locate the MegaLinter job, wait for completion if running, fetch the logs of the MegaLinter step.
4. Parse the MegaLinter summary (the `❌`/`✅` table) and per-linter error sections.
## Local mode
Before the first local run, make sure the user is aware that running MegaLinter locally is **resource-consuming**: it needs a reasonably powerful machine (CPU, RAM, free disk space) and a good internet connection — MegaLinter is Docker-based and the first run downloads a large image (can be several GB depending on the flavor). Because of this, **watch mode (CI does the work) is usually the recommended option**. When both modes are possible (a MegaLinter CI job exists for the repository, or a branch/PR could be pushed to trigger one) and the user did not explicitly choose, **ask them** which mode to use (use your platform's structured question mechanism if it has one, with watch mode first/recommended) instead of starting a local run.
### Engine preflight (before every local run)
Requires a container engine (docker or podman) that actually **responds** - an installed binary proves nothing: with a stopped backend (e.g. Docker Desktop's Windows service), the `docker` CLI can hang indefinitely instead of failing fast. Probe with a bound before starting any run:
```bash
timeout 10 docker info --format '{{.ServerVersion}}' # exit 124 = installed but not answering
timeout 10 podman info --format '{{.Version.Version}}'
```
- Chosen engine answers → proceed (pass `--container-engine podman` when using podman).
- Chosen engine errors or times out → probe the other engine the same way; if it answers, use it instead.
- Neither answers → do **not** start a run (it would hang the same way). Tell the user what you found ("Docker Desktop appears installed but is not responding - is it running?") and **ask** whether you should install or start an engine — then (and only then) load `container-engine.md` from this skill's directory for the setup instructions (prefer podman: free of charge even in enterprise contexts). If the user declines, fall back to watch mode.
Flavor and version are resolved automatically from `MEGALINTER_FLAVOR` / `MEGALINTER_VERSION` in `.mega-linter.yml` — do not pass `--flavor` or `--release` yourself.
```bash
npx mega-linter-runner # docker
npx mega-linter-runner --container-engine podman # podman
```
Tip: for repeated local runs (e.g. fix → re-check loops), install the runner once with `npm install -g mega-linter-runner` and call `mega-linter-runner` directly — it avoids the `npx` package resolution overhead on every invocation.
- Add `--fix` if `.mega-linter.yml` defines `APPLY_FIXES` other than `none` (the repository has opted into auto-fixing).
- **Cap parallelism on local machines**: MegaLinter defaults to one parallel linter process per CPU core, which can saturate a dev machine where Docker shares resources with everything else. When running on a local computer — not in CI (no `CI`/`GITHUB_ACTIONS`/`GITLAB_CI`-style environment variable set) — add `-e PARALLEL_PROCESS_NUMBER=4` to full runs (use the machine's core count instead if it has fewer than 4). Skip this when the repository configuration already sets `PARALLEL_PROCESS_NUMBER`; never write it into `.mega-linter.yml`, where it would also slow down CI.
- **Always add `-e JSON_REPORTER=true`** to full runs: the JSON report is **not generated by default** (`JSON_REPORTER` defaults to `false`), and this env variable overrides the repository configuration, guaranteeing `megalinter-reports/mega-linter-report.json`.
- Then read `megalinter-reports/mega-linter-report.json` and `megalinter-reports/linters_logs/ERROR-*.log` instead of parsing the console output, and extract the console tips from the persisted log file (see "Console tips" below) - do not re-read the whole console stream for them.
- **A missing report file never means "wait"**: the runner is synchronous — once the command has exited, no report file will ever appear afterwards. Do not poll, sleep, or re-run for it. If the expected files are absent (the repository may set `REPORT_OUTPUT_FOLDER` to a custom folder or `none`, `TEXT_REPORTER: false`, or a different `TEXT_REPORTER_SUB_FOLDER`), fall back in order: check `REPORT_OUTPUT_FOLDER` in `.mega-linter.yml` and glob `**/mega-linter-report.json` / `**/linters_logs/` under it, then parse the console output — the `❌`/`✅` summary table and per-linter error sections are always printed there.
### Run with a time bound - never wait unbounded
Local runs can hang for environmental reasons (engine backend down, Windows bind-mount stalls - see below), so give **every** local invocation (prerun, full run, targeted re-check) an explicit bound:
1. Prefer the runner's own flag when available: check `npx mega-linter-runner --help` for `--timeout`, and pass `--timeout <seconds>` if listed - on expiry it also stops and removes the container. Do not assume it exists (older runner versions / pinned `MEGALINTER_VERSION`).
2. Fallback: wrap with the shell coreutils command - `timeout <seconds> npx mega-linter-runner ...`. This kills the wrapper only, **not** the container: after it fires, do the orphan cleanup below.
3. Launch in the background with output going to a log file and check it every 1-2 minutes; never sit in a single indefinite blocking call.
Suggested bounds: **full run 30 min**, **prerun or targeted single-linter run 10 min** - a full flavor run on a mid-size repo normally takes minutes, not hours. First run on a machine: pre-pull the image separately (`docker pull <image>` / `podman pull <image>`) so the multi-GB download does not eat the bound.
### Stalled or just slow? Diagnose, don't keep waiting
No new log output for ~5 minutes is a possible stall, not proof of work. Diagnose actively (`<engine>` = docker or podman):
1. `<engine> ps -a` - is the container still there, and how long has it been "Up"?
2. `<engine> logs --tail 30 <name>` - what was the last line? A phase boundary that never advances (e.g. "...collects the files to analyse", "Processing linters on [N] parallel cores") shows where it is stuck.
3. `<engine> exec <name> ps aux` - what is running inside, and how much cumulative CPU TIME do those processes show vs the container's wall-clock uptime? **Seconds of CPU over hours of uptime = I/O stall** (filesystem or network), not real computation: stop waiting, kill the run, clean up (below), and report the diagnosis instead of polling further. On Windows the usual culprit is the WSL2 bind-mount penalty - see "Windows bind-mount slowness" in `performance.md`.
### Orphaned containers after a forced kill
Killing the wrapping command (shell `timeout` expiring, Ctrl-C, killing the npx process) does **not** reliably stop the container - especially on Windows, where signal forwarding is unreliable. Only the runner's own `--timeout` guarantees cleanup. After any forced interrupt:
1. `<engine> ps -a` - look for a still-"Up" container running a megalinter image.
2. `<engine> stop <name>`, then `<engine> rm <name>`, for each match.
### First local run: prerun analysis
Before the **first** local full run on a repository (fresh `megalinter-setup`, or no `megalinter-reports/mega-linter-report.json` from a previous run), start with a prerun analysis so the real run is not wasted on a badly tuned configuration. Also use it later whenever the user asks to tune MegaLinter performances.
Prerun requires MegaLinter v10 or beta: check `MEGALINTER_VERSION` in `.mega-linter.yml` and skip this step (go straight to the full run) when the pinned version is older.
1. Run MegaLinter in analysis-only mode (fast: no linter is run, and the image pull is reused by the real run right after):
```bash
npx mega-linter-runner --prerun
```
2. Read `megalinter-reports/prerun-report.json`. Each entry of `suggestions` describes a `.mega-linter.yml` change: `variable`, `operation` (`append` to a list / `set`), `values`, `safe`, `reason`, `details`.
3. Review the suggestions with the user:
- `safe: true` suggestions (directories containing only gitignored files) do not change the linting scope - present them grouped, recommend applying them.
- `safe: false` suggestions (well-known generated folder names still containing lintable files, flavor change) need an explicit user decision - ask about each one, with the file counts from `details`. A flavor change also requires updating the image reference in the CI workflow files.
4. Apply the accepted changes to `.mega-linter.yml`, then continue with the normal full run.
If the report file is missing after the run (image older than v10 that ignored `MEGALINTER_PRERUN` and linted everything), treat the output as a normal full run instead of re-running.
## Targeted re-check (after fixes)
Re-run only what previously failed, in parallel (max 4 concurrent containers):
```bash
npx mega-linter-runner --linter PYTHON_RUFF -e JSON_REPORTER=true src/a.py src/b.py &
npx mega-linter-runner --linter MARKDOWN_MARKDOWNLINT -e JSON_REPORTER=true README.md &
wait
```
(`-e JSON_REPORTER=true` for the same reason as in full runs: the JSON report is not generated by default.)
**Version rule (all skills)**: runner and Docker image versions always follow `MEGALINTER_VERSION` from `.mega-linter.yml` — invoke `npx mega-linter-runner@beta` when it is `beta`, plain `npx mega-linter-runner` otherwise, and never pass `--release` yourself. Caveat until MegaLinter v10: standalone `megalinter-only-*` images are only multi-arch on the `beta` tag, so if a standalone run fails with a platform error while `MEGALINTER_VERSION` is not `beta`, inform the user and propose either pinning `MEGALINTER_VERSION: beta` or falling back to a full-image re-check.
- Pass the fixed files as arguments for file-scoped linters; omit the file list for project-scoped linters (e.g. `REPOSITORY_*`, `COPYPASTE_JSCPD`).
- Each run writes its reports to `megalinter-reports/<linter_key_lower>/` — no conflict between parallel runs.
- Local-mode guardrails apply here too: engine preflight first, bound each run (~10 min per standalone linter), and check for orphaned containers after any forced kill.
## Output contract
Whatever the mode, summarize the result in this shape (this is what `megalinter-fix` consumes):
```json
{
"status": "success|errors|failure",
"linters": [
{
"key": "PYTHON_RUFF",
"errors": 12,
"fixable": true,
"blocking": true,
"files": ["src/a.py"],
"samples": ["src/a.py:10:5 E501 line too long"]
}
]
}
```
Distinguish **blocking** linters (❌, fail the job) from non-blocking ones (⚠️, `DISABLE_ERRORS: true`). A `failure` status means the job/run itself broke (container engine, network, configuration): include a `"failure_reason"` field with a short cause excerpt instead of linter errors. In watch mode, a `"job_url"` field may be added for reference. Add the optional `"tips"` field when console tips were found (see below).
## Console tips (even when the run is green)
MegaLinter's console output is full of actionable advice for agents that never reaches the JSON report: performance warnings (">300 .gitignored files... consider ADDITIONAL_EXCLUDED_DIRECTORIES", "Heavy folders detected"), flavor suggestions, `[Activation]` notices explaining why a linter did not run, deprecation and removed-linter notices, timeout kills, forwarded-exclusion traces. Always collect them:
- **Local mode**: the full console stream is persisted in the report folder - glob `megalinter-reports/mega*linter.log` (file name from `LOG_FILE`, default `mega-linter.log`; `LOG_FILE: none` disables it, then use the captured console output). Grep it instead of re-reading the console: `grep -E "⚠|WARNING|\[Activation\]|Heavy folders|To improve|[Ff]lavor|deprecat|Timed out|[Cc]onsider" <log-file>`.
- **Watch mode**: the CI job log IS the console output - apply the same grep to the downloaded log.
Curate the matches into at most 10 one-line entries: keep lines that suggest a configuration, performance, or upgrade action; drop per-file lint errors, banners, and progress lines; dedupe repeats. Add them to the output as:
```json
"tips": [
"More than 300 .gitignored files detected (612): consider adding directories to ADDITIONAL_EXCLUDED_DIRECTORIES (heaviest: site, coverage)",
"[Activation] MARKDOWN_RUMDL inactive: set MARKDOWN_DEFAULT_STYLE=rumdl to activate"
]
```
Relay the tips to the user after the error summary, and feed the configuration-related ones into the `megalinter-setup` refinement step or the prerun suggestions review when one is in progress. Like performance suggestions, never apply a tip without the user's agreement.
## Performance check (even when the run is green)
MegaLinter's summary table includes an `Elapsed time` column per linter — always collect it. Add a `"slow_linters"` field to the output when any linter took **more than 30 seconds** or more than **25% of the total lint time**:
```json
"slow_linters": [{"key": "REPOSITORY_GRYPE", "elapsed_seconds": 116.6}]
```
When `slow_linters` is non-empty, load `performance.md` from this skill's directory and report the matching improvement suggestions to the user — explicitly noting that nothing is failing and these are pure speed wins. Never apply a performance change (exclusions, caching, disabling a linter) without the user's agreement.
## Optimization: sub-agents (Claude Code and compatible agents)
If sub-agents are available and the agent definitions are installed (see `megalinter-setup`):
- Watch mode → spawn `megalinter-watcher` with the branch/PR reference; it polls, fetches and parses, and returns the output contract.
- Local mode → spawn `megalinter-runner` with the command to run; it executes and digests the reports.
- Targeted re-check → spawn one `megalinter-runner` per standalone linter run, in parallel (max 4).
This keeps multi-megabyte CI logs and linter output out of your context. Without sub-agents, do everything inline.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!