Site Logo
Published on

SAM: construí mi propio director de proyectos porque coordinar todo a mano dejó de alcanzar

Authors

Antes, ser full-stack era raro. Escribir el front, el back, diseñar la base de datos, entender el deployment, sostener la arquitectura completa de una aplicación en la cabeza — pocos desarrolladores podían con todo eso a la vez, y los que podían tardaban. Por eso existían los equipos: alguien de frontend, alguien de backend, alguien de infra.

Hoy esa barrera se corrió. Con agentes escribiendo código, el costo de escribir código se volvió prácticamente cero. Lo que no bajó de precio es todo lo demás: la arquitectura, el diseño del sistema, las decisiones de base de datos, el deployment, la coordinación entre todas esas piezas. Ese es el trabajo que queda, y es el que no escala solo porque el código salga más rápido.

Esta es la premisa de este post y la razón por la que armé SAM: un orquestador que uso para coordinar todo lo que pasa en Alto Valle Studio y en los proyectos de mis clientes — tickets, agentes escribiendo código en paralelo, entornos de prueba, ramas, pull requests — para no ser yo el cuello de botella.

El código se volvió barato; todo lo demás no

Cuando escribir código deja de ser el límite, lo que te frena es otra cosa: tener que aprender y sostener arquitectura, diseño de sistema, bases de datos y deployment para cada proyecto que llevás. Y si llevás varios proyectos de varios clientes a la vez — que es mi caso — esa carga no se suma, se multiplica. Cada contexto nuevo (qué stack usa este cliente, cómo se despliega, qué convenciones tiene ese repo) es tiempo que no vas a recuperar escribiendo código más rápido, porque el código ya no era el problema.

Ahí es donde me encontré siendo yo mismo el embudo: no porque no pudiera escribir el código — los agentes lo escriben —, sino porque cada agente trabajando en cada proyecto necesitaba que yo cargara en la cabeza en qué estado había quedado cada cosa. Qué ticket estaba en qué worktree, qué rama era real y cuál inventada, qué entorno seguía corriendo y cuál ya había muerto. Coordinar eso a mano, para un puñado de clientes con varios proyectos cada uno, dejó de ser humanamente sostenible bastante antes de lo que pensé.

La frase que me quedó grabada cuando me senté a diagnosticar esto en serio fue: SAM modelaba muy bien el trabajo, pero no modelaba el estado del mundo. Los tickets tenían archivo en disco, ciclo de vida, historial. Los entornos, las ramas, los worktrees y los PRs no — eran cálculos que se recalculaban cada vez que abría la pantalla, y que se perdían apenas reiniciaba el proceso.

Un ejemplo concreto: el entorno de un ticket vivía en memoria. Reiniciás el servidor — algo que pasa seguido en desarrollo — y esa información desaparece, aunque el proceso real siga corriendo en algún puerto. La rama de un ticket ni siquiera se guardaba: se derivaba del id del ticket, lo cual funcionaba perfecto hasta que un ticket corría en un modo donde esa rama nunca había existido, y el sistema mentía con total confianza.

De ahí la lección que terminó siendo el principio de diseño de todo lo demás: lo que no es una entidad con ciclo de vida propio, tarde o temprano miente.

De full-stack a technical lead

La forma en la que resolví esto no fue escribir más rápido. Fue dejar de ser yo quien sostiene el estado de cada proyecto, y pasarle esa carga a algo que no se olvida.

En la práctica, esto me convirtió a mí en algo parecido a un technical lead, y a SAM en algo parecido a un PM o un PO: yo decido qué se hace, reviso el resultado y doy el veredicto final; SAM coordina a los agentes que escriben el código, y se encarga de acordarse de en qué estado quedó cada rama, cada entorno, cada worktree — la carga cognitiva que antes era mía. El resultado, para mí, es directo: puedo entregar más cosas, más rápido, y sostener varios proyectos a la par sin que cada uno me robe el contexto del anterior.

Creo que es para donde vamos todos, no solo yo. Si el código ya no es el cuello de botella, el rol del desarrollador se corre hacia coordinar, decidir y revisar — y esa coordinación necesita su propia herramienta, tanto como el código necesita la suya.

Qué es SAM, en la práctica

En arquitectura es simple: un dashboard en React, un motor en Node.js, y un sidecar en Python para transcribir voz a texto — así puedo dictarle un ticket en vez de escribirlo. Todo corriendo local en mi máquina con Windows, con git worktrees por ticket y puertos derivados dinámicamente para no pisarme entre entornos de prueba.

Pero lo que importa no es el stack, es el ciclo:

