Cómo programo en 2026: mi stack en la era de los agentes

Cómo programo en 2026: mi stack en la era de los agentes

Llevo unas semanas dándole vueltas a una idea incómoda: cada vez abro menos un editor para escribir código. Lo dirijo, lo reviso, lo apruebo, pero tecleo cada vez menos. Y aun así estoy publicando más cosas que nunca: dos podcasts, una web personal con nueve herramientas, monitorización del servidor, un Jitsi propio, un fan site de Apple, cada vez más plugins de Moodle, este blog. Algo ha cambiado en cómo programo, y creo que merece la pena contarlo.

Dónde corre todo

Un Mac mini en casa. Sin VPS, sin cloud, sin Kubernetes. Apache sirve la web, PHP responde lo dinámico, Hugo construye el blog, un Cloudflare Tunnel saca todo a internet con HTTPS automático. La factura mensual de infra es lo que cuesta tener el Mac mini encendido.

Hace cinco años habría dicho que esto no escala. Hoy pienso lo contrario: para un proyecto personal, depender de menos servicios externos significa menos cosas que se rompen y menos suscripciones que pagar. Si necesito más capacidad, compro otro Mac mini.

El “editor”

Claude Code. Esto es el cambio fundamental. No es un autocompletado, no es un asistente, no es un chat al que copias y pegas. Es un agente que lee el repo, propone cambios, los aplica, ejecuta los tests, verifica con curl que la URL responde, y se acuerda de actualizar los seis sitios donde había que tocar algo cuando añado un episodio nuevo al podcast.

Lo que más ha cambiado mi flujo no es la generación de código —eso lo hace cualquier modelo— sino tres cosas que el agente hace por mí:

  • Recordar: tiene memoria persistente entre sesiones. Sabe que mi blog se publica con un git hook, que el podcast usa la voz Guillermo de ElevenLabs, que cuando edito un informativo hay que tocar también listen.php y monitor/index.php. No tengo que volver a explicarlo cada semana.
  • Verificar: no se fía de que su código funcione. Ejecuta lo que escribe. Comprueba que el MP3 devuelve 200, que el JSON es válido, que el día de la semana coincide con la fecha del calendario antes de escribir un título.
  • Automatizar lo repetitivo: tengo skills propias para publicar un episodio, generar imágenes con Pillow, lanzar reviews del diff, configurar Telegram. Lo que antes era un checklist mental ahora es una orden de tres palabras.

El stack de código real

Cuando hay que escribir, esto es lo que uso. Y lo destacable es por qué no uso otras cosas.

PHP plano. Sin Laravel, sin Symfony, sin frameworks. Para una web personal con cinco endpoints, un framework es más complejidad que beneficio. proc_open para llamar a msmtp, file_put_contents para escribir logs en JSONL, header() para devolver JSON. Funciona, es rápido, lo entiende cualquier programador en treinta segundos.

Python solo para scripts puntuales. Generación de imágenes con Pillow, llamadas a la API de ElevenLabs, alguna automatización con requests. Nunca para servir web. Si necesita estado, no es Python.

Bash para el pegamento. Los build-blog.sh, los post-commit hooks, los pipelines de ffmpeg para montar audio. Bash sigue siendo la mejor forma de orquestar comandos del sistema.

Hugo para el blog. Estático, rápido, sin base de datos. Un git commit dispara el hook que reconstruye y publica. El blog que estás leyendo se sirve sin un solo proceso PHP corriendo detrás.

HTML, CSS y JS sin framework para el frontend. La portada de sergiocomeron.com, las nueve herramientas, el player del podcast. Todo HTML estático con un CSS sin preprocesador y JS vanilla. Lighthouse da 96. No necesito React para una página que cambio cada dos meses.

Git como cola de despliegue

Esto es probablemente lo que más recomendaría copiar.

Cada repo tiene un git hook post-commit que, cuando detecta cambios en ciertos archivos, ejecuta el build y publica. El blog se reconstruye si toco content/posts/. La web principal se sincroniza con Apache si toco el index.html. El podcast actualiza el feed si toco feed.xml.

1git commit -m "post: cómo programo en 2026"
2# → el hook reconstruye Hugo, copia el output a Apache,
3# → Cloudflare sirve el HTML nuevo en segundos

