slop-eval

Servidor MCP que envuelve la CLI de slop-eval para la puntuación de genericidad de salidas de UI generadas por IA.

Documentación

slop-eval

CI npm version PyPI version License: Apache 2.0 Node

Inicio rápidoReferencia de CLIAPI de libreríaServidor MCPComparaciónFAQ

Puntúa interfaces de usuario generadas por IA según su carácter genérico con un juez LLM, de modo que un chequeo de CI detecte el mismo problema de "esto parece hecho por IA como todos los demás" que un revisor humano señalaría a simple vista.

Terminal recording: cloning slop-eval, installing dependencies, building the CLI, running --help, then running a first score without ANTHROPIC_API_KEY set, showing the real fail-fast error message that tells you how to set the key

npx slop-eval-cli score --screenshot ./preview.png --json

Sin paso de instalación: npx obtiene y ejecuta directamente el paquete npm publicado. ¿Prefieres Python? pip install slop-eval-cli te da el mismo CLI como un port genuino e independiente de la lógica de puntuación.

Dos distribuciones: npm y Python, ambas activas

slop-eval-cli está disponible tanto en npm como en PyPI (paquete slop_eval). El port de Python es una implementación genuina e independiente, construida y probada (60/60 tests, verificados en esta pasada) contra la misma rúbrica y el mismo prompt de juez de Anthropic que el original en TypeScript. Consulta python/README.md para el uso específico de Python.

Por qué existe esto, y qué no es

Hallmark de Nutlope, una popular skill de diseño con IA con más de 21.000 estrellas, tiene un issue abierto donde un usuario dice sin rodeos: "todo esto parece slop". El mantenedor lo cerró NOT_PLANNED. Por separado, un colaborador abrió un PR contra Hallmark titulado "Add eval-driven quality harness for Hallmark outputs" que lleva abierto y sin fusionar unos dos meses al momento de escribir esto. Ambos son reales y con fecha al momento de escribir esto. Ninguno demuestra que la demanda sea grande, solo que la brecha es real y actualmente no está atendida.

slop-eval no es la primera herramienta en este espacio, y no intenta serlo. Dos herramientas reales y gratuitas ya están cerca:

  • Impeccable (pbakaus/impeccable, 54.000+ estrellas, Apache 2.0) incluye un CLI que señala 59 indicios visuales específicos de IA en interfaces (paletas de gradiente, glassmorphism, bordes con franja lateral, violaciones de contraste WCAG), todos activados por defecto sin llamada a un modelo; un comando impeccable critique aparte añade juicios opcionales basados en LLM. La detección principal sigue siendo rápida porque no necesita un modelo para ninguno de sus chequeos por defecto. Ha crecido mucho más allá de un detector de slop hasta convertirse en una skill completa de lenguaje de diseño para Claude Code, Cursor y Codex, con 23 comandos en total.
  • aislop (MIT, 500+ estrellas) hace el equivalente determinista y basado en reglas para código generado por IA (no UI): más de 50 reglas regex/AST en 8 lenguajes, sin LLM en la ruta de ejecución, posicionado exactamente como una puerta de calidad de CI.

Ninguno hace puntuación holística de UI basada en juicio: "¿esta disposición se siente novedosa?", "¿esta elección de componentes se siente meditada?", el tipo de lectura que una regla fija no puede codificar fácilmente. Esa es la brecha que llena slop-eval, construido para componerse con herramientas como las de Impeccable en lugar de reemplazarlas.

Características

