Greenlight

Por Rene Turcios. Verificaciones previas al vuelo para contribuciones de código abierto: ¿este issue realmente se puede fusionar? Veredictos (GO / RISKY / TAKEN / GATED / STALE), puntuaciones de fricción del repositorio y modo de escaneo. CLI y servidor MCP con herramientas check_issue, scan_repo, repo_friction.

Documentación

Greenlight

Greenlight revisa un issue de GitHub antes de que inviertas horas en él, y te dice en palabras sencillas si es probable que tu pull request sea aceptado.

El problema

Encuentras un issue que parece perfecto. Programas toda la noche. Luego ocurre una de estas cosas:

  • Alguien ya reclamó el trabajo en un comentario. El issue sigue diciendo "sin asignar", pero tres voluntarios escribieron "yo me encargo" hace semanas y nunca lo viste.
  • El repositorio quería que preguntaras primero. Tu pull request se cierra porque los mantenedores exigen que los contribuyentes soliciten asignación u obtengan un aval (una recomendación de alguien que conocen) antes de que cualquiera pueda abrir un PR, y nadie te lo dijo.
  • Tus commits son rechazados por un tecnicismo. El repositorio exige una línea "Signed-off-by" en cada commit (llamada firma DCO, abreviatura de Developer Certificate of Origin) o una entrada en su carpeta de changelog, y te enteras después de hacer push.

Todos estos son rituales de contribución: reglas no escritas que un repositorio espera antes de que un pull request externo cuente. Cada repositorio tiene las suyas, y se esconden en lugares diferentes, desde archivos CONTRIBUTING hasta archivos de reglas internas AGENTS.md (archivos de instrucciones en lenguaje sencillo que dicen a las personas y agentes de codificación cómo trabajar en ese repositorio). Nos topamos con todos estos a mano mientras verificábamos issues reales, así que Greenlight automatiza la comprobación.

Qué hace Greenlight

Un motor, cuatro pasos sencillos:

  1. Comprueba antes de reclamar. Apúntalo a cualquier URL de issue. Lee el issue, sus comentarios, los pull requests vinculados y mencionados, y las reglas del repositorio, luego responde: GO (tuyo para tomar), RISKY (posible, pero conoce esto primero), TAKEN (alguien está en ello), GATED (una regla del repositorio te bloquea), o STALE (abandonado). También detecta trabajo parcialmente reclamado e issues donde la mitad de la solución ya se envió, para que te limites a lo que queda.
  2. Reclama de la manera correcta. Redacta el comentario de reclamo en la forma que las reglas del repositorio realmente quieren: un simple "trabajaré en esto" cuando sea suficiente, una solicitud de asignación cuando el repositorio lo requiera, o una negativa cuando se necesite un aval (ninguna herramienta puede avalar por ti). Nunca publica sin tu consentimiento.
  3. Prepara tu espacio de trabajo con las reglas del propio repositorio. Configura tu fork y rama, luego escribe una lista de verificación que incluye lo que aprendió del propio repositorio: los archivos de reglas internas, el comando de verificación que insisten en usar, si el repositorio quiere una entrada de changelog, y cómo están estilizados sus commits.
  4. Abre el PR solo cuando lo básico pase. Comprueba que la rama realmente está por delante del repositorio, y en repositorios que requieren firma DCO verifica que cada commit lleve la línea Signed-off-by antes de abrir el pull request.

Úsalo cuando

  • Encontraste un issue que te gusta y estás a punto de invertir tiempo real en él.
  • Quieres saber si un issue realmente sigue siendo tuyo para terminar, o si alguien reclamó silenciosamente parte de él en un comentario.
  • Las reglas de un repositorio no están claras y quieres verlas resumidas antes de empezar.
  • Reclamaste algo hace un tiempo y quieres saber si ese reclamo todavía cuenta.
  • Estás eligiendo entre varios repositorios o issues y quieres el más ganable primero.

Qué hace, técnicamente

