Codex Automations sin Codex: agentes nocturnos con Claude Code y systemd

| Última modificación: 4 de mayo de 2026 | Tiempo de Lectura: 8 minutos
Premios Blog KeepCoding 2025

Co-Fundador de KeepCoding

Hace dos semanas, OpenAI presentó las Codex Automations. La idea: defines un trigger (un cron, un push, un issue nuevo), escribes instrucciones en lenguaje natural, y un agente lo ejecuta solo en un worktree aislado. Sin intervención humana. Mientras duermes, el agente hace triage de issues, resume fallos de CI, genera release briefs y hasta mejora sus propias instrucciones.

Suena a magia. Y lo es, un poco. Pero hay un detalle que no mencionan mucho en el keynote: necesitas la Codex App corriendo en tu escritorio. macOS o Windows. Nada de servidor headless. Nada de dejarlo en un miniPC y olvidarte.

Y ahí es donde pensé: «Espera. Yo ya tengo esto.»

Las piezas que ya tienes

Si usas Claude Code, ya tienes el 90% de la infraestructura. claude --print ejecuta un prompt sin sesión interactiva. Le pasas instrucciones, te devuelve resultado, y cierra. Sin GUI. Sin terminal abierta. Perfecto para un cron.

Si tienes un servidor siempre encendido (un miniPC, una Raspberry Pi, un VPS de 5 euros), ya tienes el scheduler. systemd o cron, lo que prefieras. Llevan décadas funcionando mientras duermes.

Y si usas Gitea, GitHub, o cualquier forge con API, ya tienes dónde depositar los resultados: comentarios en PRs, issues nuevas, ficheros commiteados.

Dicho en cristiano: las Codex Automations son un patrón. No un producto. Y el patrón es viejo.

┌─────────────────────────────────────────────┐
│           systemd timer (cada N horas)       │
│                     │                        │
│                     ▼                        │
│           script bash/fish                   │
│              │                               │
│              ├── git pull --ff-only           │
│              ├── claude --print "prompt"      │
│              ├── parsear resultado            │
│              ├── notificar (Telegram/email)   │
│              └── git push (si hay cambios)    │
└─────────────────────────────────────────────┘

Anatomía de una automatización

Todas las automatizaciones siguen la misma estructura. Un script que:

  1. Actualiza el repo (git pull)
  2. Ejecuta Claude Code en modo no interactivo
  3. Hace algo con el resultado
  4. Notifica y/o commitea

Vamos a montar la primera. Luego las demás son variaciones del mismo tema.

El script base

#!/usr/bin/env bash
set -euo pipefail

REPO_DIR="/srv/social-publisher"
LOG_DIR="/var/log/automations"
TIMESTAMP=$(date +%Y%m%d-%H%M%S)

cd "$REPO_DIR"
git pull --ff-only

RESULT=$(claude --print \
  --model sonnet \
  --max-turns 3 \
  "$1")  # El prompt viene como argumento

echo "$RESULT" > "$LOG_DIR/$TIMESTAMP.md"

Eso es todo. El esqueleto cabe en 12 líneas. Lo demás es decidir qué prompt le pasas y qué haces con $RESULT.

El timer de systemd

# /etc/systemd/system/claude-automation.timer
[Unit]
Description=Claude Code automation

[Timer]
OnCalendar=*-*-* 03:00:00
Persistent=true

[Install]
WantedBy=timers.target
# /etc/systemd/system/claude-automation.service
[Unit]
Description=Claude Code automation runner

[Service]
Type=oneshot
User=claude-runner
ExecStart=/opt/automations/review-prs.sh
Environment=ANTHROPIC_API_KEY=<tu-key>
sudo systemctl enable --now claude-automation.timer

A las 3 de la mañana, systemd arranca el script. Claude analiza lo que le pidas. Deposita el resultado. Tú te enteras por la mañana.

Ejemplo 1: Review automático de PRs

Este es el que más jugo da. Cada vez que hay una PR abierta, Claude la revisa y deja un comentario.

Con webhook es más elegante, pero un cron cada 30 minutos funciona igual de bien para equipos pequeños:

#!/usr/bin/env bash
set -euo pipefail

GITEA_URL="https://git.example.com"
GITEA_TOKEN="$(op read 'op://DEV/Gitea/token')"
REPO="myorg/myrepo"