Verificado directamente contra el código de este repositorio:

  • Tres categorías de rúbrica, cada una con evidencia citada obligatoria. src/rubric/v1.json puntúa novedad de la disposición, distintividad de la identidad visual y novedad de los patrones de componentes, 0-10 cada una. Un hallazgo sin una cita específica se trata como un bug, no como una puntuación válida (ver src/sources/RuleSource.ts).
  • Juez LLM mediante llamada forzada a herramienta, que devuelve JSON estructurado. LLMJudgeSource llama a la API de Anthropic con tool_choice bloqueado a un esquema submit_slop_scores: la respuesta llega como JSON estructurado y fiable en lugar de una respuesta de chat que hay que separar con regex.
  • Modo --json para CI y agentes. Cada ejecución puede emitir un objeto { target, rubric, compositeScore, findings[], summary, disclaimer } analizable en stdout, tanto en rutas de éxito como de error, para que un script o agente nunca tenga que ramificar según la forma para encontrar una cadena de error.
  • Contrato real de códigos de salida. 0 éxito (sin umbral, o puntuación igual o superior a --fail-below), 1 éxito pero por debajo del umbral, 2 error de uso o fallo irrecuperable. Verificado directamente contra el CLI compilado y los paquetes reales de npm/PyPI en esta sesión; ver Referencia de CLI.
  • Caché por hash de contenido. src/cache/judge-cache.ts aplica hash a los bytes de entrada y omite la llamada a la API por completo en una ejecución repetida con entrada sin cambios. Es tanto una garantía de corrección como un ahorro de coste: un PR sin cambios no puede hacer oscilar una puerta de CI por la varianza entre ejecuciones del LLM.
  • Interfaz de plugin RuleSource componible. src/sources/RuleSource.ts es el límite que implementa toda fuente de puntuación. Hoy hay una fuente real (LLMJudgeSource) y un stub documentado (ScreenshotDiffSource, reportado honestamente como not_scored hasta que exista un corpus etiquetado real), de modo que un catálogo futuro de reglas o un segundo proveedor de LLM encaja sin tocar el puntuador compuesto.
  • Entrada por captura de pantalla (lectura visual real) o respaldo --url. --screenshot envía la imagen renderizada real al juez. --url es una limitación documentada de v0.1: no incluye un navegador headless, así que obtiene el HTML/texto crudo y el juez razona sobre el marcado y el texto en lugar de la disposición.
  • GitHub Action que lidera con la señal específica, luego la puntuación. action/action.yml publica un comentario en el PR encabezado por el hallazgo señalado más específico, seguido del puntuación compuesta, dando al revisor el razonamiento detrás del número.
  • Rúbrica pública y versionada. Cada puntuación nombra la versión de rúbrica (v1 hoy) que la produjo. Los cambios de rúbrica se publican como un archivo nuevo, nunca como una edición silenciosa de uno existente.
  • Una API de librería real y nativa para agentes junto al CLI. Ambas distribuciones exportan un punto de entrada programático (score_composite y amigos en Python, runScore/scoreComposite en TypeScript) para que un framework de agentes pueda llamar a slop-eval en proceso en lugar de invocar un subproceso. Ver API de librería.

Inicio rápido

Requiere Node.js 18+ (npm) o Python 3.9+ (PyPI), y una ANTHROPIC_API_KEY (trae tu propia clave; consigue una en console.anthropic.com).

El camino más rápido, sin necesidad de clonar ni compilar localmente, es la línea única al principio de este README:

npx slop-eval-cli score --screenshot ./preview.png --json

Verificado en esta sesión contra el paquete npm publicado real, con un PNG real en ./preview.png y sin ANTHROPIC_API_KEY configurado:

$ npx --yes slop-eval-cli@latest score --screenshot ./preview.png --json
{
  "error": "ANTHROPIC_API_KEY environment variable is not set.\nslop-eval calls the Anthropic API to run the LLM judge, and is BYO-key (bring your own key) -- there is no default or shared key baked into this tool. Set your key and try again:\n\n  export ANTHROPIC_API_KEY=\"sk-ant-...\"\n\nGet a key at https://console.anthropic.com/"
}
# exit code 2

Para compilar desde el código fuente en su lugar:

git clone https://github.com/RudrenduPaul/slop-eval.git
cd slop-eval
npm install
npm run build

export ANTHROPIC_API_KEY="sk-ant-..."
./dist/cli.js score --screenshot ./test/fixtures/sample.png