Un motor, cuatro superficies:

  1. Veredictos de disponibilidad para un issue: GO, RISKY, TAKEN, GATED, STALE. Señales: asignados, PRs vinculados abiertos/cerrados/ fusionados (línea de tiempo + búsqueda + referencias de comentarios), heurísticas de comentarios de reclamo incluyendo reclamos con alcance (frases como "por favor asigna", "trabajando en esto", "tomando la solicitud de respaldo restante"), detección parcialmente abordada (PRs fusionados que referencian el issue, comentarios de mantenedores como "mitad abordado ... dejando esto abierto"), antigüedad del issue y última actividad.
  2. Puntuaciones de fricción del repositorio (0-100, 100 = más fácil): puertas de contribución analizadas de variantes de CONTRIBUTING más archivos de reglas internas (AGENTS.md, CLAUDE.md), con cada puerta registrando de qué archivo proviene su evidencia (asignación-primero, aval, CLA, DCO, discusión-primero, comentario-primero, solo-colaboradores), más señales de resultado cuando se pueden calcular.
  3. Modo escaneo: clasifica los issues abiertos de buen-primer-issue / se-busca-ayuda de un repositorio por veredicto para que un contribuyente (o agente) elija uno ganable primero. Cae a issues abiertos recientes sin asignar cuando un repositorio no tiene issues iniciales etiquetados.
  4. Automatización de contribución: comandos claim, prep y pr (más herramientas MCP correspondientes) que ejecutan el pipeline después del veredicto. Todas las escrituras son de prueba por defecto y necesitan un token más una bandera explícita de ejecución.

Un corpus de validación de diez casos reales de la campaña (test/fixtures/cases/, ejecutado por test/cases.test.ts) fija cada regla de veredicto a algo que realmente ocurrió: un issue tomado, una mención débil de PR, puertas de reclamo-primero, puertas de asignación y aval, un reclamo con alcance, un issue medio enviado, un GO limpio y un reclamo obsoleto.

Instalación

npm install
npm run build

Establece GITHUB_TOKEN (un token de acceso personal clásico, sin alcances necesarios para repositorios públicos) para elevar el límite de tasa de la API de GitHub de 60 a 5000 solicitudes por hora. Greenlight almacena en caché las respuestas de la API bajo ~/.cache/greenlight.

CLI

# Verdict for one issue
npx greenlight check https://github.com/batrapulkit/squidbrake/issues/74

# [GO] batrapulkit/squidbrake#74
#   Taint: tell the approver when an agent edits its own setup right after reading outside content
#   - open, unassigned, no linked PRs, no claim signals, no blocking gates

# Rank a repo's starter issues, GO first (falls back to recent open
# unassigned issues when the repo does not use those labels; --no-fallback to opt out)
npx greenlight scan PrefectHQ/fastmcp

# Friction score for a repo
npx greenlight friction triggerdotdev/trigger.dev

# JSON output for scripting
npx greenlight check <issue-url> --json

Ejemplos reales de nuestra verificación:

  • batrapulkit/squidbrake#74 puntúa GO: 0 comentarios, etiquetado se-busca-ayuda, sin reclamos, sin puertas.
  • shadcn-labs/pdfcn#58 puntúa RISKY (bandera reclamado): un voluntario solicitó asignación el mismo día que lo verificamos.
  • langchain-ai/langchain#41185 puntúa TAKEN (carrera de reclamos): 3 reclamantes fuertes mientras aún "sin asignar".
  • PrefectHQ/fastmcp#5718 puntúa GATED: FastMCP requiere asignación o una etiqueta "prs welcome" antes de un PR.
  • triggerdotdev/trigger.dev#5016 puntúa GATED: los PRs de autores sin aval se cierran automáticamente, una solicitud de aval va primero.

Cómo funciona la puntuación

