Módulo 1: Claude Code en GitHub Actions
Costos y Rate Limiting
Costos y Rate Limiting
Descripción
Tu workflow funciona, es seguro, y produce output útil. Pero hay una pregunta que no resolviste todavía: ¿cuánto cuesta? Cada ejecución consume tokens de la API de Anthropic + minutos de runner de GitHub Actions. Sin control, los costos crecen rápido — y la primera factura sorprende al equipo.
Esta cápsula te enseña a presupuestar y optimizar. Vas a aprender a calcular el costo real por run con tu modelo y volumen de tokens, identificar qué triggers generan ejecuciones innecesarias, configurar paths filters para correr solo cuando es relevante, y aplicar rate limiting a nivel del workflow para que un mal día (50 PRs en un repo problemático) no derrumbe tu presupuesto.
Al terminar, vas a tener un workflow económicamente sustentable: predecible, optimizado, y con guardas para los casos extremos.
El Cálculo Básico de Costos
Un run de Claude Code en CI tiene dos componentes de costo:
COSTO POR RUN = costo_de_API + costo_de_runner
API de Anthropic:
Input tokens × precio_input + Output tokens × precio_output
(precios oficiales en docs.anthropic.com/pricing)
GitHub Actions runner:
minutos × precio_por_minuto (free tier vs paid)
(Linux: $0.008/min en repos privados después del free tier;
gratis ilimitado en repos públicos)
Ejemplo concreto
Asumamos un workflow que corre claude-haiku-4-5 con un PR promedio:
Input promedio: 3,000 tokens (diff + prompt)
Output promedio: 600 tokens (análisis estructurado)
Por run:
3,000 × $0.0008/1K + 600 × $0.004/1K
= $0.0024 + $0.0024
= ~$0.005 por API call (medio centavo)
Runner:
~1.5 minutos × $0.008/min
= $0.012
Total por run: ~$0.017 (~1.7 centavos)
Escalado a un equipo
Equipo de 5 developers, 10 PRs por semana cada uno, 3 actualizaciones promedio por PR:
PRs por semana: 50
Actualizaciones: 150 (3 por PR)
Total runs/semana: ~150
Runs/mes: ~600
Costo mensual:
600 × $0.017 = ~$10.20/mes
Escalable para un equipo chico. Pero hay casos donde explota:
Equipo grande con monorepo:
20 developers × 15 PRs/semana × 5 actualizaciones = 1,500 runs/sem
6,000 runs/mes × $0.017 = ~$100/mes
Si además usas Sonnet o Opus (10× más caro):
6,000 × $0.17 = ~$1,000/mes
La elección del modelo es el factor #1 de costos. Haiku es 10× más barato que Sonnet. Para análisis general (este módulo), Haiku es suficiente. Para refactorings complejos, Sonnet vale la pena. Opus solo para tareas críticas de razonamiento.
Paths Filters: Ejecutar Solo Cuando es Relevante
El primer ahorro grande: no correr el workflow en cambios irrelevantes. Un PR que solo modifica README.md no necesita análisis de Claude Code.
Configurar paths filters
on:
pull_request:
types: [opened, synchronize]
paths:
- 'src/**'
- 'lib/**'
- 'tests/**'
- 'package.json'
- 'requirements.txt'
paths-ignore:
- '**.md'
- 'docs/**'
- '.github/ISSUE_TEMPLATE/**'
Cómo funciona:
paths: solo dispara si el PR toca al menos uno de esos pathspaths-ignore: no dispara si todos los archivos modificados están en esos paths
Regla: usa uno o el otro, no ambos. paths-ignore es más conservador (corre por defecto y excluye casos); paths es más restrictivo (solo corre en lo permitido).
Caso de uso típico
# Correr solo cuando cambia código fuente o tests
paths:
- 'src/**'
- 'tests/**'
# Pero ignorar cambios menores
paths-ignore:
- 'src/**.md'
- 'tests/fixtures/**'
Ahorro estimado: en un proyecto con docs activo, paths filters reducen ejecuciones un 30-50%.
Skipping Condicional con if
Más allá de paths, puedes saltear ejecuciones según condiciones del PR:
Ejemplo: skipear PRs de bots
jobs:
analyze:
if: github.actor != 'dependabot[bot]' && github.actor != 'renovate[bot]'
runs-on: ubuntu-latest
steps:
# ...
Bots como Dependabot abren muchos PRs de actualización de dependencias. Analizarlos con Claude Code rara vez aporta valor (los diffs son cambios de versión predecibles).
Ejemplo: skipear PRs draft
jobs:
analyze:
if: github.event.pull_request.draft == false
runs-on: ubuntu-latest
Un PR en draft está en construcción. Analizar antes de que el autor lo marque como ready desperdicia ejecuciones.
Ejemplo: skipear si el commit message lo indica
jobs:
analyze:
if: "!contains(github.event.head_commit.message, '[skip ai]')"
runs-on: ubuntu-latest
Permite a developers skipear el análisis cuando saben que no aporta (ej. "actualización trivial de copy"). Convención: incluir [skip ai] en el commit message.
Limitando el Tamaño del Diff
Un PR con 500 archivos modificados puede generar un diff enorme — caro y poco útil para Claude Code (la calidad degrada con context lleno).
Validar tamaño antes de ejecutar
"""Validar tamaño antes de llamar a Claude."""
from pathlib import Path
import sys
MAX_DIFF_LINES = 1500 # umbral razonable
diff_text = Path("pr_diff.txt").read_text()
diff_lines = len(diff_text.splitlines())
if diff_lines > MAX_DIFF_LINES:
print(f"PR demasiado grande ({diff_lines} líneas > {MAX_DIFF_LINES} límite).")
print("Skipping Claude Code analysis. Considera dividir el PR.")
# Opcional: postear comment al PR explicando
sys.exit(0) # exit 0 para no marcar el workflow como failed
Trade-off: PRs grandes son los que más se beneficiarían de análisis automático, pero también los que más cuestan. La política depende del equipo: bloquear ($0 gastados, equipo presionado a partir el PR), o ejecutar con chunking (más caro pero más útil — Módulo 2 cápsula 06).
Rate Limiting: Protegerse de Casos Extremos
Imagina: alguien hace fuerza-push a una rama con 50 commits y dispara el workflow 50 veces. O un bot configurado mal abre 100 PRs en un día.
Sin protección, esos casos pueden generar facturas de cientos de dólares.
Concurrency: solo un run por PR
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
analyze:
# ...
Cómo funciona: si llega un nuevo run para el mismo PR mientras hay uno en curso, el viejo se cancela y solo se ejecuta el nuevo. Salva runs duplicados cuando un developer hace push 3 veces seguidas.
Quota mensual con secret variable
Para casos más estrictos, puedes llevar una cuenta manual y abortar si excede:
- name: Check monthly quota
run: |
USAGE_FILE="usage_$(date +%Y%m).txt"
if [ -f "$USAGE_FILE" ]; then
CURRENT=$(cat "$USAGE_FILE")
else
CURRENT=0
fi
if [ "$CURRENT" -gt 1000 ]; then
echo "Monthly run quota exceeded ($CURRENT runs)."
exit 0
fi
echo $((CURRENT + 1)) > "$USAGE_FILE"
(Esto es ilustrativo; en producción usaríamos un sistema de tracking más robusto, no archivos en el runner.)
GitHub Actions Spending Limit
GitHub permite configurar spending limit a nivel de organización o cuenta:
Settings → Billing → Plans and usage → Set spending limit
Si llegas al límite, los workflows se pausan automáticamente. Es la última línea de defensa para repos privados.
Optimizando con Cache
Algunos costos se pueden reducir con caching:
Cache de dependencias Python
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip' # ← cache automático de pip
Reduce el tiempo de pip install de 30s a 3s. Con 600 runs/mes, ahorra ~5 horas de runner = ~$2.5/mes.
Cache custom para datos
Si tu script descarga algo que no cambia entre PRs (ej. base de datos de patrones, lista de CVEs), cachealo:
- name: Cache vulnerability database
uses: actions/cache@v4
with:
path: ~/.cache/vuln-db
key: vuln-db-${{ hashFiles('.github/db-version.txt') }}
Trampas Comunes en Costos
Error 1: Usar Sonnet o Opus por defecto
Síntoma: Factura mensual 5-10× más alta de lo esperado.
Por qué pasa: "Mejor modelo = mejor resultado". No siempre. Para análisis general de PR, Haiku es suficiente.
Cómo corregir: Empezar con Haiku. Subir a Sonnet solo si el resultado de Haiku es notoriamente insuficiente. Opus rara vez se justifica para CI.
Error 2: No configurar concurrency
Síntoma: PRs con muchos pushes generan runs duplicados que se ejecutan en paralelo, todos pagando.
Por qué pasa: Por defecto, GitHub corre cada trigger en paralelo. Con 5 pushes en 1 minuto, son 5 runs simultáneos.
Cómo corregir: concurrency con cancel-in-progress: true. Solo el último run se completa, los anteriores se cancelan.
Error 3: Ignorar el costo del runner
Síntoma: El equipo solo cuenta tokens de API. La factura de GitHub Actions sorprende.
Por qué pasa: El runner cuesta $0.008/min para repos privados. Con workflows de 5+ minutos, suma rápido.
Cómo corregir: Optimizar tiempo total: cache de pip, evitar steps innecesarios, paralelismo donde aplica.
Error 4: No filtrar bots
Síntoma: El bot del workflow analiza los PRs del bot de Dependabot. Generan análisis sin valor.
Por qué pasa: No hay filtro if: github.actor != 'dependabot[bot]'.
Cómo corregir: Filtrar explícitamente bots. Ahorro típico: 20-30% de runs (depende del nivel de actualización automatizada del repo).
Error 5: Sin spending limit
Síntoma: Un mal día (bug en el workflow que hace loop, ataque de un contributor malicioso) genera factura de $1000.
Por qué pasa: Sin spending limit en GitHub Billing, el costo puede crecer ilimitadamente.
Cómo corregir: Configurar spending limit razonable en Settings → Billing. Es la red de seguridad.
Diagnóstico: ¿Tu Workflow Está Optimizado?
Pregunta 1: ¿Sabes cuánto te costó el último mes de Claude Code en CI?
Si dijiste "no sé", abre Anthropic console → Billing y mira. Sin esa cifra, no puedes optimizar.
Pregunta 2: ¿Tu workflow tiene paths filters?
Si no, probablemente estás corriendo en cambios de docs/configs que no se benefician. Ahorro fácil de 30-50% de ejecuciones.
Pregunta 3: ¿Tu workflow tiene `concurrency` configurado?
Si no, runs paralelos al hacer push múltiple desperdician runs. Activarlo es 1 línea.
Pregunta 4: ¿Filtras PRs de bots automáticos (Dependabot, Renovate)?
Si no, estás analizando PRs de actualización de versiones que casi siempre no aportan análisis útil.
Pregunta 5: ¿Tienes spending limit configurado en GitHub Billing y un sistema de alertas en Anthropic console?
Sin estas dos redes de seguridad, un incident silencioso puede generar $1000+ antes de que lo notes.
Ejercicios
Ejercicio 1: Calcular costo mensual estimado (Fácil)
Para tu equipo, calcula: developers × PRs/semana × actualizaciones/PR × 4 semanas × $0.017. Compáralo con tu factura real (si la tienes). Identifica si hay desviación.
Ejercicio 2: Implementar paths filters (Medio)
Configura paths-ignore en tu workflow para que no corra cuando el PR solo modifica docs (**.md, docs/**). Verifica con un PR de docs que el workflow no se dispara.
Ejercicio 3: Configurar concurrency + skip de bots (Medio)
Agrega concurrency para cancelar runs duplicados, y if para skipear PRs de bots. Verifica con dos pushes seguidos al mismo PR (debería cancelar el primero) y con un PR generado por Dependabot (debería skipear).
Ver solución integrada
name: Claude Code Analysis
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
on:
pull_request:
types: [opened, synchronize, ready_for_review]
paths:
- 'src/**'
- 'tests/**'
- 'package.json'
paths-ignore:
- '**.md'
jobs:
analyze:
if: |
github.actor != 'dependabot[bot]' &&
github.actor != 'renovate[bot]' &&
github.event.pull_request.draft == false
runs-on: ubuntu-latest
permissions:
pull-requests: write
contents: read
steps:
# ... resto del workflow
Las cuatro optimizaciones combinadas (paths, concurrency, bots, draft) reducen ejecuciones típicamente 50-70%.
Ejercicio 4: Configurar spending limit (Fácil)
En GitHub Billing, configura un spending limit. En Anthropic console, configura un budget alert. Documéntalo en el SECURITY.md o equivalente del repo.
Resumen
- Costo por run = API de Anthropic + GitHub Actions runner
- Modelo es factor #1 de costos — Haiku para análisis general, Sonnet/Opus solo si justificado
- Paths filters ahorran 30-50% de ejecuciones en repos con docs activos
ifconditions skipean bots, drafts, y commits con[skip ai]concurrencyevita runs duplicados de pushes consecutivos- Spending limit en GitHub Billing es la última línea de defensa
- Cache de pip y custom reduce minutos de runner
Próxima cápsula: Módulo 2 — Code Review Automático en PRs. Hasta ahora el workflow ejecuta análisis general; el Módulo 2 lo especializa en code review con inline comments. Llevas todo lo aprendido en este módulo (workflows, secrets, output, costos) al siguiente nivel.
Recursos Adicionales
- Anthropic Pricing — Precios actuales por modelo
- GitHub Actions Pricing — Costos de runners
- GitHub Actions: paths filters — Documentación oficial
- GitHub Actions: concurrency — Documentación oficial
- GitHub Actions: caching — Cache de dependencias
- Anthropic Token Counting — Estimar tokens antes de la llamada
- GitHub Actions: usage limits — Límites de la plataforma