Para consumo de CI o agentes, añade --json. --json siempre emite un objeto JSON válido en stdout, tanto en la ruta de éxito como en la de error, y el chequeo de exclusión mutua --url/--screenshot es un buen ejemplo de una ruta real de error de uso en la que puedes confiar que sea analizable:

Terminal recording: running score with --json to show the structured JSON error object on stdout, then passing both --url and --screenshot together to show the mutually-exclusive usage error, also returned as valid JSON

./dist/cli.js score --screenshot ./test/fixtures/sample.png --json
{
  "target": "./test/fixtures/sample.png",
  "rubric": "v1",
  "compositeScore": 62,
  "findings": [
    {
      "ruleId": "llm-judge.layout-novelty",
      "category": "Layout novelty",
      "score": 4,
      "evidence": "Matches a common hero + 3-card grid + footer CTA pattern.",
      "status": "flag"
    }
  ],
  "summary": { "pass": 1, "flagged": 1, "notScored": 1 },
  "disclaimer": "This score is a heuristic quality signal from an LLM judge, not a certification..."
}

Referencia de CLI

Capturado directamente de ./dist/cli.js score --help en el CLI compilado en esta sesión, palabra por palabra:

Usage: slop-eval score [options]

Score a URL or screenshot for AI-UI genericness against a versioned rubric.

Note on --url mode (v0.1 limitation): this tool does not bundle a headless
browser. If --url is given, the raw HTML/text response is fetched and given to
the judge as a fallback input, instead of a rendered screenshot -- the judge
can reason about markup and copy, but not the actual visual layout. For the
stronger, layout-aware signal, render the page yourself and pass --screenshot.

Options:
  --url <url>          URL to score (fetched as raw HTML/text -- see
                        limitation note above)
  --screenshot <path>  path to a screenshot image to score (preferred over
                        --url)
  --rubric <name>       rubric version to use, reads src/rubric/<name>.json
                        (default: "v1")
  --json                output structured JSON instead of a human-readable
                        report (default: false)
  --fail-below <n>      exit code 1 if the composite score is below this
                        threshold (0-100); no threshold by default
  -h, --help             display help for command

Códigos de salida: 0 éxito (sin umbral, o puntuación igual o superior a --fail-below), 1 éxito pero por debajo del umbral, 2 error de uso o fallo irrecuperable (clave de API faltante, archivo ilegible, rúbrica malformada, --url/--screenshot mutuamente excluyentes).

--url y --screenshot son mutuamente excluyentes; pasar ambos o ninguno es un error de uso (salida 2) en cualquier modo de salida. Ambos verificados directamente contra el CLI compilado en esta sesión.

Terminal recording walking the real usage-error paths: missing --url/--screenshot, both flags passed together, an unreadable file path, and a missing ANTHROPIC_API_KEY, each exiting 2 with a clear message

[!NOTE] --url es una limitación de v0.1, por diseño: no incluye un navegador headless. Obtiene el HTML/texto crudo y se lo pasa al juez como respaldo de texto, razonando sobre el marcado y el texto en lugar de la disposición renderizada. --screenshot es la señal más fuerte; renderiza la página tú mismo (Playwright, Puppeteer, o el paso de captura de vista previa existente de tu CI) y pasa la imagen.

El CLI de Python (script de consola slop-eval, instalado vía pip install slop-eval-cli) expone el mismo conjunto de banderas y el mismo contrato de códigos de salida, confirmado contra su propia salida --help en esta sesión.

API de librería

Ambas distribuciones exportan un punto de entrada programático real y documentado además del CLI. Esta es la interfaz que un framework de agentes o un script de CI llama en proceso en lugar de invocar un subproceso.

Python (slop_eval/__init__.py):

from slop_eval import score_composite, ScoreInput, LLMJudgeSource, ScreenshotDiffSource

sources = [LLMJudgeSource("v1"), ScreenshotDiffSource()]
result = score_composite(sources, ScoreInput(screenshot_path="./preview.png"))
print(result.composite_score, result.findings)

