Seis meses sin escribir código a mano: lo que aprendí
Seis meses sin escribir código a mano: lo que aprendí
Hay un post de exe.dev que se me quedó dando vueltas toda la semana. El autor se puso una regla en febrero: si un agente se trababa, no podía terminar el código él mismo. Tenía que entender qué le estaba faltando al agente y arreglar eso en su lugar. Seis meses después corría veinte VMs en paralelo, había reemplazado code review por design review, y escribía menos líneas por mes que en cualquier semana de 2019. El post está lleno de frases que te quedas mirando al techo: “shipping got easy, deciding what to ship got important”, o “I’ve shipped more in these six months than in any stretch of my career. I’ve also failed more”.
La tentación es leerlo como una victoria de la IA. No lo es. Es una derrota de la idea de que escribir código es la parte difícil del trabajo de un ingeniero. Y deja varias lecciones que vale la pena desarmar, porque aplican mucho más allá de exe.dev.
El primer error: confundir tipear con entender
El autor arranca con una confesión que todos los que programamos hace años sentimos en algún momento: “I could see the code in my head. I just couldn’t type it out fast enough”. Su superpoder era el modelo mental del sistema, no la velocidad del teclado. Cuando apareció Copilot, fue alivio. Cuando llegó Cursor, fue mejor. Cuando llegó Claude Code, fue una liberación: podía describir el cambio una vez y el agente editaba varios archivos a la vez.
Lo que no cambió fue la responsabilidad. “I still had to read every change the model generated to match it against the desired state I had in my head”. La IA escribe más rápido de lo que vos podés leer, pero todavía necesitás leer para validar. Si dejás de leer, dejás de entender. Y si dejás de entender, terminás heredando una codebase legacy que resulta ser nueva. Eso es vibe coding en su peor versión: aceptar lo que el agente produce porque compila y pasa tests, sin internalizar qué se construyó ni por qué.
La distinción que propone el post entre vibe coding y agentic engineering es la más importante del texto. Vibe coding es dejar que el agente diseñe, implemente y valide, y vos mirás desde afuera. Agentic engineering es trabajar con el agente en el sistema primero: arquitectura, interfaces, constraints, tradeoffs. Cuando llega el código, ya sabés qué estás por recibir. Es ingeniería movida un nivel arriba: el código es output, no el producto.
El problema real: agentes en paralelo rompen todo
Lo que me parece más interesante del post no es el “no escribir código”, es la sección donde describe lo que pasa cuando ponés varios agentes a trabajar a la vez. “I wasn’t intentionally building a parallel system. I was just filling the time between tasks”. Le sobraba tiempo entre agentes, así que abría otro. Como tiene ADHD, perdió la noción de cuántos tenía corriendo en simultáneo.
El caos que describe suena familiar a cualquiera que haya intentado usar dos agentes en la misma máquina:
- Pisaban archivos del mismo repo
- Peleaban por puertos
- Instalaban dependencias incompatibles
- Dejaban procesos vivos que comían memoria
- Git state se mezclaba entre worktrees
“I had started more agents to avoid waiting and somehow created a new way to wait”. Es la versión moderna de la ley de Brooks: sumar devs a un proyecto atrasado lo atrasa más. Sumar agentes a una máquina sin aislarlos hace exactamente lo mismo.
Las soluciones que probó son las que cualquiera que haya escalado esto conoce:
- Worktrees resuelven Git pero no el resto (puertos, DB, procesos)
- AGENTS.md con reglas tipo “usá puerto random, creá DB efímera, no toques procesos ajenos” funciona pero gasta context explicando a cada agente qué no hacer
- Containers aíslan puertos y procesos pero el blast radius sigue siendo el de tu laptop: si un agente prompt-injectado puede alcanzar Stripe, el container no te salva
La solución que eligió exe.dev es la correcta: una VM disposable por agente. “I closed my laptop. The work kept going”. Cada agente corre en su propio Linux con SSH y HTTPS ya configurados. Cuando un agente rompe algo, perdés la VM, no tu sesión. Cuando querés que un agente trabaje seis horas en un refactor, cerrás la laptop y te vas a dormir. Cuando volvés, el diff te está esperando.
La métrica que importa no es cuántas líneas escribe el agente, sino cuánto te cuesta reintentar cuando falla. Si la respuesta es “una VM”, podés permitirte fallar mucho. Si la respuesta es “medio día de setup”, no.
YOLO mode solo es aceptable dentro de una caja
Hay un momento en el post donde el autor dice algo que a cualquier ingeniero de seguridad le va a erizar la piel: “None of this worked if I had to approve every tool call. That would just turn me into the queue again. Each agent was running inside an isolated, disposable VM, so I let it run in YOLO mode”.
YOLO mode significa: el agente puede correr bash, instalar paquetes, levantar servicios, cambiar lo que necesite. Sin pedir permiso. Es lo opuesto a la permission fatigue que cubrimos en este post: cuando tenés que aprobar cada acción, terminás aprobando cualquier cosa por cansancio.
El autor lo justifica con una frase clave: “A trashed environment cost me nothing but the VM”. Esa es la condición necesaria para que YOLO mode sea razonable. Si la VM tiene acceso a tu laptop, a tu base de datos de producción, a tu cuenta de Stripe, no es YOLO mode, es un incidente esperando.
Aún así, no todo pasa dentro de la caja. Los agentes necesitan leer logs, pull de Git, llamar a Anthropic u OpenAI, inspeccionar cosas en Stripe. El post distingue dos patrones para extender el blast radius sin perder la VM:
- Acceso de lectura pasa casi siempre: si un agente lee contenido no confiable y puede ser prompt-injected, lo peor que puede hacer es leer cosas que no debería, y eso deja痕
- Acceso de escritura no pasa nunca directo: si necesita escribir, va a un entorno de test. El peor caso es “datos de test corruptos”, no “producción quemada”
- Credenciales fuera de la VM: en vez de meter la API key de Stripe en el container, se manda el request por un proxy que agrega la credencial. El agente ve la respuesta, nunca ve el secreto
Eso último es lo que más me gustó. Es el patrón que MCP 2.0 stateless debería formalizar a nivel protocolo: el agente nunca toca el secreto, solo recibe resultados. Pero la idea de exe.dev va más allá de MCP: las credenciales viven en el host que orquesta los containers, y cada VM es un consumidor anónimo de un proxy que sabe más de lo que muestra.
La trifecta letal de Simon y dónde está el riesgo real
El post cita explícitamente un concepto de Simon Willison que cada vez aparece más en discusiones serias: la lethal trifecta. Son tres capacidades que, combinadas en un mismo agente, son garantía de incidente:
- Acceso a datos privados (código, docs internos, datos de usuarios)
- Procesamiento de contenido no confiable (emails, páginas web, PDFs que te mandan)
- Capacidad de comunicación externa (mandar emails, hacer commits, hablar con APIs externas)
Cualquier par es manejable. Las tres juntas en un agente es cómo se te filtran los secretos. El autor no intenta minimizar la superficie de tools ciegamente; lo que hace es aislar el entorno y controlar qué combinaciones son posibles. Si un agente tiene acceso a tu código y puede leer emails pero no puede commitear, está acotado. Si tiene acceso a logs de producción y puede leer páginas web pero no puede mandar emails, también. El problema aparece cuando las tres capabilities se montan sobre el mismo loop.
Esto conecta directo con lo que cubrimos en agentes hablando entre sí: cuando los agentes empiezan a delegar trabajo a otros agentes, la trifecta se multiplica por N y los límites se vuelven borrosos. Ahí es donde el sandboxing clásico no alcanza: no podés confiar en que ningún componente de la cadena es 100% seguro. La estrategia de exe.dev es asumir compromiso y poner el blast radius en la VM, no en tu infra.
Code review murió, hola design review
Una de las afirmaciones más fuertes del post: “Peer code review is dead. We don’t do code reviews at exe.dev: we merge code we deem should be merged”. La review que importa sucede antes, en la discusión de diseño, en los contracts, en la validación. Para cuando existe el diff, las decisiones ya están tomadas.
Esto es contraintuitivo pero tiene sentido si lo seguís hasta el final. Si el agente ya escribió el código, ya pasó los tests, ya tiene screenshots de la UI funcionando, ya fue revisado por otros dos agentes, leer el diff una vez más no agrega valor real: lo que agregás o no, ya se decidió en la fase de diseño. El cuello de botella se movió. Antes era “¿este código compila y resuelve el problema?”, ahora es “¿estamos resolviendo el problema correcto?”.
Eso explica el ascenso del concepto de harness: el harness es la configuración de tools, system prompt, skills, AGENTS.md, entorno, que define qué puede hacer un agente y cómo lo hace. Como dice el autor, “the harness is the fulcrum from which my expectations meet the LLM’s capabilities”. Un buen modelo con un mal harness produce resultados mediocres. Un modelo commodity con un harness excelente produce resultados que rivalizan con los del modelo frontier. El diferencial ya no está en qué modelo usás, está en cómo lo configurás.
Si tu único criterio de calidad es “qué modelo corre el agente”, estás optimizando la variable equivocada. El 80% de la diferencia entre un agente útil y un agente brillante vive en el harness.
Ingeniería de migraciones, no de features
La parte más sobria del post es la final. “So much of the game is migrations now. Code changes are cheap, but systems carry state: data, running processes, users mid-flight”. Cuando el código es barato, lo caro es mover estado de un diseño al siguiente sin romper a nadie en el medio. El trabajo de ingeniería dejó de ser “agregar features” y pasó a ser “gestionar migraciones”.
Eso tiene sentido si lo pensás. Con vibe coding podés reescribir un módulo en una tarde. Pero los usuarios que ya lo están usando, los procesos que dependen de su comportamiento, los scripts de CI que asumen su shape, los datos que viajaron por su API: todo eso queda atado. La ley de Hyrum se cumple: “once enough people use a system, someone depends on every observable behavior, even behavior you never intended to be a contract”. Des-shippear es más caro que shippear, porque des-shippear rompe gente que no sabías que existía.
Lo que el post dice sin decir es que la disciplina de testing ya no es opcional, y el tipo de testing cambió. Unit tests que duplican la implementación churn junto con el código: cuando el agente reescribe la implementación, los tests se rompen y hay que regenerarlos, y terminaste con tests que validan lo que el agente escribió, no lo que el sistema debe cumplir. Lo que importa son behavior tests, contract tests, property tests: definir invariantes del sistema y pinear qué tiene que seguir siendo verdad mientras el código debajo cambia libremente. Es lo opuesto al test que verifica la implementación actual.
Lo que no me cierra del post
No todo es oro. El post tiene un tono casi triunfalista que esconde costos reales. El autor reconoce que “I’ve lost some of that depth. I don’t have the same line-by-line familiarity with every system”. Esa pérdida de familiaridad es real y tiene costo: cuando algo se rompe a las 3 AM, ¿cuánto tarda un dev que ya no lee el código en encontrar la falla? El post no contesta eso. Dice “Work no longer waits for me to finish one thing before starting another”, que es cierto, pero también dice que la profundidad de comprensión del sistema que tenía hace seis meses ya no la tiene. Esa tensión no se resuelve solo con más VMs.
Además, exe.dev es una empresa chica vendiendo VMs Linux. Tienen incentivo comercial a presentar este modelo como el futuro. Cuando un dev de FAANG te dice que ya no escribe código, la pregunta no es si es cierto, es cuántos de sus colegas pueden hacer lo mismo con la misma cantidad de guardrails, o si los guardrails son posibles solo porque hay cinco personas coordinando los agentes en vez de cincuenta.
Lo que sí me llevo: la idea de que ingeniería de sistemas, sandboxing y diseño de harness son lo único que escala. Los modelos van a seguir mejorando. Los agentes van a ser más rápidos. Pero el trabajo de configurar bien el entorno, aislar el blast radius, validar invariantes y decidir qué construir en vez de cómo construirlo, sigue siendo trabajo de ingenieros. La IA no te reemplaza: te corre el techo de lo que podés hacer, siempre que inviertas en serio en el harness.