No hay CI/CD, no hay GitHub Actions, no hay webhook a Cloudflare Pages. Un commit local hace todo. Si me equivoco, hago otro commit. La latencia entre “tengo una idea” y “está publicado” son segundos.

Logs en JSONL planos

Toda la observabilidad de mi servidor son archivos JSONL en ~/.monitor_logs/. Eventos del monitor, escuchas del podcast, alertas de Cloudflare. Un script en PHP los lee y pinta un dashboard con Chart.js. Sin Grafana, sin Prometheus, sin Loki.

Cuando algo es muy grande, hace falta una base de datos de series temporales. Cuando es lo mío, tail -f y jq resuelven el 90% de lo que necesito.

El móvil también es terminal

Algo que ha cambiado en los últimos meses es que ya no necesito estar delante del Mac mini para usarlo. Tengo un bot de Telegram conectado a Claude Code: puedo escribirle desde el iPhone y pedirle que publique el informativo del día, que compruebe si un servicio sigue vivo, que me resuma el monitor, que conteste un email pendiente. La app de Claude en iOS también me permite seguir conversaciones que dejé abiertas en la terminal — empiezo algo en casa, lo continúo en el coche, lo cierro desde el sofá.

El efecto es raro al principio. Estás paseando y se te ocurre publicar algo, lo dictas, el agente lo escribe y lo deja servido antes de que vuelvas a casa. La terminal sigue siendo donde más trabajo, pero ha dejado de ser el único sitio donde puedo trabajar.

Lo que ya no hago

  • No configuro entornos de desarrollo (salvo para Moodle). Mi entorno de desarrollo es el servidor de producción. Apache local, PHP local, los mismos archivos. Lo que veo en mi navegador es lo que ve el mundo. Para los plugins de Moodle sí tengo un entorno aparte, pero eso ya es otra historia que cuento más abajo.
  • No abro Docker para todo. Lo uso solo cuando es imprescindible, como con Jitsi. Para PHP y Hugo es overkill.
  • No instalo dependencias que no necesito. Cada composer require o npm install es una decisión, no un reflejo.
  • No aprendo el framework de moda. Cuando algo no encaja en HTML plano, miro qué hay. La mayoría de veces, HTML plano encaja.

Cuando sí escribo código: los plugins de Moodle

El otro lado de mi día a día es UDIMA, donde llevo años desarrollando plugins de Moodle: módulos de actividad, bloques, plugins locales, informes, lo que la universidad necesite en cada momento. Ahí sí toco código. Y aun así Claude está presente en casi todo lo que escribo.

La diferencia con mis proyectos personales es de control. En sergiocomeron.com puedo aceptar un cambio amplio sin mucho riesgo: si algo se rompe, lo arreglo en cinco minutos y no se entera nadie. En un plugin que usan miles de alumnos no me lo puedo permitir. Cada cambio pasa por mi cabeza línea a línea antes de subir nada.

Y, sin embargo, Claude resuelve la mitad del trabajo: el andamiaje. Moodle tiene convenciones muy rígidas — version.php, db/install.xml, db/upgrade.php, lang/en/, settings.php, lib.php, classes/, capabilities, eventos, observadores, tareas programadas — y casi todo ese esqueleto es repetitivo y está bien documentado. Es exactamente el tipo de código que un agente escribe en segundos sin error. Pedirle “añade una capability para que solo los profesores vean este informe” o “genera el upgrade.php que añade esta columna a la tabla” me ahorra media hora cada vez. Lang strings, formularios con moodleform, plantillas Mustache, settings de admin: todo eso ya lo hace muy bien.

Mención aparte para los tests unitarios. Montar un PHPUnit en Moodle con advanced_testcase, resetAfterTest y los fixtures correctos siempre ha sido engorroso, y por eso muchos plugins arrastraban menos cobertura de la que tocaba. Ahora le pido al agente que escriba los tests de la clase que acabo de tocar y los tengo en un minuto. Yo sigo decidiendo qué hay que probar y dónde está el riesgo — pero escribir el test ha dejado de ser una excusa para no escribirlo.