score_composite(sources: List[RuleSource], score_input: ScoreInput) -> CompositeResult ejecuta cada RuleSource en orden de lista, aplana sus hallazgos y devuelve un CompositeResult con composite_score: float (0-100) y findings: List[RuleFinding]. También se exportan: RuleFinding, RuleFindingStatus, RuleSource, Rubric, RubricCategory, load_rubric, build_json_report, render_human_report, print_report, print_error, MissingApiKeyError, RubricLoadError.

TypeScript (src/cli.ts, exportado desde la entrada main/types del paquete): runScore(options: ScoreOptions, buildSources?) => Promise<number> y buildProgram(): Command son los dos puntos de entrada exportados, junto con la interfaz ScoreOptions. scoreComposite (de src/scorer/composite.ts) es la misma función de puntuación compuesta que el CLI llama internamente. Estos existen principalmente para que el conjunto de tests pueda manejar el CLI en proceso; el __init__.py del paquete Python es la superficie de librería "nativa para agentes" más deliberadamente documentada de las dos.

Servidor MCP

slop-eval incluye un servidor del Protocolo de Contexto de Modelos, para que un agente compatible con MCP (Claude Desktop, Claude Code, Cursor, un orquestador) pueda llamar a slop-eval directamente como herramienta en lugar de invocar el CLI y analizar el stdout él mismo.

pip install "slop-eval-cli[mcp]"

Configuración de Claude Desktop:

{
  "mcpServers": {
    "slop-eval": {
      "command": "slop-eval-mcp",
      "env": { "ANTHROPIC_API_KEY": "sk-ant-..." }
    }
  }
}

El servidor expone una herramienta, run(args: list[str]) -> dict, un envoltorio genérico alrededor del CLI: pásale los mismos argv que pasarías en la línea de comandos (menos el slop-eval inicial), y devuelve la salida JSON analizada del CLI, o un dict {"error": ...} estructurado en una salida no cero, un timeout o un fallo del subproceso — la llamada a la herramienta nunca lanza una excepción. Ejemplo:

run(["score", "--screenshot", "./preview.png", "--json"])
# -> {"result": {"target": "./preview.png", "rubric": "v1", "compositeScore": 62.0, "findings": [...], ...}}

Inícialo directamente con slop-eval-mcp (transporte stdio). Requiere Python 3.9+ para el paquete base; el extra mcp en sí necesita mcp>=2.0.0.

GitHub Action

- uses: RudrenduPaul/slop-eval/action@main
  with:
    url: ${{ steps.deploy.outputs.preview_url }}
    fail-below: 50
  env:
    ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

Publica un comentario en el PR encabezado por el hallazgo señalado más específico, seguido de la puntuación compuesta. Requiere permissions: pull-requests: write en el workflow que lo llama. Referencia completa de entradas/salidas en action/README.md.

Comparación honesta

slop-evalImpeccableaislop
ObjetivoUI generada por IAUI generada por IAcódigo generado por IA
Método de detecciónJuez LLM (holístico)Reglas deterministas, 59 chequeos por defecto; un comando critique aparte añade juicios LLM adicionales opcionalesReglas deterministas (50+ chequeos)
Requiere clave de APISí (trae tu propia clave de Anthropic)No, para los 59 chequeos deterministas por defectoNo
VelocidadMás lento por diseño, una llamada real al modelo está en la ruta críticaCasi instantáneo para los chequeos deterministasSub-segundo, sin llamada de red
Fuentes de reglas componiblesSí, interfaz de plugin RuleSourceNo (conjunto de reglas fijo)No (conjunto de reglas fijo)
Estrellas de GitHubNuevo (este repositorio)54.000+500+
LicenciaApache 2.0Apache 2.0MIT
Modelo de puerta de CIGitHub Action, umbral --fail-belowNo posicionado principalmente como producto de CISí, puerta de calidad de CI

¿Quieres chequeos rápidos, deterministas y de costo cero para indicios conocidos de IA en UI? La herramienta de Impeccable es la mejor opción hoy, y por número de estrellas y alcance es el proyecto más consolidado con diferencia. Para un juicio holístico sobre novedad de la disposición y de componentes que un conjunto de reglas fijo no puede codificar fácilmente, eso es lo que añade slop-eval. Nada te impide ejecutar ambos en el mismo trabajo de CI.