El motor de veredictos es determinista (sin LLM) y comprueba, en orden:

  1. Issue cerrado: TAKEN (nunca aterrizable).
  2. Cualquier asignado: TAKEN.
  3. Un PR vinculado abierto que cierra el issue: TAKEN. Un PR que meramente menciona el número del issue (como pdfcn PR #91, que cierra #70 pero lista issues hermanos en su cuerpo) solo añade una bandera weak-pr-mention y degrada un veredicto por lo demás-GO a RISKY.
  4. Dos o más reclamantes fuertes: TAKEN (carrera de reclamos).
  5. Un reclamo fuerte fresco de todo el issue (menos de 45 días): RISKY con la bandera claimed. Un reclamo fresco con alcance a parte del issue ("tomando la solicitud de respaldo restante"): RISKY con banderas claimed + partial-claim y una razón nombrando al reclamante y el alcance, nunca TAKEN.
  6. Un reclamo fuerte de más de 45 días sin PR de cierre: RISKY con la bandera stale_claim. El reclamante probablemente se fue, pero nadie lo sabe con certeza. Los reclamos obsoletos con alcance reciben el mismo tratamiento.
  7. Una puerta dura (asignación, aval, solo-colaboradores) sin nadie asignado: GATED.
  8. Sin actividad durante 180+ días: STALE.
  9. Una puerta suave de reclamo-primero (el repositorio pide a los contribuyentes comentar antes de empezar, como pdfcn): nunca GATED; limita un veredicto por lo demás-GO a RISKY con una nota, la misma forma de degradación que una mención débil de PR.
  10. De lo contrario: GO.
  11. Un PR abierto referenciado en un comentario de no-autor cuyo título/cuerpo menciona el número del issue: degrada un veredicto por lo demás-GO a RISKY con la bandera comment-mentioned-pr ("puede que ya cubra parte de este issue"). Ninguno puede producir TAKEN; solo los PRs de cierre hacen eso.
  12. Parcialmente abordado: PRs fusionados que referencian el número del issue (mencionado en comentario o vinculado), o comentarios de mantenedores que señalan que parte del trabajo ya se envió ("Mitad abordado por #905, dejando esto abierto para la mitad B", "Enviado en v3.1.0" junto a la referencia del issue). Un GO simple oculta el trabajo de alcance que esto necesita, así que se añade la bandera partially-addressed, un veredicto por lo demás-GO se limita a RISKY con una razón como "parte de este issue ya se envió (PR #905, fusionado); limita tu trabajo a lo que queda". Nunca TAKEN.

La detección de reclamos escanea comentarios en busca de frases explícitas de reclamo, señales en progreso ("solución lista", "PR en camino", "abrí un PR"), y ofertas suaves ("feliz de arreglar"). Los autores de bots se ignoran, al igual que los reportadores de issues a menos que anuncien una solución lista. Los reclamos con alcance ("tomando la solicitud de respaldo restante", "reclamando esta mitad") se registran como parciales: un reclamo parcial fresco degrada un veredicto por lo demás-GO a RISKY con una razón nombrando al reclamante y el alcance, nunca TAKEN. Las referencias de PR (#NNN) en comentarios de no-autores se verifican contra la API de PR: un PR abierto referenciado que menciona el issue degrada GO a RISKY con la bandera comment-mentioned-pr, y uno fusionado alimenta la regla 12 anterior.

La puntuación de fricción comienza en 100 y resta pesos de puertas (asignación -25, aval -35, solo-colaboradores -50, discusión-primero -10, reclamo-primero -5, CLA/DCO -5 cada una), ajusta por tasa de fusión de PRs externos y tiempos de revisión/respuesta cuando se pueden calcular, y añade hasta +10 por buenos-primeros-issues abiertos. Las señales desconocidas permanecen nulas y se omiten, nunca se adivinan. Ver src/friction.ts para la fórmula exacta.

Servidor MCP

El mismo motor se expone sobre stdio para agentes de codificación (Claude, Cursor, Cline). La cuña: los agentes desperdician la mayoría de los tokens arreglando issues ya tomados. Haz que el agente verifique el issue antes de escribir código.

{
  "mcpServers": {
    "greenlight": {
      "command": "node",
      "args": ["/path/to/greenlight/dist/index.js"],
      "env": { "GITHUB_TOKEN": "your-token" }
    }
  }
}

Herramientas:

  • check_issue - veredicto para una URL de issue
  • scan_repo - clasifica los issues abiertos de un repositorio, GO primero (issues iniciales etiquetados, cayendo a issues abiertos recientes sin asignar)
  • repo_friction - puntuación de fricción para un repositorio
  • claim_issue - comentario de reclamo con veredicto (prueba a menos que execute: true)
  • prep_issue - verificación de fork y rama más una lista de verificación local PREP.md con las convenciones aprendidas del repositorio (prueba a menos que execute: true)
  • open_pr - apertura de PR consciente de DCO desde una rama de fork (prueba a menos que execute: true)

Ejecútalo localmente: npm run dev (la entrada MCP es src/index.ts; el CLI es src/cli.ts).

Automatización

Greenlight 0.2.0 automatiza el pipeline de contribución que su autor ejecutó a mano para cuatro PRs reales (shadcn-labs/pdfcn #92-#95): veredicto, comentario de reclamo, fork y rama, y apertura del PR, con conciencia de DCO en todo momento.

# 1. Claim the issue: verdict first, comment shaped by the repo's gates
greenlight claim https://github.com/shadcn-labs/pdfcn/issues/65

# 2. Prepare: fork/branch check (learning the repo's branch convention) plus a PREP.md checklist
greenlight prep https://github.com/shadcn-labs/pdfcn/issues/65 --dir /tmp/prep65

# 3. Open the PR from your fork branch (verifies DCO sign-off on DCO repos)
greenlight pr https://github.com/shadcn-labs/pdfcn/issues/65 --branch feat/quarterly-report-block

Valores predeterminados de seguridad, y esto es una característica:

  • Prueba por defecto. Los tres comandos imprimen exactamente lo que publicarían o crearían y salen. Nada se publica o crea sin --yes (CLI) o execute: true (MCP).
  • Las escrituras necesitan un token. Las operaciones de lectura funcionan sin token alguno. Las operaciones de escritura requieren GITHUB_TOKEN (o GH_TOKEN); sin uno imprimen un error claro nombrando la variable de entorno y salen con código no-cero.
  • Con veredicto. claim rechaza veredictos TAKEN o STALE a menos que --force, y rechaza repositorios con puerta de aval directamente (un aval no puede automatizarse). Los repositorios con puerta de asignación reciben una solicitud de asignación en lugar de un comentario de intención; los repositorios de reclamo-primero (comentar antes de empezar) reciben el comentario de intención estándar, que satisface el ritual.
  • Nombres de rama conscientes del repositorio. prep lee las ramas principales de PRs cerrados recientes y sigue una convención dominante (la feat/<slug>-block de pdfcn) mientras aún muestra el valor predeterminado feat/<slug>-<number>.
  • Consciente de DCO. En repositorios DCO, pr verifica que cada commit en la rama lleve una línea Signed-off-by: y rechaza, listando los commits sin firmar, cuando falta uno.
  • Preparación consciente del repositorio. prep también aprende los rituales de contribución del repositorio para la lista de verificación PREP.md: qué archivos de reglas internas existen, el comando de verificación que insisten en usar (como pnpm verify), si el repositorio ensambla su changelog desde un directorio .changes/, qué scripts de package.json raíz existen, y si los commits recientes siguen Conventional Commits. Las reglas vinculantes viven cada vez más en AGENTS.md en lugar de CONTRIBUTING, y la preparación lee esas también.

El índice de fricción

data/friction-index.json es un conjunto de datos verificado y creciente de repositorios puntuados. Comienza con el ecosistema MCP/AI que verificamos a mano el 2026-10-13 (FastMCP, trigger.dev, langchain, deepagents, openclaw, squidbrake, reticle, pdfcn, chatflow-agent, y los tres repositorios de SDK MCP). Regenera con npm run index. Las entradas etiquetadas como hand-verified 2026-10-13 provienen de la lectura manual de las políticas reales de los repositorios y sus rastreadores de incidencias. Las entradas etiquetadas como live se extrajeron de archivos de reglas internas en vivo (variantes de CONTRIBUTING, AGENTS.md, CLAUDE.md). Cada compuerta registra de qué archivo proviene su evidencia. Los campos de resultado calculados (tasas de fusión, tiempos de revisión) permanecen como null hasta que podamos calcularlos honestamente, nunca fabricados.

Desarrollo

npm test    # tsx --test, includes fixture tests that reproduce our real verdicts
npm run build

Hoja de ruta (Más adelante)

  • Extensión de navegador que puntúa incidencias en línea en github.com
  • Panel alojado del índice de fricción, actualizado periódicamente
  • Acción de GitHub para mantenedores que etiqueta automáticamente los comentarios de reclamación
  • Detección de correcciones estacionadas y avisos automáticos: escanear bifurcaciones en busca de ramas que referencien incidencias abiertas y avisar cuando se cumpla la compuerta

Licencia

MIT. Ver LICENSE.