gatefile

Por Rene Turcios. Extrae las puertas de contribución ocultas de un repositorio (asignación primero, reclamo primero, DCO, aval) de su documentación a un contribution-gates.json legible por máquina. CLI y servidor MCP con herramientas extract_gates, validate_gates, gates_badge.

Documentación

gatefile

Compuertas de contribución ocultas, extraídas en un archivo que las máquinas pueden leer.

Cada repositorio oculta sus reglas reales para contribuidores externos: comenta antes de empezar, espera a que te asignen, firma tus commits, consigue un aval, firma un CLA. Hoy descubres esas reglas cuando tu PR se cierra automáticamente. gatefile las extrae de la documentación del propio repositorio en contribution-gates.json, un formato legible por máquinas que las herramientas (como Greenlight) y el CI pueden consumir.

El problema

Un contribuidor elige un issue, escribe el código, abre el PR, y un bot lo cierra: "no estabas asignado", "autores sin aval se cierran automáticamente", "falta Signed-off-by". Las reglas siempre estuvieron en CONTRIBUTING.md, enterradas en prosa, diferentes en cada repositorio. Los mantenedores repiten las mismas correcciones; los contribuidores pierden las mismas noches.

Qué hace gatefile

  1. extraer: lee CONTRIBUTING.md, plantillas de PR e issues, archivos de flujo DCO/CLA, hooks de lefthook y archivos CLA (desde la API de GitHub o un directorio local) y emite las compuertas que encuentra, cada una con una línea citada real como evidencia.
  2. validar: compara un contribution-gates.json confirmado contra una extracción nueva e informa desviaciones (STALE, MISSING, SEVERITY_CHANGED). Código de salida 1 en caso de desviación, para que el CI pueda aplicarlo.
  3. insignia: genera un fragmento de README que informa a los humanos sobre las compuertas en lenguaje sencillo.

El formato contribution-gates.json

{
  "version": 1,
  "repo": "shadcn-labs/pdfcn",
  "generatedFrom": ["CONTRIBUTING.md"],
  "gates": [
    {
      "id": "claim_first",
      "kind": "claim_first",
      "severity": "blocker",
      "evidence": "Comment before starting work, and check the thread first in case someone else is already working on it.",
      "source": "CONTRIBUTING.md"
    }
  ],
  "conventions": {
    "branchNaming": "Name your branch feat/block-name",
    "prTitleFormat": "PR titles should follow Conventional Commits",
    "requiredChecks": []
  }
}

Tipos de compuerta

tiposeveridadsignificado
claim_firstbloqueanteComenta en el issue antes de empezar a trabajar
assignment_requiredbloqueanteEspera a que te asignen antes de abrir un PR
discuss_firstbloqueanteAbre una discusión o issue antes de codificar
issue_firstbloqueanteCada PR debe estar vinculado a un issue
vouch_requiredbloqueanteUn miembro existente debe avalarte
collaborators_onlybloqueanteSolo los colaboradores del repositorio pueden abrir PRs
no_direct_prsbloqueanteNo se aceptan PRs directos
dco_requiredadvertenciaLos commits necesitan un aviso Signed-off-by (DCO)
cla_requiredadvertenciaDebe firmarse un Acuerdo de Licencia de Contribuidor

Severidad: las compuertas blocker pueden hacer que un PR se cierre o rechace antes de la revisión. Las compuertas warn pueden corregirse después de abrir el PR. La evidencia es siempre una cita real del archivo fuente, recortada a unos 140 caracteres, nunca inventada.

Uso

CLI

# Extract gates from a repo (GitHub API, GITHUB_TOKEN optional)
gatefile extract shadcn-labs/pdfcn

# Extract from a local clone instead (fully offline)
gatefile extract local --local ./pdfcn --out contribution-gates.json

# Validate the committed file against fresh docs, exit 1 on drift
gatefile validate shadcn-labs/pdfcn --file contribution-gates.json

# Print a README snippet for humans
gatefile badge shadcn-labs/pdfcn

Servidor MCP

Añade a la configuración de tu cliente MCP:

{
  "mcpServers": {
    "gatefile": {
      "command": "node",
      "args": ["/path/to/gatefile/dist/mcp.js"]
    }
  }
}

Herramientas:

herramientaentradaslo que devuelve
extract_gatesrepo o localPathel objeto contribution-gates.json completo
validate_gatesrecorded, repo o localPath{ ok, drift[] }
gates_badgerepo o localPathfragmento de markdown para README

Ejemplo de CI

Mantén el archivo de compuertas honesto en un flujo de trabajo de GitHub Actions:

name: gates
on:
  pull_request:
    paths: ["CONTRIBUTING.md", ".github/**", "contribution-gates.json"]
jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20 }
      - run: npx -y gatefile extract ${{ github.repository }} --out /tmp/fresh.json
      - run: npx -y gatefile validate ${{ github.repository }} --file contribution-gates.json

Desarrollo

npm install
npm test        # tsx --test, offline, 23 tests
npm run build   # tsc to dist/
npm run dev -- extract owner/repo --json

TypeScript ESM, Node 20+, zod para esquemas, fetch nativo para la API de GitHub. Las pruebas usan fixtures del mundo real en test/fixtures/ modelados según casos documentados (comentar-antes-de-empezar más DCO más issue-primero; asignación-primero; solo-aval; permisivo).

Licencia

MIT, Rene Turcios 2026.