Sobre la velocidad: slop-eval es genuinamente más lento que los chequeos principales de Impeccable y que aislop, porque una llamada a un LLM está en la ruta crítica. Números reales de sobrecarga del CLI medidos desde un clon y compilación nuevos, tomados en esta sesión (rutas --help y de error, sin llamada de puntuación):

ComandoTiempo real medido
slop-eval score --help~0.05s
slop-eval score --screenshot <x> (sin clave de API, falla rápido, solo lectura de archivo local)~0.05s
slop-eval score --url <x> (sin clave de API, falla rápido)0.18s-0.91s, varía con la latencia de red, ya que esta ruta obtiene la URL antes de que se ejecute la comprobación de clave

La latencia real de una ejecución puntuada (una llamada real al juez LLM, nueva frente a en caché) requiere un ANTHROPIC_API_KEY en vivo que este entorno no tiene, así que estos dos números son objetivos pendientes de una ejecución medida real: menos de 10 segundos en frío, menos de 1 segundo en un acierto de caché para entrada idéntica. El número de acierto de caché está garantizado por la lógica de caché por hash de contenido en src/cache/judge-cache.ts; el número de ejecución en frío es una estimación. Preferimos etiquetar un objetivo como objetivo que afirmar un número que no podemos reproducir.

Qué significa una puntuación (y qué no)

Una puntuación de slop-eval es una señal heurística de calidad a partir de la lectura de tu interfaz por parte de un LLM frente a una rúbrica establecida. No es una certificación de que algo sea o no generado por IA, y una puntuación limpia no significa que la interfaz sea buena según todas las medidas, solo que esta rúbrica, en esta versión, no la marcó.

La rúbrica es pública y tiene versiones

Cada puntuación se evalúa contra src/rubric/v1.json, un archivo real con versiones que puedes abrir y leer directamente. Léelo, propón cambios o fija una versión específica con --rubric. Una versión de rúbrica nunca se edita en el mismo lugar; un cambio se publica como un archivo nuevo, de modo que una puntuación histórica siempre registra qué rúbrica la produjo.

Hoja de ruta

  • v0.1 (esta versión): puntuación con juez LLM, CLI, GitHub Action, caché por hash de contenido, modo --json y API de biblioteca en ambas distribuciones.
  • v0.2: ScreenshotDiffSource se vuelve real una vez que exista un corpus etiquetado genuino. Un adaptador del catálogo Impeccable, pendiente de verificación de licencia. Un comando explícito rescore --rubric v2 para que un cambio de rúbrica nunca sea silencioso.

Seguridad

ANTHROPIC_API_KEY se lee únicamente del entorno, nunca se registra en logs y nunca se escribe en la caché por hash de contenido; consulta SECURITY.md para la política completa y el proceso de divulgación privada.

Preguntas frecuentes

¿Qué es slop-eval y en qué se diferencia de un linter? Es una CLI, una GitHub Action y una biblioteca que puntúa la genericidad ("slop") de interfaces generadas por IA utilizando un juez LLM de Anthropic frente a una rúbrica con versiones (src/rubric/v1.json), en lugar de un conjunto fijo de comprobaciones deterministas de patrones. Está diseñado para detectar esa lectura de "esto parece cualquier otra app construida con IA" que un revisor humano hace a simple vista, y para ejecutarse junto a un linter determinista en el mismo trabajo de CI o bucle de agente.

¿Necesito una clave de API? Sí. slop-eval funciona con tu propia clave contra la API de Anthropic; no hay una clave compartida ni alojada. Nada se envía a ningún sitio excepto a la API de Anthropic.

