ddtcorex/maestro-skills/magento2-linter

Trust tier 3
  • community
  • ext:[{"type":"hook","description":"Pre/post lifecycle hooks"}]
Source check pending

Checking that the SKILL.md file is still in the repository.

This skill should be used when the user asks to "check coding standards", "run phpcs", "lint my code", "run PHPStan analysis", "run static analysis on this module", "find security issues in code", "check code complexity", "find code smells", "detect unused code", "audit custom code", or "verify code quality before commit". Runs automated code quality checks for Magento 2 projects — PHPCS (Magento2 standard), PHPStan, and PHPMD. DEPENDENT on magento2-dev-core for understanding the coding standards it validates.

Install

npx vskill@latest install ddtcorex/maestro-skills/magento2-linter

Semi-extensibleMentions customization, but needs skill-specific knowledge. Read the extensible skills standard

SKILL.md

Magento 2 Linter

This skill runs automated code quality checks to verify Magento 2 coding standards compliance.

Related Skills

REQUIRED BACKGROUND: Load magento2-dev-core first — this skill validates code against the coding/security standards that skill defines, and its patterns are what you fix findings with.

Part of the QA trio with magento2-security-scan (deeper vulnerability scanning) and magento2-performance-audit (runtime/infrastructure checks) — run all three before a release. Fix findings using the patterns in magento2-dev-core (or the relevant frontend/backend/Hyvä skill).

Govard-Native Lint Audit Is the Real Gate

govard audit run --checks lint is Govard's persistent, native lint gate for Magento 2 projects and modules, and running it for real is a required step before telling a user a branch is "verified" or "ready to push" — not an optional nice-to-have. Govard v1.64.0 implements two audit checks: lint (PHPCS + PHPStan + the pub/media PHP guard) and profiler (captures the Magento stock profiler CSV through the project's own web server — see "The lint run's pub/media PHP guard" below for the guard, and step 2 for the profiler command); any other --checks value is rejected. A bare local vendor/bin/phpcs/ phpstan invocation (see "Scoping" below) is a fast pre-check to catch obvious problems early — it is not proof the branch is clean, because it can diverge from the native toolchain run in either direction (see "Local Bare-Tool Runs Can Diverge from the Native Toolchain" below). Never substitute a bare-tool "0 errors" for a real govard audit run, and never present local-only results as if they were the real gate having passed.

Work through the audit in this order:

  1. Resolve target. --mode (auto, project, module_in_project, or standalone) picks

what gets analyzed; auto (the default) classifies the current directory itself — no flag needed for the common case:

  • project: current directory is a Magento project root (bin/magento plus a Magento

Composer requirement) with no enclosing module — the whole project is analyzed.

  • module_in_project: current directory is a module (etc/module.xml, or a Composer package

of type magento2-module) inside a Magento project — only the module is analyzed, with the whole project mounted read only so its autoloader resolves correctly.

  • standalone: current directory is a module with no Magento project anywhere above it —

only the module is analyzed, with its dependencies installed into a scratch worktree. --mode project / --mode module_in_project / --mode standalone all force that classification and fail outright when the directory doesn't support it — useful to catch a misresolved auto guess rather than silently linting the wrong scope.

  1. Run it: govard audit run --checks lint (lint is already the default --checks value,

so plain govard audit run is equivalent). Add ,profiler plus a --url to also capture a page-profile artifact — govard audit run --checks lint,profiler --url https://<domain>/ — and note that a bare govard audit rerun --session <id> repeats the latest run's check selection, profiler URL included. In --format text (the default) Docker logs stream live (phase start/end, cache state, glint: php X.Y analyzed) and findings are colorized + uncapped on a TTY (piped stays plain + capped at 10); in --format json stdout is a single machine-clean object, diagnostics go to stderr -- keep json for agents, text for humans. A FAILED/CANCELLED run still prints the full summary before exiting non-zero.

  1. For standalone iteration only, optionally narrow the PHP matrix with --php 8.1,8.4.

--php on project/module_in_project targets is only accepted when it repeats the project's own active stack.php_version — it can't widen or narrow those targets' single-version run.

  1. Treat these outcomes distinctly — none of them means "clean code" except the last:
  • unsupported_php — the requested PHP version isn't valid for this target (see "PHP

versions" below); no container ran.

  • infra_error — a pull/build/Docker/dependency-resolution/report-schema failure. The run

never produced a real lint result; never present this as "no findings." For a standalone target, a dependency-resolution failure while pulling a private Git/Composer dependency is a common cause — see "Standalone Composer Packages Need Isolated Verification" below for the --allow-lint-ssh-agent remedy.

  • cancelled — the run was stopped before completing; not a pass.
  • lint findings — PHPCS/PHPStan findings on an otherwise-completed run. This is the actual

