Claude-skills lint-drupal-module
Lint review completo de un módulo Drupal 11 combinando 4 fuentes en paralelo — PHPStan level 5 + phpstan-drupal, PHPCS Drupal/DrupalPractice, agente drupal-qa (estándares) y agente drupal-security (OWASP). Dos modos — completo (todo el módulo) y diff (solo archivos cambiados vs develop). Genera informe markdown estructurado en la carpeta del IDE con resumen ejecutivo, hallazgos clasificados por severidad, acciones P0/P1/P2 y comandos de verificación. Úsalo siempre que el usuario quiera auditar calidad o seguridad de un módulo Drupal custom, aunque no diga "lint". Triggers — "lint review", "lint del módulo", "auditar módulo Drupal", "revisar módulo custom", "phpstan del módulo", "validar módulo", "qa del módulo", o cuando el usuario pregunta "¿está bien este módulo?", "¿hay errores?", "¿es seguro?". También antes de un release, antes de un PR a develop, o al validar un módulo recién creado.
git clone https://github.com/j4rk0r/claude-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/j4rk0r/claude-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/lint-drupal-module" ~/.claude/skills/j4rk0r-claude-skills-lint-drupal-module && rm -rf "$T"
skills/lint-drupal-module/SKILL.mdLint Review — Módulo Drupal 11
Primera línea del informe generado: "Español confirmado."
Para qué sirve
Combina 4 fuentes de análisis (PHPStan, PHPCS, agente drupal-qa, agente drupal-security) en una sola invocación paralelizada, y consolida los hallazgos en un informe accionable. A mano son ~12 pasos y ~30 minutos; con la skill, lo que tarda la fuente más lenta (~2-5 min en completo, ~30s-1min en diff).
Fast path
1. Identificar módulo (nombre/ruta del usuario, o Glob si no especifica) 2. Detectar modo: completo (default) | diff (si dice "diff", "rápido", "vs develop") 3. Detectar entorno: ddev describe → ejecutar via "ddev exec" 4. Verificar herramientas (vendor/bin/phpstan, vendor/bin/phpcs); instalar si faltan PREGUNTANDO 5. Verificar agentes drupal-qa y drupal-security disponibles (si no, ver "Recovery") 6. Leer references/prompts-agentes.md (necesario para el paso 7) 7. Ejecutar las 4 fuentes EN PARALELO en el mismo mensaje: a) Agent drupal-qa — prompt literal de references/prompts-agentes.md b) Agent drupal-security — prompt literal de references/prompts-agentes.md c) PHPStan level 5 vía Bash (ver "Ejecución en paralelo") d) PHPCS Drupal,DrupalPractice vía Bash 8. Leer references/plantilla-informe.md y consolidar las 4 salidas en un informe markdown 9. Detectar IDE → escribir en <carpeta-IDE>/Lint reviews/<nombre-modo-rama>.md 10. Resumir top bloqueantes en chat; preguntar "arregla todo" / "solo crítico" / "déjalo así"
Si cualquier paso falla, detente y consulta
. No improvises.references/edge-cases.md
Referencias bajo demanda
Tres archivos en
references/, cargados solo cuando los necesitas (progressive disclosure):
| Archivo | Cuándo cargarlo | Por qué |
|---|---|---|
| Antes del paso 7 (invocar agentes) | Contiene los prompts literales para y . Son largos a propósito — sin brief explícito los agentes devuelven reviews superficiales. Cópialos literales, solo sustituye , , . |
| Antes del paso 8 (redactar informe) | Plantilla fija. La consistencia entre informes de distintos módulos es lo que hace que el equipo los lea rápido. |
| Cuando algo falle | Síntoma → causa → solución para los problemas más comunes (DDEV, PHPStan, services.yml, OAuth, modo diff). |
Si ya leíste un archivo en esta sesión, no recargues — el contexto lo conserva.
Modos
Modo completo (default)
Analiza TODOS los archivos del módulo. Más exhaustivo (~2-5 min). Úsalo:
- Antes de un release
- En módulos recién creados
- Auditorías periódicas
- Cuando el usuario no especifica modo
Modo diff
Analiza SOLO los archivos cambiados en la rama actual respecto a
origin/develop. Más rápido (~30s-1min). Úsalo:
- Reviews intermedias durante desarrollo
- Validación pre-push
- Cuando el usuario dice "diff", "rápido", "solo lo que cambié", "vs develop"
Obtener la lista de archivos analizables del módulo (filtrando extensiones que PHPStan/PHPCS pueden procesar):
cd drupal git fetch origin develop --quiet git diff --name-only origin/develop...HEAD \ | grep "^web/modules/custom/<nombre>/" \ | grep -E '\.(php|module|inc|install|profile|theme|yml|twig)$'
El segundo
grep es importante: sin él recibirás .css, .md o imágenes que PHPStan rechaza con "no PHP files found". Para PHPStan específicamente, restringe aún más a \.(php|module|inc|install|profile|theme)$ (sin yml/twig).
Si el resultado está vacío o estás en
develop → ver references/edge-cases.md, sección "Modo diff".
Identificación del módulo
| Lo que dice el usuario | Acción |
|---|---|
Nombre exacto () | |
Ruta () | Validar que existe |
| Sin especificar | . Si hay 1 → usar; si >1 → listar y preguntar; si 0 → parar |
Entorno de ejecución
(silencioso) → si OK, todo dentro de DDEV conddev describe
.ddev exec- Si no hay DDEV → buscar
directo.vendor/bin/phpstan - Si nada → preguntar al usuario qué entorno usa.
Path en contenedor DDEV: verifica con
ddev exec "ls /var/www/html". Suele ser /var/www/html/drupal o /var/www/html según el docroot del .ddev/config.yaml.
Instalación de herramientas
Si
vendor/bin/phpstan no existe:
ddev composer require --dev phpstan/phpstan mglaman/phpstan-drupal phpstan/phpstan-deprecation-rules
Pedir confirmación antes de instalar. PHPCS suele venir con
drupal/coder (verificar con ddev exec "vendor/bin/phpcs -i" | grep -i drupal).
Configuración PHPStan
Crea
phpstan.lint-review.neon en la raíz del proyecto Drupal (no en el módulo):
parameters: level: 5 paths: - web/modules/custom/<nombre> excludePaths: - web/modules/custom/<nombre>/js/vendor/* - web/modules/custom/<nombre>/tests/fixtures/* reportUnmatchedIgnoredErrors: false includes: - vendor/mglaman/phpstan-drupal/extension.neon - vendor/mglaman/phpstan-drupal/rules.neon - vendor/phpstan/phpstan-deprecation-rules/rules.neon
No uses
drupal_root (deprecated en phpstan-drupal 2.x — ver edge-cases).
Ejecución en paralelo
Crítico: lanza las 4 fuentes en el MISMO mensaje (mismo bloque de tool calls). Sin paralelización pierdes el principal valor de la skill.
Modo completo
# PHPStan — usa el bloque paths: del .neon ddev exec "cd /var/www/html/drupal && vendor/bin/phpstan analyse -c phpstan.lint-review.neon --no-progress --error-format=raw" # PHPCS — apunta al directorio del módulo. Restringido a archivos PHP con --extensions. # ⚠️ NUNCA incluir `js` en --extensions: el standard Drupal aplica reglas PHP al JS # y phpcbf puede convertir null/true/false → NULL/TRUE/FALSE, rompiendo el JS en runtime. # Los archivos JS se analizan con ESLint/prettier, no con PHPCS (ver edge-cases.md). ddev exec "cd /var/www/html/drupal && vendor/bin/phpcs --standard=Drupal,DrupalPractice --report=full --extensions=php,module,inc,install,profile,theme --ignore='*/vendor/*,*/js/*' web/modules/custom/<nombre>"
Modo diff
Tras obtener la lista de archivos cambiados (ver sección "Modo diff"), pásalos como argumentos posicionales — sobreescriben el bloque
paths: del .neon:
# PHPStan — solo archivos PHP cambiados ddev exec "cd /var/www/html/drupal && vendor/bin/phpstan analyse -c phpstan.lint-review.neon --no-progress --error-format=raw \ web/modules/custom/<nombre>/src/Foo.php \ web/modules/custom/<nombre>/src/Bar.php" # PHPCS — filtra archivos PHP y YAML (no JS) antes de pasarlos como positional args. # Pasa SOLO archivos cuya extensión esté en --extensions; si pasas un .js posicional, # phpcbf lo procesa igualmente aunque no esté en --extensions, rompiendo el JS. ddev exec "cd /var/www/html/drupal && vendor/bin/phpcs --standard=Drupal,DrupalPractice --report=full --extensions=php,module,inc,install,profile,theme --ignore='*/vendor/*' \ web/modules/custom/<nombre>/src/Foo.php \ web/modules/custom/<nombre>/src/Bar.php \ web/modules/custom/<nombre>/<modulo>.routing.yml"
Nota sobre
: PHPCS a menudo reporta "PHPCBF CAN FIX N OF THESE SNIFF VIOLATIONS AUTOMATICALLY". Si el número es alto (>50% de los ERRORS de PHP, no cuentes los de JS), merece la pena ofrecerle al usuariophpcbfcomo acción rápida tras el informe (ver "Después del informe"). Los JS NUNCA deben ir a phpcbf — ver el edge case "phpcbf rompe JavaScript" enphpcbf.references/edge-cases.md
Agentes (en el mismo mensaje que los dos comandos anteriores)
- Agent
— prompt literal dedrupal-qa
, sección "Prompt parareferences/prompts-agentes.md
".drupal-qa - Agent
— prompt literal de la misma referencia, sección "Prompt paradrupal-security
".drupal-security
En modo diff, pasa la lista de archivos a los agentes con la ruta completa relativa al repo (
web/modules/custom/<nombre>/src/Foo.php), no la subruta del módulo. Los agentes hacen Read sobre esas rutas.
Consolidación del informe
Sigue la plantilla literal de
. La estructura es fija: cabecera, resumen ejecutivo, una sección por fuente (PHPStan/PHPCS/QA/Security), acciones priorizadas P0/P1/P2, cobertura buenas prácticas, comandos de verificación.references/plantilla-informe.md
Reglas críticas (todas detalladas en la plantilla):
- Severidades fijas: 🔴 ERROR/CRÍTICO, 🟠 ALTO, 🟡 MEDIO/WARNING, 🟢 BAJO, ℹ️ INFO.
siempre clickable, ruta relativa al proyecto.archivo:línea- Top 5 bloqueantes con ID corto reusable (
,SEC-ALTO-1
, etc.).QA-ROUTING - P0 deben ser accionables — "añadir
en las 9 rutas POST", no "mejorar la seguridad"._csrf_request_header_token - Veredicto categórico al final del resumen ejecutivo.
Ubicación del informe
Paso 1 — IDE por env var (PRIORITARIO). Ejecuta
printenv CLAUDE_CODE_ENTRYPOINT:
| Carpeta |
|---|---|
| |
| |
| |
otros (, vacío) | continuar al Paso 2 |
Paso 2 — fallback por existencia:
.antigravity/ > .cursor/ > .vscode/ > docs/lint-reviews/.
Nombre:
lint-review-<nombre-modulo>-<modo>-<rama>.md. Sobrescribir si existe (es la versión más reciente). NUNCA caigas a detección por carpeta cuando el env var es claro — eso causa el bug de elegir .cursor/ solo porque sobrevive de un uso anterior del IDE.
Después del informe
- Resumen 3-5 líneas en chat: total hallazgos, top 3 bloqueantes, veredicto.
- Link clickable al informe (ruta relativa).
- Pregunta al usuario qué hacer (no asumas). Las opciones dependen de lo que encontraste:
- "arregla todo" → delegar a
con la lista P0 estructurada (archivo:línea + acción)drupal-backend - "solo crítico" → solo HIGH/CRITICAL de seguridad
- "auto-fix PHPCS" → ofrece esta opción SOLO si PHPCS reportó que phpcbf puede arreglar una cantidad significativa (>50% de los ERRORS de PHP, excluyendo los de JS). Ejecuta:
. OBLIGATORIO el flagddev exec "cd /var/www/html/drupal && vendor/bin/phpcbf --standard=Drupal,DrupalPractice --extensions=php,module,inc,install,profile,theme --ignore='*/vendor/*,*/js/*' web/modules/custom/<nombre>"
para excluir--extensions
— sin él, phpcbf convierte.js
/null
/true
→false
/NULL
/TRUE
en JavaScript y rompe el código en runtime (ver edge-cases.md). Avisa al usuario de que phpcbf modifica archivos in-place y pídele que revise el diff antes de commitear.FALSE - "déjalo así" → cerrar
- "arregla todo" → delegar a
- Recordar: tras fixes en
orouting.yml
→services.yml
obligatorio + tests del módulo + re-ejecutar la skill para verificar.drush cr
NEVER (lecciones aprendidas a las malas)
Estas son las trampas que he visto romper la skill en sesiones reales. Cada una incluye el porqué, no solo la regla.
- NUNCA modifiques archivos del módulo durante la skill. Solo reportas. Por qué: los fixes son una fase posterior con confirmación explícita del usuario; mezclar análisis y fix dificulta auditar qué cambió.
- NUNCA ejecutes las 4 fuentes en mensajes separados. Por qué: la skill tarda ~4x más y pierdes el principal valor de tener herramientas + agentes corriendo en paralelo. Si tu cliente no soporta tool calls paralelas, dilo en voz alta antes de empezar para que el usuario lo sepa.
- NUNCA parafrasees los prompts de los agentes. Cópialos literales desde
. Por qué: sin la checklist explícita los agentes devuelven reviews superficiales (ver el docu del propio prompts-agentes.md).prompts-agentes.md - NUNCA marques el veredicto como "APTO" con hallazgos ALTO/CRÍTICO sin resolver. Por qué: el equipo lee solo el veredicto cuando va con prisa; un APTO falso bloquea la cultura de auditar.
- NUNCA listes
en Controllers como bloqueante. Por qué: es falso positivo conocido de phpstan-drupal con el patrón estándar de Drupal (ver edge-cases).Unsafe usage of new static() - NUNCA elimines aliases FQCN en
sin verificar la Forma A vs Forma B. Por qué: la Forma A (alias real conservices.yml
) es necesaria para el autowiring del Hook OOP. Eliminarla rompe'@servicio'
. Ver edge-cases.drush cr - NUNCA asumas que los tests funcionales pasan solo porque PHPUnit no falla. Por qué: si PHPStan reporta métodos inexistentes (
,getClient()
sobre interfaces) en el directoriopost()
, el test depende del driver actual y romperá silenciosamente en CI cuando cambie. Reportarlo como bloqueante.tests/ - NUNCA escribas el informe en inglés. Código, comandos y nombres de clase en inglés; explicaciones en español. Por qué: el equipo trabaja en español y los informes mezclados son ruido.
- NUNCA ejecutes
sobre archivos JavaScript (ni pasándolos como argumento ni dejando que el standard Drupal los incluya). Por qué: el standard Drupal de PHPCS aplica la reglaphpcbf
a cualquier archivo que pilla, incluyendoDrupal.Semantics.ConstantName
. Phpcbf convierte.js
/null
/true
→false
/NULL
/TRUE
en JavaScript, lo que rompe el código en runtime conFALSE
. Usa siempreReferenceError
y--extensions=php,module,inc,install,profile,theme
al llamar a phpcbf (y a phpcs por consistencia). Los JS se analizan/arreglan con ESLint, no con PHPCS. Ver el edge case completo en--ignore='*/js/*'
.references/edge-cases.md
Checklist de auto-verificación (antes de entregar)
Verifica cada item leyendo el informe que has generado. Si algo falta, vuelve atrás antes de entregárselo al usuario.
- Primera línea del informe es exactamente
Español confirmado. - El informe está en
(verifica con<carpeta-IDE>/Lint reviews/lint-review-<nombre>-<modo>-<rama>.md
)ls - Las 4 fuentes aparecen en el informe (PHPStan, PHPCS, drupal-qa, drupal-security). Si alguna no se ejecutó, debe estar marcada como
, no omitida silenciosamente.❌ no ejecutada — <razón> - Cada hallazgo tiene
con ruta relativa al proyecto (no rutas absolutas del contenedor DDEV).archivo:línea - Sección "P0 bloqueantes" con acciones concretas. Si una P0 dice "mejorar X", reescríbela hasta que diga "añadir/eliminar/cambiar Y en
".archivo:línea - Tabla de resumen ejecutivo con conteos por fuente y total.
- Veredicto explícito al final del resumen (
,APTO
,APTO con correcciones menores
,APTO con correcciones críticas
). Nada de "depende".NO APTO - Si hay hallazgos ALTO/CRÍTICO sin resolver, el veredicto NO es "APTO".
- Sección "Comandos de verificación" al final, con los comandos reales que se usaron (no genéricos).
- El módulo no ha sido modificado:
sobre la carpeta del módulo no muestra cambios atribuibles a esta skill.git status - La última línea de tu mensaje en chat es una pregunta al usuario (
/arregla todo
/solo crítico
), no un asume "ahora arreglo todo".déjalo así
Recovery — qué hacer si algo falla
| Síntoma | Acción |
|---|---|
no existe | Avisar al usuario, no inventar plantillas |
| DDEV no levantado | Pedir al usuario antes de |
| PHPStan/PHPCS no instalados | Pedir confirmación para instalar () |
Agentes o no disponibles | Continuar con las otras fuentes (PHPStan + PHPCS) y pedir al usuario que confirme si quiere review manual del modelo (más lento, menos rigor) |
| Una de las 4 fuentes falla en runtime | Continuar con las otras 3, marcar la fallida en el informe |
| No se puede crear la carpeta del IDE | Crear con ; si falla, usar |
| Modo diff sin cambios en el módulo | Ofrecer cambiar a completo |
Estás en (no hay rama feature) | Abortar con mensaje claro |
| Cliente no soporta tool calls paralelas | Avisar al usuario al inicio: la skill será 4x más lenta, ¿continuar? |
| Síntoma no listado | Consulta . Si tu síntoma no aparece, añádelo después de resolverlo |
Relación con skills hermanas
= revisión de lógica de negocio Codex sobre el diff (los 18 puntos del framework). Esta skill = lint estático (tipos, estándares, seguridad) sobre módulo o diff.codex-diff-develop
= revisión arquitectónica de PR completo, opinión humana. Esta skill = nivel inferior, herramientas automatizadas + agentes especializados.codex-pr-review- Las tres son complementarias. Workflow ideal pre-merge:
(esta skill) → fixes mecánicoslint-drupal-module
→ fixes de lógicacodex-diff-develop
→ revisión final antes de mergearcodex-pr-review