1. Definís el ticket        → de qué se trata, con qué criterio se da por cerrado
2. Un agente lo toma        → worktree propio, tools (leer, editar, bash, navegador real)
3. Reporta al terminar      → resumen estructurado: qué hizo, contra qué criterios, qué quedó abierto
4. SAM levanta el entorno   → healthcheck real, no un timer que asume que si no explotó, anda
5. Vos das el veredicto     → probás de verdad, no confías en la palabra del agente
6. Un solo camino de cierre → merge + borrar rama + limpiar worktree + verificar contra GitHub

Ese "un solo camino de cierre" no es un detalle menor. Antes había varias formas distintas de dar un ticket por terminado — arrastrarlo en el tablero, aprobarlo desde el chat, cerrarlo a mano desde GitHub — y sólo una de esas limpiaba de verdad. Las otras eran fábricas silenciosas de ramas sueltas y PRs sin mergear.

Con quien hablo del otro lado es siempre el mismo SAM, sin importar el contexto: le puedo hablar de un ticket puntual o de todo el portfolio en la misma sesión, y sigue siendo el mismo agente, con el mismo hilo de conversación. El scope cambia — a veces está mirando un ticket, a veces todo el tablero —, pero no hay versiones separadas para cada contexto ni personajes distintos según de qué le hable.

El nombre, dicho sea de paso, no es al azar. Le puse SAM por Samwise Gamgee, el que en El Señor de los Anillos carga a Frodo en los tramos finales, cuando ya no puede caminar solo. Me gustó la imagen de un agente que te carga con vos. No calculé, cuando lo bauticé, que el chiste se iba a volver literal: hoy es, efectivamente, el sistema que me carga a mí, con mi propio trabajo y mi propio quilombo. Sigue siendo, para mí, la mejor descripción de por qué existe esta herramienta.

Cómo está funcionando hoy

El tablero de SAM: columnas por estado, varios agentes trabajando en paralelo, cientos de tickets cerrados Captura ilustrativa, con datos simulados — no es el tablero real de ningún cliente.

El portfolio real hoy son varios clientes, diez productos, diecisiete proyectos. Adentro de eso está Alto Valle Studio — mi propio estudio, con Walletfy y Chequeo como productos —, mi cliente más grande (un distribuidor con sistemas internos y externos, mobile y web), y Cooperativa del Valle, un proyecto ficticio que uso a propósito para estresar casos límite sin arriesgar nada real.

Los números de uso, a la fecha en que escribo esto: cien tickets, ciento cincuenta y pico de sesiones de chat, y más de cien entradas de bitácora y corridas de agente registradas.

Y acá va la anécdota que más vergüenza me dio de todo este proceso: durante meses, la carpeta donde vive todo eso — los tickets, las sesiones, la bitácora, todo — no era un repositorio git. El repo del código de SAM sí lo era, pero explícitamente ignoraba esa carpeta. Hacer git push del código no respaldaba nada del workspace. Si mi disco moría un día cualquiera, se llevaba con él cien tickets y toda la memoria de lo que había pasado, sin backup de ningún tipo.

Lo arreglé en cuanto lo vi: un commit inicial de cerca de 600 archivos, unos 11 MB. Es un error tonto en retrospectiva, pero es exactamente el tipo de cosa que un sistema que usás todos los días te deja pasar por alto — estaba tan ocupado mirando si los tickets se movían bien de columna que no me pregunté dónde vivían.

Después el modelo cambió otra vez. Cuando SAM pasó a ser una herramienta de instancia única, con su home fijo en ~/.sam, el git del workspace dejó de tener sentido y lo reemplacé por algo más tonto — y por eso más difícil de romper: un botón que hace un zip del home entero a una carpeta que ya sincroniza el Drive. Menos elegante que un historial de commits, pero es un backup que no depende de que yo me acuerde de nada.

La idea detrás de todo esto

Tres decisiones se repiten en cada parte del sistema, y son la columna vertebral real de SAM, más allá de cualquier feature puntual.

Punteros, no contenido. El índice central no guarda documentación, guarda referencias a dónde vive esa documentación. Si un producto tiene repo, la fuente de verdad es lo que está escrito en ese repo — SAM sólo mantiene un índice derivado que se regenera. Si no tiene repo (un cliente, un producto que agrupa varias apps), ahí sí SAM es la fuente, porque no hay otro lugar donde esa información pudiera vivir sin duplicarse.

Las apps sobreviven a los repos, no al revés. La jerarquía es Cliente → Producto → App → Repo, con el Repo como entidad aparte, transversal. ¿Por qué? Porque en medio de una migración, una misma app puede vivir literalmente en dos repos a la vez — el viejo achicándose, el nuevo creciendo — y sigue siendo la misma app: mismos usuarios, misma URL de producción, mismo historial. Si modelás App como si fuera lo mismo que Repo, perdés todo eso justo en el momento en que más te importa no perderlo.

