GitHub Triage
Triagea las issues y pull requests abiertas de un repositorio. Opcionalmente, primero limpia los PRs listos (fusiona PRs de bots que pasan y PRs aprobados por mantenedores, revisa aquellos nunca revisados), luego cierra issues que ya están resueltas (con un comentario citando el PR o commit que las resolvió), asegura que las issues y los PRs pendientes que las corrigen se referencien mutuamente, y asigna una estimación de prioridad y tamaño solo local a cada issue que aún está pendiente.
Cuándo usarlo
- Cuando el usuario ejecuta
/github-triagepara limpiar o revisar las issues abiertas y pull requests de un repositorio. - Cuando un backlog de issues se ha desviado: trabajo resuelto que quedó abierto, correcciones que se implementaron sin cerrar sus issues, o PRs en curso que nunca enlazaron su issue.
- Cuando se han acumulado PRs listos (actualizaciones de dependencias que pasan, PRs aprobados y en verde) o PRs que están sin revisar.
Cuándo NO usarlo
- No invocar automáticamente. Esta skill realiza escrituras irreversibles en GitHub (fusionar PRs, cerrar issues, publicar comentarios) y solo se ejecuta bajo invocación explícita.
- No usar para aplicar etiquetas de prioridad/esfuerzo en GitHub. La prioridad y el tamaño se presentan solo localmente y nunca se publican (ver Reglas de Seguridad).
- No usar como sustituto de la decisión final de fusión de un humano: cada fusión se propone para su aprobación explícita, nunca se realiza de forma autónoma.
Principios fundamentales
- Las escrituras están controladas. Calcular el triaje completo primero, presentar cada escritura propuesta (incluidas las fusiones) para revisión, y no ejecutar nada hasta que el usuario lo apruebe.
- Evidencia antes de cerrar. Nunca cerrar una issue sin una razón concreta y citada (un PR fusionado o un commit en la rama predeterminada). Cuando la evidencia es débil o ambigua, dejar la issue pendiente y marcarla para revisión.
- Prioridad y tamaño se quedan localmente. Son una ayuda interna de planificación para el usuario, nunca se escriben en GitHub.
Flujo de trabajo
Fase 0: Seleccionar el repositorio objetivo
gh auth status # confirmar que gh está autenticado
git rev-parse --is-inside-work-tree # ¿el directorio actual es un repositorio git?
git remote -v # enumerar remotos
Determinar el conjunto de repositorios distintos alojados en GitHub entre los remotos.
Un remoto está alojado en GitHub cuando la URL del host es github.com, en cualquiera de estas formas:
https://github.com/OWNER/REPO(.git)[email protected]:OWNER/REPO(.git)ssh://[email protected]/OWNER/REPO(.git)
Normalizar cada uno a OWNER/REPO y eliminar duplicados (una configuración de fork puede tener origin
y upstream apuntando a diferentes repositorios de GitHub; múltiples remotos apuntando al
mismo OWNER/REPO cuentan como uno).
Regla de selección:
| Situación | Acción |
|---|---|
| Exactamente un repositorio de GitHub distinto | Usarlo como predeterminado — no preguntar. |
| No es un repositorio git, o cero remotos de GitHub | Preguntar al usuario por el OWNER/REPO a triagear. |
| Más de un repositorio de GitHub distinto | Usar AskUserQuestion para que el usuario elija qué OWNER/REPO. |
Las instancias de GitHub Enterprise no se pueden detectar automáticamente de manera confiable. Si el usuario trabaja en una instancia de GHE, pedir
OWNER/REPOy que configurenGH_HOST/ usen el host configurado degh. Confirmar el repositorio resuelto al usuario antes de continuar.
Almacenar el resultado como REPO="OWNER/REPO" y pasar -R "$REPO" a cada llamada gh.
Validarlo con ^[A-Za-z0-9._-]+/[A-Za-z0-9._-]+$ antes de usar, para que una URL remota malformada o
hostil nunca fluya a un comando.
Fase 1: Recopilar issues y contexto
# Issues abiertas (gh issue list excluye PRs por defecto)
gh issue list -R "$REPO" --state open --limit 1000 \
--json number,title,body,labels,assignees,comments,reactionGroups,createdAt,updatedAt,url
# PRs abiertos — candidatos para "corrección pendiente" (fase de issues) y triaje de PRs (Fase 2)
gh pr list -R "$REPO" --state open --limit 1000 \
--json number,title,body,author,isDraft,reviewDecision,latestReviews,\
mergeable,mergeStateStatus,statusCheckRollup,labels,createdAt,headRefName,url,closingIssuesReferences
# PRs fusionados recientemente — candidatos para "ya resuelto"
gh pr list -R "$REPO" --state merged --limit 300 \
--json number,title,body,mergedAt,url,closingIssuesReferences
closingIssuesReferences lista las issues que un PR está vinculado a cerrar — poblado por cualquiera
de las palabras clave de cierre de GitHub (close/closes/closed, fix/fixes/fixed,
resolve/resolves/resolved) en el cuerpo del PR, o por un enlace manual de la interfaz de usuario. Es la
señal más fuerte disponible. Para issues que no cubre, también buscar mensajes de commit
en la rama predeterminada. Resolver la rama predeterminada de manera autoritativa desde el repositorio seleccionado
(no desde origin/HEAD local, que puede no estar establecido o apuntar al remoto incorrecto):
default_branch=$(gh repo view "$REPO" --json defaultBranchRef --jq .defaultBranchRef.name)
# Anclar el número de issue para que #12 no coincida con #120, #123, …
git log --oneline "origin/$default_branch" \
| grep -iE "(close|fix|resolve)[sd]? +#<N>([^0-9]|$)"
Fase 2: Triagear pull requests abiertos (opcional)
Manejar los PRs antes que las issues: fusionar PRs listos aquí significa que la verificación de "ya resuelto" en la fase de issues verá el trabajo que esas fusiones acaban de implementar.
Si no hay PRs abiertos, saltar esta fase. De lo contrario, resumir los PRs abiertos y preguntar al usuario si desea manejar los PRs ahora (AskUserQuestion: manejar PRs / saltar a issues). Si saltan, ir directamente a la clasificación de issues.
Clasificar cada PR abierto según su estado de revisión, CI y fusión. Las formas de los campos a continuación son
lo que gh pr ... --json realmente devuelve — confiar en ellas, no en la intuición:
- Listo para fusionar =
mergeable == "MERGEABLE"ymergeStateStatus == "CLEAN"y CI no está bloqueando (abajo).CLEANes el veredicto del lado del servidor de GitHub "sin conflictos, no atrasado, no es borrador, checks requeridos en verde" — cualquier otromergeStateStatus(BEHIND,UNSTABLE,BLOCKED,DIRTY,DRAFT, …) no está listo. Tratarmergeable == "UNKNOWN"(GitHub recalcula la mergeabilidad perezosamente, especialmente justo después de otra fusión) como no listo — volver a consultar brevemente o saltar; nunca fusionar basándose en ello. - CI no bloquea — escanear
statusCheckRollup(clave en__typename) y rechazar el PR solo ante un problema real: un fallo grave (unCheckRuncuyoconclusionesFAILURE/CANCELLED/TIMED_OUT/ACTION_REQUIRED/STARTUP_FAILURE/STALE, o unStatusContextcuyostateesFAILURE/ERROR), o algo aún en ejecución (unCheckRunstatusdeQUEUED/IN_PROGRESS/WAITING/PENDING, o unStatusContextstatedePENDING/EXPECTED— esperar, no fusionar aún).SUCCESS,NEUTRALySKIPPEDestán bien y no deben bloquear (por ejemplo, una ejecución de CodeQL que reportaNEUTRALen una actualización de dependencia — un PR verde de Dependabot esCLEANcon un check de CodeQLNEUTRAL). Un rollup vacío es sin CI — un estado distinto, nunca tratado como listo.mergeStateStatus == "CLEAN"ya refleja el estado de checks requeridos; usar el rollup para detectar checks no requeridos fallando o pendientes. - Bot/automatizado =
author.is_bot == true. Cotejar la lista blanca de auto-fusión contraauthor.logindespués de normalizar la representación degh— eliminar unapp/inicial y un[bot]final (gh devuelve Dependabot comoapp/dependaboten algunas versiones ydependabot[bot]en otras; normalizar ambos adependabot). En lista blanca por defecto:dependabot,renovate, más cualquier otro que nombre el usuario. Un PR que pasa de un bot no incluido en la lista blanca se reporta, nunca se ofrece para fusionar. - Aprobado por mantenedor =
latestReviewstiene una entrada constate == "APPROVED"cuyoauthorAssociationesOWNER/MEMBER/COLLABORATORy cuyoauthor.loginno es el autor del PR. No usarreviewDecision == "APPROVED"solo: está impulsado por protección de rama y esnullen repositorios sin regla de revisión requerida, por lo que tanto sobreconfía (no puede confirmar acceso de escritura) como pasa por alto aprobaciones genuinas. - Nunca revisado =
latestReviewsno tiene ninguna entradaAPPROVED/CHANGES_REQUESTEDde nadie que no sea el autor del PR (un comentario de bot de "revisión deshabilitada" de un fork no es una revisión).
| Categoría | Condición | Acción ofrecida |
|---|---|---|
| PR de bot fusionable | bot en lista blanca + listo + no borrador | Ofrecer fusión incremental, en orden |
| Aprobado y listo | aprobado por mantenedor + listo + no borrador | Solicitar fusión |
| Nunca revisado | no bot + solo el autor ha revisado (o sin revisiones) + no borrador | Ofrecer generar un subagente de revisión |
| Necesita trabajo | borrador, fallo grave de CI, CI pendiente, conflictos, atrasado, cambios solicitados, o un PR de bot que no está listo | Solo reportar — no se ofrece acción |
("listo" ya subsume CI-no-bloquea. Los subagentes de revisión son para PRs escritos por humanos — una actualización de dependencia de un bot que no está lista se reporta como Necesita trabajo, no se revisa.)
Presentar los PRs categorizados y ofrecer las acciones aplicables mediante AskUserQuestion.
Fusión incremental, en orden (PRs de bot y PRs aprobados y listos): confirmar el conjunto de fusión y el método de fusión primero (fusionar es irreversible), luego fusionar uno a la vez, los más antiguos primero. Elegir un método que el repositorio permita y fallar cerrado si no lo hace:
gh repo view "$REPO" --json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed # repositorio posicional, no -R
Para cada PR en orden, verificar de nuevo inmediatamente antes de fusionar (el estado cambia después de cada
fusión — un PR fusionado puede dejar al siguiente BEHIND, en conflicto, o recalculando), fusionar
de forma síncrona, luego confirmar que se implementó antes de avanzar:
gh pr view <N> -R "$REPO" --json isDraft,reviewDecision,mergeable,mergeStateStatus,statusCheckRollup
# proceder solo si aún está listo: no borrador, mergeable == MERGEABLE, mergeStateStatus == CLEAN, CI no bloquea
gh pr merge <N> -R "$REPO" --<método> # nunca --auto, nunca --admin
gh pr view <N> -R "$REPO" --json state # esperar "MERGED" antes de pasar al siguiente PR
Detenerse y reportar si un PR ya no está listo (incluyendo mergeable == "UNKNOWN"), si la
fusión no se implementó, o si algún check requerido no está en verde — nunca forzar, --admin,
--auto, o saltar un check. Para PRs de bot, mostrar la dependencia y el salto de versión (por ejemplo,
saltos mayores) en la compuerta para que el usuario pueda decidir con contexto.
Subagentes de revisión (PRs nunca revisados): cuando el usuario opta, generar un Agente
por PR — todos en un solo mensaje de asistente para que se ejecuten en paralelo. Cada subagente
revisa el diff de un PR y devuelve una revisión estructurada; escribir cada una en
github-pr-<número>-review.md en el directorio de trabajo (sobrescribiendo cualquier archivo anterior
para ese PR). Las revisiones son solo lectura y nunca se publican en GitHub. Ver
references/reviewing-prs.md para el prompt del subagente,
rúbrica de revisión y formato de archivo.
Después de cualquier fusión, volver a obtener la lista de PRs fusionados (la consulta --state merged de la Fase 1)
para que la fase de issues pueda detectar issues que esas fusiones resolvieron.
Fase 3: Clasificar cada issue abierta
Ordenar cada issue abierta en exactamente un cubo.
Cubo A — Ya resuelta (el trabajo se implementó, la issue quedó abierta). Requiere evidencia concreta; preferir corroboración sobre una sola señal débil:
- Un PR fusionado lista la issue en
closingIssuesReferences, o su título/cuerpo referencia#Njunto con una palabra clave de cierre. (La más fuerte.) - Un commit en la rama predeterminada referencia
#Ncon una palabra clave de cierre. - El comportamiento que la issue solicita existe demostrablemente en el código actual — verificar leyendo el código relevante con Grep/Read, no asumir. Una implementación diferente o parcial no resuelve la issue.
→ Escritura propuesta: cerrar la issue con un comentario que nombre el PR/commit que la resuelve.
gh issue close <N> -R "$REPO" \
-c "Resuelta por #<PR> (<razón breve>). Cerrando ya que el cambio ahora está en $default_branch."
Cubo B — PR pendiente la resolvería (un PR abierto aborda la issue).
Detectar en cualquier dirección: el closingIssuesReferences del PR abierto incluye la
issue; el cuerpo/comentarios de la issue enlazan el PR; o un PR abierto claramente corrige lo
mismo que describe la issue. El objetivo es que la issue y el PR se referencien
mutuamente — llenar solo lagunas genuinas, y preferir escrituras no destructivas:
- Sin referencia en ninguna dirección → publicar un comentario de puntero (no destructivo) en el
lado que carece de ella. Una mención de
#<PR>/#<N>crea una referencia cruzada que GitHub refleja en la línea de tiempo del otro.gh issue comment <N> -R "$REPO" -b "Hay una corrección en curso en #<PR>." - Ya enlazada en al menos una dirección → registrar "ya enlazada — sin acción".
No editar el cuerpo del PR a menos que el usuario quiera explícitamente que el PR cierre automáticamente la issue al fusionarse. Un comentario establece una referencia pero no desencadena cierre automático — solo una palabra clave de cierre en el cuerpo del PR o en un mensaje de commit lo hace. Cuando el usuario opta, nunca sobrescribir la descripción: volver a obtener el cuerpo inmediatamente antes de editar y pasarlo a través de stdin, para que el texto del PR no confiable nunca transite una cadena interpolada por el shell:
body=$(gh pr view <PR> -R "$REPO" --json body --jq .body)
printf '%s\n\nCloses #%s\n' "$body" "<N>" | gh pr edit <PR> -R "$REPO" --body-file -
No duplicar enlaces que ya existen.
Cubo C — Pendiente (sin resolución, sin PR pendiente). Asignar, solo localmente, una prioridad y una estimación de tamaño de cambio (siguiente sección).
Fase 4: Puntuar issues pendientes (SOLO LOCAL)
Prioridad — Critical / High / Medium / Low. Sopesar:
- Impacto / gravedad — seguridad, pérdida de datos, caídas o errores de corrección tienen prioridad sobre
mejoras; docs/cosméticos son los más bajos. Las etiquetas existentes (
security,bug,crash,regression) son señales fuertes. - Alcance — cuántos usuarios/flujos de trabajo están afectados.
- Señal — reacciones (👍), informes duplicados, antigüedad con actividad continua.
- Urgencia — bloquea un lanzamiento, tiene una fecha límite, o tiene una regresión activa.
Tamaño del cambio — el proxy de esfuerzo, expresado como un cubo de camiseta size/* a partir de
las líneas totales estimadas (adiciones + eliminaciones, ignorando archivos generados/vendidos),
usando la nomenclatura de tamaños de Kubernetes/Prow:
size/XS— ≤ 10 líneassize/S— 11‑30 líneassize/M— 31‑100 líneassize/L— 101‑500 líneassize/XL— 501‑1000 líneassize/XXL— >1000 líneas
Si la issue carece de suficiente detalle técnico para estimar, indicar esto en lugar de adivinar.
Fase 5: Reporte de resumen
Después de que el usuario apruebe cualquier escritura propuesta (cierres, fusiones, comentarios, adiciones de palabras clave de cierre):
- Ejecutar cada escritura aprobada.
- Presentar un resumen tabular: issues cerradas, PRs fusionados, issues enlazadas, issues pendientes (con su prioridad/tamaño asignados y un breve tema de una línea).
- Resaltar cualquier issue que quedó abierta pero que podría estar resuelta — aquellas donde la evidencia era débil — pidiendo a un humano que las verifique manualmente.
Reglas de seguridad
- Todas las escrituras son puestas en escena antes de ejecutarlas. Nunca cerrar, fusionar, o comentar sin aprobación explícita.
- Las etiquetas de prioridad y tamaño son solo locales. No publicar, ni siquiera como comentarios o referencias, en GitHub — permanecen en el hilo de la sesión.
- Las revisiones de subagentes son solo locales. Las revisiones se escriben en archivos
.mden el directorio de trabajo; nunca se publican en GitHub. - Los PRs de bots requieren verificación de lista blanca. Una actualización de dependencia que pasa de un bot no incluido se reporta, nunca se fusiona. Los PRs de bots en lista blanca se fusionan uno a la vez con re-verificación entre cada uno.
- Sin fusión administrativa. Nunca pasar
--adminagh pr merge, ni usar--auto(que omite checks requeridos). Siempre fusionar de forma síncrona y confirmar.
Referencias
- references/reviewing-prs.md — Prompt del subagente y rúbrica de revisión.