signal to act on. Only a completed run with zero findings is a clean result.

  1. If the team has configured an external provider (audit.lint.external_providers in the

project config), run it explicitly as an additional policy gate, not a substitute for the native run: govard audit run --lint-provider team-ci — team-ci here is just an example name; --lint-provider takes the provider's name directly, and that name and its definition come entirely from the project's own config (there's no bundled vendor-specific provider, and no separate flag for it). An external provider is never inferred and never a fallback for the native backend: an unknown --lint-provider name is an error, and a native failure stays a native failure. A standalone target has no project configuration to source audit.lint.external_providers from, so govard is the only provider available there.

  1. Never describe a host-project approximation as standalone matrix proof. Running bare

vendor/bin/phpcs/phpstan against a module nested inside a large host project is a fast local pre-check, not evidence of what an isolated standalone matrix run would find — the host project's own vendor//generated/ can hide or fabricate results in either direction (see the isolation notes under "Standalone Composer Packages" below). If the module qualifies as standalone, govard audit run is the authoritative check; fall back to a manual isolated install only when Govard itself isn't available.

No diff or file-list scoping. The native audit's finest granularity is a whole module (module_in_project) or the whole project (project) — there is no file-list or changed-lines argument, so a file list resolved for a PR/MR review does not flow into govard audit run. govard audit diff --base <ref> (equivalently run --scope diff --base <ref>) records that base ref in the session manifest, but lint still analyzes the full target today — result evidence reports effective_scope: project regardless of the base ref given. Don't expect either form to narrow analysis to just the diff; treat every native run's findings as covering the whole module/project and split diff-introduced from pre-existing findings yourself afterward (see magento2-code-review's scope-modes reference for that split).

The lint run's pub/media PHP guard (M2-LINT-MEDIA)

Since Govard v1.64.0, every govard audit run --checks lint also flags each PHP file found under pub/media as a M2-LINT-MEDIA / PHP file in pub/media finding — no extra flag, no opt-in. Treat these findings as a security incident, never as style noise: PHP files under pub/media are a classic webshell drop zone (often disguised as images with a GIF89a header followed by PHP code) and, depending on server configuration, may be directly executable via their public URL.

First response when they appear:

  1. Extract the full file list from the report (tool: M2-LINT-MEDIA entries).
  2. Quarantine the files (move them out of the webroot; do not just delete evidence).
  3. Check web-server access logs for requests to those paths to determine whether they were

ever executed.

  1. Investigate the upload vector that planted them (custom options, quote uploads, third-party

modules), then rerun the audit and expect zero media findings before calling the project clean.

PHP versions

The lint image provides 7.4, 8.0, 8.1, 8.2, 8.3, 8.4, and 8.5.

  • `project` and `module_in_project` analyze exactly one version — the project's active

stack.php_version — and accept any of the seven. The run is refused outright when a running application container reports a different PHP than the configuration does.

  • `standalone` accepts 8.1 through 8.5 and defaults to all five; 7.4 and 8.0 are

not available there and are rejected (unsupported_php) before any image is pulled, built, or run.

PHP 8.0 is real, supported analysis input for project/module_in_project targets — not a stub — but the toolchain has two independent version splits, not one:

  • PHPStan / `bitexpert/phpstan-magento`: 8.0 alone pins an older major (PHPStan ^1.12,

bitexpert/phpstan-magento ^0.19) than the other six versions (PHPStan ^2.2, bitexpert/phpstan-magento ^0.43).

  • PHPCS / `magento/magento-coding-standard`: 7.4 and 8.0 both pin ^4.0, while 8.1

through 8.5 pin ^40.0 — a different split that groups 8.0 with 7.4 instead of against it.

Because the two axes disagree on where the line falls, no PHP version's findings are safely comparable to any other's across both tools at once. Treat every PHP version's run as its own baseline: don't compare rule IDs or findings across different PHP versions at all, for either tool.

Caching, rerun identity, and read-only source
  • Cache: reusable analyzer state lives under ~/.govard/cache/audit/lint/<target-id>/, keyed

per toolchain identity (image, runner, PHP matrix, analyzer policy). Changing composer.json/composer.lock/phpcs.xml/phpstan.neon (or their .dist variants) discards the cached analyzer state but keeps the Composer download cache warm — a lock change doesn't force a full dependency re-download. --no-lint-result-cache forces a fresh analyzer pass for one run (reported back as cache state bypassed) without discarding the Composer download cache. audit cleanup --older-than <duration> prunes old sessions, never this cache.

  • Rerun identity: every run is recorded under an explicit <session-id>/runs/<run-id>/.

govard audit rerun, status, and result all require the exact --session value returned by the original run (result also needs --run) — Govard never guesses "the latest session," so a rerun is always traceable to the run it's re-checking, not a fresh unrelated one.

  • Read-only source: the source tree is always mounted read only into the lint container — a

lint run cannot modify the code it analyzes. Auto-fix, if wanted, is still the separate bare phpcbf route (see "Auto-fix Capabilities" below).

Running the Linter

Lint: run govard audit run --checks lint --format json on the host and read the JSON (phpcs, phpstan, pub/media guard); do not hand-parse text output or exit codes.
Otherwise: govard audit run --checks lint --format json (machine-clean, one JSON on stdout, diagnostics on stderr; text mode capped at 10 and colorized — not for agents).

Prerequisites

Ensure the project has required tools:

bash
# PHPCS (Magento Coding Standard)
composer require --dev magento/magento-coding-standard --no-interaction
# PHPStan (Magento extension)
composer require --dev bitexpert/phpstan-magento --no-interaction

If `phpcs --standard=Magento2` errors with "Referenced sniff ... does not exist" or "the Magento2 coding standard is not installed", don't immediately conclude the dependency is missing from the project. Check first whether it's already resolved in composer.lock but just not registered with phpcs:

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 95 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
4
Repository forks
2
7-day trend score
8

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Extension points

  • hookPre/post lifecycle hooks

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/ddtcorex/maestro-skills/magento2-linter/badge)](https://verified-skill.com/skills/ddtcorex/maestro-skills/magento2-linter)

Something wrong with this skill or its page? Tell us.