Todo lo que puede ensuciarse necesita ciclo de vida y reconciliación, no un cálculo que se recalcula cuando mirás. Es la lección directa del problema de fondo. Un entorno no es un timer que asume que si no explotó, está sano — es un healthcheck real contra el puerto, con estado persistido, que al arrancar se pregunta "¿esto que dice el archivo sigue siendo cierto en el mundo?" antes de confiar en nada.

Y la más simple de las tres, aunque discutible: markdown plano, no base de datos. Cien tickets, unos seiscientos archivos, once megas — la escala no lo pide. Los agentes ya leen markdown nativamente, meter una base ahí es serialización extra sin ganancia real. El respaldo de eso, como conté arriba, hoy no es git — es el zip al Drive. Pero el archivo sigue siendo texto plano legible por cualquiera, con o sin SAM corriendo, que es la parte de la decisión que no cambió.

Lo que no funciona (todavía)

Ser honesto acá me parece más útil que vender un sistema perfecto.

La sesión número 108. El panel de chats se volvió inusable en algún momento, y no por casualidad: cada vez que abrís un ticket que ya está terminado, el sistema fabrica una sesión nueva en vez de reusar una cerrada. El resultado es un panel lateral que crece sin parar y que ya tuve que podar una vez.

Un bug que casi me hace perder trabajo de verdad. En el cierre de un ticket, en cierto modo, el sistema commiteaba los cambios sucios del worktree localmente, pero no los pusheaba. Después mergeaba en GitHub lo que había en el remoto — sin ese commit — y recién ahí borraba la rama local y la remota. El commit con los cambios sin guardar desaparecía en el proceso, a pesar de que el código tenía un comentario que decía literalmente que nada de lo que seguía podía borrar trabajo. Lo encontré leyendo el código con lupa, no porque me hubiera explotado en producción — pero es el tipo de bug que te hace confiar menos en un sistema hasta que lo cerrás del todo.

Sólo un caso de tres está realmente operado. De los tres modos en los que puede estar el entorno de un ticket (desarrollo local con worktree propio, checkout único sin worktree, preview remoto), sólo el primero tiene botones de verdad. Los otros dos son de sólo lectura o directamente no orquestados — y resulta que los dos proyectos que más uso en modo local sin worktree (SAM mismo, y mi cliente más grande) caen justo en el caso que no tiene ni un botón.

Hacia dónde va

El rediseño en curso se puede resumir en tres capas, en orden de dependencia:

Capa de INVENTARIO   → reconcilia contra la realidad, siempre, en background
                        (¿el proceso vive? ¿el puerto responde? ¿qué dice git de verdad?)
Capa de ESTADO        → Runtime, Rama, Pull Request como entidades persistidas,
                        cada una con salud y deuda propia
Capa de ACCIÓN        → un click resuelve: terminal real, merge, limpieza

Un cambio de modelo que me entusiasma en particular: pasar de un worktree por ticket a un worktree por feature (una épica con varios tickets adentro). Hoy, un cliente con cinco features en danza tiene sus cinco tickets serializados contra el mismo checkout. Con un worktree por feature, esas cinco pasan a correr en paralelo de verdad, y yo pruebo la feature entera integrada una sola vez en vez de cinco pedacitos sueltos.

Así se ve hoy el mockup de la pantalla nueva, en la lente que resuelve justamente eso — qué hay para probar, dónde está levantado y cómo se prueba, feature por feature:

Mockup de la pantalla de Dirección, lente Probar: features listas para probar con su entorno levantado, tests automáticos y casos manuales

Y la misma pantalla, en la lente que muestra el portfolio completo agrupado por cliente — la vista que reemplaza tener que abrir quince proyectos para saber cómo viene cada uno:

Mockup de la pantalla de Dirección, lente Portfolio: muro de productos agrupado por cliente Ambas capturas son del mockup navegable, con datos simulados.

Y más adelante, la fase 2: dejar de ser sólo un gestor de tickets para ser una plataforma que además corre lo que esos tickets producen — infraestructura propia, un preview real por worktree, y tickets que puedan nacer de una señal (un funnel que se cae, un error que afecta a varios usuarios) y no sólo de una idea mía escrita a mano.


Lo raro de todo esto es que SAM es, a la vez, la herramienta y el objeto de su propio problema: lo construyo con los mismos agentes que después coordina, en los mismos worktrees que después va a tener que reconciliar contra la realidad. Cada bug que encuentro en el sistema que gestiona mi trabajo es, literalmente, mi próximo ticket de trabajo.

Sigo siendo el único desarrollador de esto, en una PC con Windows, tratando de que la herramienta que uso para no ser el cuello de botella no se convierta ella misma en algo que hay que vigilar a mano. Pero apuesto a que esta forma de trabajar — technical lead más orquestador, en vez de desarrollador haciendo malabares con todo — es donde vamos a terminar la mayoría de los que llevamos varios proyectos a la vez.