¿Cómo lo instalo y qué plataformas soporta? Dos distribuciones independientes, ambas verificadas como instalables y ejecutables en esta sesión. npm: npx slop-eval-cli score ... (sin instalación) o npm install -g slop-eval-cli, que requiere Node.js 18+ (consulta engines en package.json). PyPI: pip install slop-eval-cli, que requiere Python 3.9-3.13 (consulta los clasificadores en python/pyproject.toml). Ninguno de los dos paquetes tiene un binario nativo ni un paso de compilación específico de plataforma, así que ambos se instalan de la misma manera en macOS, Linux y Windows.

¿Cómo se compara slop-eval con Impeccable específicamente? Consulta la tabla de Comparación honesta más arriba para el desglose completo. En resumen: el núcleo de Impeccable son 59 comprobaciones deterministas, todas habilitadas por defecto, que no requieren clave de API y se ejecutan casi al instante, y el proyecto en sí ha crecido hasta convertirse en una habilidad de lenguaje de diseño mucho más amplia (más de 54 000 estrellas, 23 comandos) más allá de la simple detección de slop; un comando separado critique añade juicios adicionales de LLM sobre el conjunto determinista. slop-eval es una única llamada a un juez LLM que requiere una clave de Anthropic propia y es más lento por diseño, porque una llamada real al modelo está en la ruta crítica, a cambio de un juicio holístico de diseño/componentes que una regla fija difícilmente puede codificar. Están diseñados para ejecutarse juntos en el mismo trabajo de CI.

¿Puedo usar un proveedor de modelos diferente (OpenAI, Gemini)? No en v0.1. LLMJudgeSource llama directamente a la API de Anthropic; ANTHROPIC_MODEL solo permite elegir un modelo diferente de Anthropic. Un proveedor conectable encajaría de forma natural en la interfaz RuleSource más adelante, pero aún no está construido, así que no interpretes "fuentes de reglas componibles" como "multiproveedor" hoy.

¿--url renderiza la página como lo haría un navegador, y qué pasa si falla mi ejecución de puntuación? No, no en v0.1. --url obtiene la respuesta HTML/texto cruda y se la pasa al juez como alternativa; renderiza la página tú mismo y pasa --screenshot para una lectura visual real. En cuanto a fallos en general: cada ruta de error, incluida la falta de ANTHROPIC_API_KEY, sale con el código 2 e imprime un mensaje claro (un objeto JSON {"error": ...} en modo --json), de modo que una ejecución fallida siempre debería decirte exactamente qué corregir.

¿Volver a ejecutar slop-eval sobre el mismo PR hará parpadear la comprobación de CI? No. Una entrada idéntica (los mismos bytes de captura de pantalla, o la misma URL más el contenido obtenido) alcanza la caché por hash de contenido en src/cache/judge-cache.ts y nunca vuelve a llamar a la API, por lo que la misma entrada siempre devuelve el mismo resultado en caché.

¿Es screenshot-diff-vs-corpus una comprobación real hoy? No. Es una implementación real de RuleSource en el código, pero v0.1 la incluye como un stub honesto de not_scored porque aún no existe un corpus de comparación etiquetado. Sembrar manualmente un corpus no validado sería una señal menos honesta que informar "no puntuado". La comparación basada en corpus está planificada para v0.2.

¿Puedo usar slop-eval con fines comerciales, incluso en un producto de código cerrado? Sí. Ambas distribuciones son Apache 2.0 (LICENSE, python/LICENSE), una licencia permisiva que permite el uso comercial, la modificación y la redistribución en código cerrado, e incluye una concesión expresa de patentes. Llamar a la CLI, a la Action o a la biblioteca desde un proyecto de código cerrado no te obliga a abrir nada; la licencia y el aviso de copyright solo deben acompañar a las copias redistribuidas del código propio de slop-eval.

Contribuciones

Se aceptan issues y PRs; consulta CONTRIBUTING.md (cubre tanto el paquete npm como el de Python, incluidos los requisitos de cobertura por paquete). Las nuevas implementaciones de RuleSource son la contribución de mayor impacto: la interfaz de plugins existe precisamente para que un nuevo método de detección no requiera tocar el puntuador compuesto.

Licencia

Apache 2.0. Consulta LICENSE.