Donde no llega solo es en la lógica de negocio y en la integración fina con las APIs de Moodle. La diferencia entre usar $DB->get_records() o un recordset, cuándo cachear con cache::make(), qué hook usar en lugar de tocar core, cómo registrar un evento sin acoplarse demasiado al módulo que lo dispara — todo eso lo decido yo. El agente propone, pero las decisiones arquitectónicas son mías porque conozco el plugin, conozco a quien lo usa y conozco la deuda técnica que hay debajo.

También conviene desconfiar cuando el modelo inventa API. Moodle es enorme, va por la versión 5, y hay funciones que cambian de nombre, se deprecan o que nunca existieron y suenan plausibles. Toda sugerencia que toque una API que no recuerdo de memoria la verifico contra el código antes de aceptarla. Las primeras veces que no lo hice me llevé alguna sorpresa.

El resultado es un flujo distinto al de los proyectos personales. Aquí no dirijo, co-programo. Tecleo bastante. Pero tecleo lo que importa — la lógica, las decisiones, la revisión — y dejo que el agente teclee lo que no me aporta nada teclear.

Hay mucha más tela que cortar en cómo se desarrolla un plugin de Moodle con un agente al lado: el flujo de revisión, el manejo de la guía de estilo, qué partes del core conviene tener en contexto, cómo trabajar con upgrades sin romper instalaciones en producción. Eso da para un post propio que probablemente escriba pronto.

Lo que no me convence todavía

No quiero pintar esto como si todo fuera perfecto. Hay tres cosas que me siguen preocupando.

La dependencia de un único proveedor. Si mañana Anthropic cambia precios, deprecan el modelo que uso o se cae la API durante un día entero, buena parte de mi flujo se rompe. Tengo planes B mentales — cambiar de modelo, volver al editor de toda la vida — pero todavía no los he tenido que ejecutar de verdad.

El ritmo al que cambian los modelos. Cada pocos meses toca reaprender qué se le da bien y qué no, qué prompts siguen funcionando, qué ha mejorado y qué ha empeorado. Es parte del juego, pero a veces cansa. Lo que hoy escribo sobre cómo programo con Claude probablemente esté desactualizado en seis meses.

El riesgo de aceptar sin leer. Más de una vez he publicado un cambio que el agente había hecho a medias y no lo detecté hasta que algo falló. Verificar lo que sale del agente sigue siendo trabajo — no opcional, no negociable. Cuando lo olvido, lo pago.

Y luego está la duda incómoda que llevo arrastrando: hay días que termino sin haber tecleado código y me pregunto si estoy perdiendo músculo de sintaxis. Probablemente sí. La respuesta corta es que gano otro músculo distinto. La larga la tengo en la cabeza pero todavía no la sé contar bien.

¿Esto sigue siendo programar?

Esta es la pregunta incómoda, y la respuesta honesta es: sí, pero el músculo es otro.

Ya no es teclear sintaxis. Es saber qué pedir, qué dejar al agente, dónde mirar cuando algo falla, cuándo desconfiar de una sugerencia, cómo estructurar un proyecto para que el agente lo entienda. Es leer el diff con criterio. Es saber cuándo un test pasa por casualidad. Es entender qué está haciendo PHP por debajo aunque no haya escrito ni una línea de PHP esta semana.

A los que llevamos veinte años escribiendo código, este cambio nos remueve. La pregunta no es si la IA va a reemplazarnos —no lo hará, no del todo, no pronto— sino si la programación que aprendimos sigue siendo la programación que se va a hacer dentro de cinco años.

Yo creo que no. Y prefiero estar en el nuevo flujo, equivocándome con él, que defender el viejo por nostalgia.

Lo que viene

Estoy probando agentes que se ejecutan en cron sin que yo esté delante. Pequeñas tareas: revisar PRs, generar el informativo, comprobar que los servicios siguen vivos. El siguiente paso natural es que el agente publique cosas sin que yo apruebe cada paso — y ahí es donde aún no me atrevo del todo. Aprobar antes de publicar sigue siendo mi sanity check.

Pero llegaremos. Y cuando llegue, este post probablemente lo escriba un agente y yo solo lo apruebe con un emoji desde el móvil.