# Obtener PRs abiertas
PRS=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
  "$GITEA_URL/api/v1/repos/$REPO/pulls?state=open" \
  | jq -r '.[].number')

for PR_NUM in $PRS; do
  # Obtener el diff
  DIFF=$(curl -s -H "Authorization: token $GITEA_TOKEN" \
    "$GITEA_URL/api/v1/repos/$REPO/pulls/$PR_NUM" \
    -H "Accept: application/diff")

  # Claude analiza el diff
  REVIEW=$(claude --print \
    --model sonnet \
    --max-turns 1 \
    "Revisa este diff de una PR. Señala bugs potenciales, \
     problemas de seguridad y mejoras concretas. Sé directo. \
     No repitas el código, solo señala problemas con su línea.

     $DIFF")

  # Publicar como comentario
  curl -s -X POST \
    -H "Authorization: token $GITEA_TOKEN" \
    -H "Content-Type: application/json" \
    "$GITEA_URL/api/v1/repos/$REPO/pulls/$PR_NUM/comments" \
    -d "{\"body\": \"## Review automático\\n\\n$REVIEW\"}"
done

Cada mañana, cuando abres Gitea, cada PR tiene un comentario con observaciones. No sustituye al review humano, pero filtra lo obvio: typos, imports no usados, un if sin else que huele a bug.

Ejemplo 2: Triage diario de issues

Tienes 47 issues sin asignar en Linear. Nadie las mira. Se acumulan como los emails sin leer. Este script las clasifica cada noche:

#!/usr/bin/env bash
set -euo pipefail

# Exportar issues sin asignar
ISSUES=$(linear issue list \
  --team MYT \
  --state unstarted \
  --no-assignee \
  --sort created \
  --no-pager \
  --json)

# Claude las clasifica
TRIAGE=$(claude --print \
  --model sonnet \
  --max-turns 1 \
  "Clasifica estas issues por urgencia (critical, high, medium, low).
   Para cada una, sugiere quién debería encargarse según el área
   (frontend, backend, infra, docs).
   Formato: una línea por issue, ID | urgencia | área | razón breve.

   $ISSUES")

# Enviar a Telegram
curl -s -X POST \
  "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
  -d "chat_id=${CHAT_ID}" \
  -d "text=📋 Triage diario:

$TRIAGE" \
  -d "parse_mode=Markdown"

A las 8 de la mañana, cuando miras Telegram con el café, tienes un resumen de qué issues son urgentes y quién debería mirarlas. En vez de abrir Linear, escanear 47 títulos y decidir tú, el agente ha hecho el primer filtro.

Ejemplo 3: Health check semanal de repos

Este es mi favorito. Un cron dominical que analiza cada repositorio buscando deuda técnica silenciosa:

#!/usr/bin/env bash
set -euo pipefail

REPOS=("social-publisher" "tokamak" "frr.dev")
REPORT=""

for REPO in "${REPOS[@]}"; do
  cd "/srv/$REPO"
  git pull --ff-only

  CHECK=$(claude --print \
    --model sonnet \
    --max-turns 5 \
    "Analiza este repositorio y reporta:
     1. Dependencias desactualizadas (lee pyproject.toml o package.json)
     2. Tests rotos (ejecuta 'make test' si existe Makefile)
     3. CLAUDE.md obsoleto (compara con la estructura real del proyecto)
     4. TODOs y FIXMEs abandonados (más de 30 días)

     Sé conciso. Solo reporta problemas reales, no avisos genéricos.")

  REPORT="$REPORT

## $REPO
$CHECK
"
done

# Guardar informe
echo "$REPORT" > /srv/reports/health-$(date +%Y%m%d).md

# Notificar
curl -s -X POST \
  "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
  -d "chat_id=${CHAT_ID}" \
  -d "text=🏥 Health check semanal listo. $(echo "$REPOS" | wc -w) repos analizados." \
  -d "parse_mode=Markdown"

El domingo a las 6am, Claude recorre cada repo, ejecuta tests, compara el CLAUDE.md con la realidad, busca dependencias viejas. El lunes por la mañana tienes un informe con los problemas reales. No los inventados por un linter paranoico, sino los que Claude encuentra al leer el código con contexto.

Ejemplo 4: Midnight Oil (auditoría de CLAUDE.md)

Este es el más meta. Un agente que audita las instrucciones de otros agentes.

Si usas CLAUDE.md para guiar a Claude Code en tus proyectos, sabes que se quedan obsoletos. Añades un directorio nuevo, cambias la base de datos, migras de npm a pnpm… y el CLAUDE.md sigue diciendo lo de hace tres meses.

#!/usr/bin/env bash
set -euo pipefail

REPOS=("social-publisher" "tokamak" "frr.dev" "mcp-email")
DEBT_REPORT=""

for REPO in "${REPOS[@]}"; do
  cd "/srv/$REPO"
  git pull --ff-only

  if [ ! -f "CLAUDE.md" ]; then
    DEBT_REPORT="$DEBT_REPORT\n- **$REPO**: Sin CLAUDE.md"
    continue
  fi

  AUDIT=$(claude --print \
    --model sonnet \
    --max-turns 3 \
    "Lee CLAUDE.md y compáralo con el estado real del proyecto.
     Busca:
     - Comandos documentados que ya no funcionan
     - Directorios mencionados que no existen
     - Dependencias listadas que no están en el lockfile
     - Secciones que contradicen el código actual

     Lista solo las discrepancias concretas, con la línea de CLAUDE.md
     afectada y qué dice la realidad.")

  if [ -n "$AUDIT" ]; then
    DEBT_REPORT="$DEBT_REPORT\n\n### $REPO\n$AUDIT"
  fi
done

echo -e "$DEBT_REPORT" > /srv/reports/prompt-debt-$(date +%Y%m%d).md

OpenAI llama a esto Upskill: el agente mejora sus propias instrucciones. Aquí no llegamos a tanto (el agente detecta, no corrige), pero el informe de prompt debt vale oro. Es como pasar un linter a tu documentación de IA.

La comparativa honesta

Ahora la pregunta inevitable: ¿merece la pena montarlo a mano teniendo Codex Automations?

Aspecto Codex Automations DIY con Claude Code
Setup GUI, 2 minutos systemd + scripts, 1 hora
Triggers Push, PR, issue, schedule Schedule (cron), webhooks con script
Contexto Repo completo + Skills nativas Repo completo + CLAUDE.md
Resultados Inbox visual con triage Telegram / Gitea comments / ficheros
Inteligencia GPT-5.3-Codex Claude Opus/Sonnet
Coste Incluido en suscripción Codex ~0.50 EUR por ejecución (API)
Requiere Codex App corriendo (desktop) Servidor siempre encendido
Personalización Media (templates predefinidos) Total (scripts custom)
Open source Core de Codex es open source Claude Code es propietario, tus scripts son tuyos

Codex gana en time to first automation. Dos minutos en una GUI. Sin tocar la terminal.

El enfoque DIY gana en todo lo demás. Control total. Sin dependencia de una app de escritorio. Sin vendor lock-in en el scheduler. Si mañana Anthropic cierra o cambia los precios, cambias claude --print por openai chat o ollama run y el resto del script sigue igual.

Los gotchas que nadie te cuenta

Antes de que salgas corriendo a montar esto, un par de cosas que aprendí a base de golpes:

1. Los tokens cuestan dinero de verdad. Cada ejecución de claude --print con Sonnet cuesta entre 0.20 y 1.00 EUR dependiendo del tamaño del contexto. Si tienes un cron cada 30 minutos analizando 5 repos, haz las cuentas: 240 ejecuciones al día. A 0.50 EUR cada una, son 120 EUR diarios. Ajusta la frecuencia a lo que realmente necesitas.

2. --max-turns es tu amigo. Sin límite, Claude puede decidir que necesita «investigar más» y encadenar 20 llamadas a herramientas. Cada tool call consume tokens. Ponle --max-turns 3 para reviews simples y --max-turns 5 para análisis profundos.

3. El prompt es el 80% del resultado. Un prompt vago («revisa este repo») te da una respuesta vaga. Un prompt específico («busca dependencias con CVEs conocidos en pyproject.toml y lista solo las críticas») te da algo accionable. Invierte tiempo en el prompt, no en el script.

4. Parsear la salida es un arte. Claude devuelve markdown por defecto. Si necesitas JSON para procesamiento posterior, pídelo explícitamente en el prompt: «Responde SOLO con JSON válido, sin bloques de código ni explicaciones.» Y aun así, valida la salida antes de usarla.

5. Git push automático da miedo. Y debería. Un git push en un cron nocturno sin revisión humana es una bomba de relojería. Mi recomendación: que el agente commitee en una rama, cree una PR, y tú apruebes por la mañana. Nunca push directo a main.

El diagrama completo

Así queda la arquitectura cuando juntas todas las piezas:

┌─────────────────────────┐     ┌──────────────────────────────┐
│   Codex App (OpenAI)    │     │   DIY (Claude Code + infra)  │
│                         │     │                              │
│  ┌───────────────────┐  │     │  ┌────────────────────────┐  │
│  │  Desktop App      │  │     │  │  systemd timers        │  │
│  │  (debe estar      │  │     │  │  (servidor 24/7)       │  │
│  │   corriendo)      │  │     │  │                        │  │
│  └────────┬──────────┘  │     │  └───────────┬────────────┘  │
│           │              │     │              │               │
│  ┌────────▼──────────┐  │     │  ┌───────────▼────────────┐  │
│  │  Codex Agent      │  │     │  │  bash + claude --print  │  │
│  │  (worktree)       │  │     │  │  (en el repo)          │  │
│  └────────┬──────────┘  │     │  └───────────┬────────────┘  │
│           │              │     │              │               │
│  ┌────────▼──────────┐  │     │  ┌───────────▼────────────┐  │
│  │  Inbox visual     │  │     │  │  Gitea API + Telegram   │  │
│  │  (Codex App)      │  │     │  │  + ficheros MD          │  │
│  └───────────────────┘  │     │  └────────────────────────┘  │
└─────────────────────────┘     └──────────────────────────────┘

La diferencia fundamental: Codex es un sistema integrado donde todo vive dentro de la app. El enfoque DIY son piezas sueltas que tú ensamblas. Como la diferencia entre un Mac (todo controlado, todo bonito) y un PC montado por piezas (más trabajo, más control).

Montando tu primera automatización en una tarde

Si quieres probarlo hoy mismo, este es el plan:

Hora 1: El script. Copia el script base de review de PRs. Cámbialo para tu forge (GitHub, Gitea, GitLab — las APIs son similares). Pruébalo a mano: bash review-prs.sh. Comprueba que el comentario aparece.

Hora 2: El timer. Crea el unit de systemd. Actívalo. Comprueba con systemctl list-timers que aparece. Fuerza una ejecución con systemctl start claude-automation.service para verificar.

Hora 3: Las notificaciones. Monta el bot de Telegram (5 minutos con BotFather). Añade el curl al final del script. Ahora te llega un mensaje cada vez que el agente ejecuta.

Tres horas. Sin framework. Sin dependencias. Bash, curl, claude --print, y el scheduler más fiable del mundo Unix.

El truco no es la tecnología

Lo que Codex llama Automations es un patrón que existe desde que existe cron. La novedad es que el «procesamiento» ya no es un script determinista, sino un LLM que entiende contexto. Pero la orquestación — el trigger, el scheduling, la notificación — es infraestructura aburrida que llevas décadas usando.

El truco no es qué herramienta usas. Es decidir qué automatizar.

Un review de PRs que nadie lee es ruido. Un triage de issues que nadie sigue es teatro. Un health check que genera informes que se acumulan sin leer es… bueno, otro fichero Markdown que nadie abre.

Antes de montar la automatización, pregúntate: «Si este informe me llegara mañana a las 8am, ¿lo leería? ¿Haría algo con él?»

Si la respuesta es sí, monta el cron. Si la respuesta es «depende», monta el cron pero revísalo en dos semanas. Si la respuesta es no, ahorra los tokens y dedica la tarde a otra cosa.

Los agentes que curran mientras duermes son útiles. Pero solo si alguien revisa lo que hacen cuando se despierta.


Read this article in English.

Noticias recientes del mundo tech


¡CONVOCATORIA ABIERTA!

Desarrollo de apps móviles ios & Android

Full Stack Bootcamp

Clases en Directo | Profesores en Activo | Temario 100% actualizado

Descárgate también el informe de tendencias en el mercado laboral 2026.

Fórmate con planes adaptados a tus objetivos y logra resultados en tiempo récord.
KeepCoding Bootcamps
Resumen de privacidad

Esta web utiliza cookies para que podamos ofrecerte la mejor experiencia de usuario posible. La información de las cookies se almacena en tu navegador y realiza funciones tales como reconocerte cuando vuelves a nuestra web o ayudar a nuestro equipo a comprender qué secciones de la web encuentras más interesantes y útiles.