Lo que realmente quiere decir "lo construí con IA".
Semana 4 de una serie build-in-public de 10 semanas. Cómo se ve, día a día, trabajar con Claude Code como mi equipo de ingeniería: qué hace él, qué hago yo, y cómo se mueve la línea entre los dos.
La semana pasada dije que la capa de síntesis RAG era uno de los momentos donde Claude Code cargaba con responsabilidad. Era cierto, pero era una parte chica de la verdad. Claude carga con mucha responsabilidad mecanica real en gran parte de este proyecto. También hay mucho que no carga, y la línea entre las dos cosas se mueve todo el tiempo. Este post es sobre cómo se ve trabajar en ese modo, día a día, desde adentro.
Cuatro semanas adentro
Antes de meternos en cualquier otra cosa, esto es donde están parados los agentes después de cuatro semanas de paper-trading. Los mismos 12 agentes de la semana pasada. El mismo modelo compartido detrás de todos. Distintas reglas de sizing y selección. Una semana más de decisiones encima de lo que mostré en el Post 3.

Después de 28 días, 11 de los 12 agentes están en terreno positivo. A través de todo el roster, los agentes settlearon 1.383 picks y skippearon 19.555. Eso es alrededor de 14 skips por cada pick. La pool combinada de paper-money de $12.000 está arriba en $15.657 en agregado. Los agentes aciertan menos veces de las que erran (47,7% sobre los picks ya resueltos), pero el pick ganador promedio es alrededor de 1,5× más grande que el perdedor promedio, así que la matemática igual les juega a favor.
Big Jake es la historia ruidosa otra vez. El resto es la silenciosa. Las dos son reales. La semana pasada la parte de abajo del chart tenía un par de agentes bajo agua con muestras chicas. Esta semana, con siete días más de decisiones y los que arrancaron tarde alcanzando ritmo, solamente Tommy-B sigue en rojo, y por muy poco.
El resto de este post es sobre la relación de trabajo que produjo todo eso.
La forma de la cosa
Dos repos sostienen el experimento. Entre los Claude y yo:
- Alrededor de 75.000 líneas de código. 57 archivos de Python en el motor que corre los agentes simulados, 130 archivos de TypeScript y React en la web app.
- 109 commits entre el 31 de marzo y el 21 de abril.
- 106 de esos 109 terminan con un footer que dice
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>.
Ese footer no está ahí por motivos legales. Está ahí porque el punto del experimento es ver si una sola persona más IA puede hacer el trabajo de un equipo chico. Si esa es la afirmación que estoy haciendo, la única manera de que la afirmación signifique algo es que sea honesto en el git log sobre quién hizo qué. Quiero que el crédito viva en el artefacto, no solamente en el post del blog.
Dónde Claude Code carga con el peso
Cuatro lugares, con ejemplos.
La capa de síntesis RAG. Más o menos 200 líneas de código que envuelven el SDK de Anthropic y hacen análisis de noticias por juego. Tracking de costos, output estructurado, defaults sensatos, manejo de errores. Claude escribió todo eso de una pasada. (El post de la semana pasada es sobre lo que hace esta capa.)
La tabla de decisiones. Veintiocho columnas de Postgres que capturan cada jugada de cada agente en cada juego de cada slate: qué agente, qué juego, la señal estructurada, la señal no estructurada, la decisión, una razón corta en texto libre, y después de que termina el juego, el resultado y el CLV. Yo la diseñé. El schema, las migraciones, las lecturas y escrituras, todo Claude.
El pipeline de features. Seis módulos que computan algo así como 90 cantidades por juego desde MLB Stats API, clima, odds y box scores históricos. Elo con ajustes de pitcher, ventanas de entrenamiento walk-forward, sin lookahead. Yo describí lo que quería. Claude escribió el código que corrió.
Toda la superficie SaaS, construida rápido para fijar el pivot. Esto es lo más importante de la lista y necesita algo de contexto. En el Post 2 llamé al pasaje de un agente con plata real a un juego de agentes sin plata el reset estratégico del proyecto. Un reset así necesita un lugar donde vivir. No tiene sentido anunciar un pivot si el producto nuevo no existe todavía. Así que le di tres días.
Desde un git init el 10 de abril hasta el final del 12 de abril, la app pasó de nada a: auth funcional (Google-only), una página de armado de agente con un coach de IA y un preview en vivo, un dashboard con picks diarios, un leaderboard, comparación scout vs scout, historial de picks, tarjetas compartibles con imágenes OG dinámicas, billing de Stripe con webhooks y customer portal, una capa anti-abuso (device fingerprinting más bloqueo de emails desechables más rate-limits por IP), CCPA, FTC click-to-cancel, cumplimiento del EU AI Act Artículo 50, un pipeline de CI con tests unitarios y e2e, y los diecisiete commits chicos de fixes en el medio. El que más cariño le tengo: "fix: trim Stripe API key to prevent newline in header."
Cuarenta y un commits en tres días. La decisión estratégica fue mía. La ejecución fue de un co-autor. Ninguna de las dos cosas pasa sin la otra.
Dónde el peso lo cargo yo
Cuatro lugares, igual de concretos.
La idea, y los movimientos estratégicos abajo de ella. La premisa de todo esto — baseball, agentes que aprenden con el tiempo, una arena gamificada en vez de una suscripción de picks, la tesis de que una persona más IA puede hacer el trabajo de un equipo chico — es mía. El pivot de agente con plata real a juego sin plata real (Post 2) fue una decisión que tomé después de semanas de correr el agente sobre paper-money y de leer lo suficiente de gaming-law como para entender en qué superficie estaba parado. Un modelo no hace esos movimientos. Un modelo también los puede hacer descarrilar si lo dejás optimizar por "best practice" en vez de por lo correcto para este proyecto puntual.
La arquitectura. La decisión de correr todo el back-end como una sola base Postgres y un solo proceso Python sobre Railway, sin microservicios, sin colas, sin workers, es mía. La decisión de construir la inteligencia del agente en dos mitades, un modelo estructurado más un LLM no estructurado que la mayor parte del tiempo se queda callado, es mía. Y también lo es la capa de memoria: una tabla indexada por vectores que guarda cada decisión de cada agente, picks y skips, para que cada agente pueda aprender de su propia historia, y algún día de la historia de los otros agentes del roster. Claude escribió el código de todo eso. Yo escribí los design memos que hicieron que el código fuera necesario.
Decisiones de vendor y trade-offs bajo presión. A mediados de abril, FanGraphs empezó a devolver errores 403 sobre IPs de cloud. El modelo que estaba entrenando dependía de FanGraphs. El mensaje del commit del fix dice, palabra por palabra:
Replace FanGraphs with MLB Stats API for batting and pitching data. FanGraphs blocks cloud IPs with 403. MLB Stats API is free, no auth, no IP restrictions, and returns all 30 teams in one call. Computed stats: FIP from raw components, wRC+ approximation from OPS+ style formula, K%/BB%/ISO from counting stats.
Claude escribió ese swap. La decisión de hacer el swap en vez de pagar por FanGraphs enterprise fue mía. La decisión de re-entrenar el ensemble sobre el feature set nuevo en vez de mandarlo a producción con NaNs en las columnas de batting fue mía. El criterio sobre cuánta accuracy estaba dispuesto a resignar fue mío. Esos diagnósticos de un párrafo con una dirección al final son la parte que tengo que producir yo, antes de que se escriba una línea de código.
Nomenclatura del producto, gusto, y decir que no. Las palancas del armado de agente se llaman Swing Size, The Leash, Tap Out Tolerance, Cherry Pickerness y Swagerness. Esos nombres salieron de mí. Son el tipo de criterio — qué es jugado, qué es claro, qué se lee como un producto real y no como un proyecto de ingeniería — que no creo que una IA deba estar tomando, por lo menos no en este proyecto y no en esta voz. Y lo mismo aplica para la cosa más útil que hago la mayoría de los días, que es decir que no a ideas. Una parte del no es gusto: eso no es el producto. Una parte es secuencia: esa es la idea correcta dentro de tres meses, no hoy. Una parte es ser honesto sobre el alcance: no tengo el ancho de banda para una tercera superficie. Claude es excelente en cómo una vez que está decidido el qué. El qué sigue siendo mío.
Dos reglas operativas a las que llegué
Trabajar en este modo a esta escala me dejó dos reglas simples que ahora trato como importantes.
Decile lo que no sabe. El repo de la app tiene un archivo AGENTS.md en la raíz. Dice, completo:
This is NOT the Next.js you know. This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in node_modules/next/dist/docs/ before writing any code. Heed deprecation notices.Ese párrafo corto me ahorra horas por semana. Claude Code está entrenado sobre una foto del mundo. El mundo siguió de largo. La foto está equivocada sobre las cosas más comunes primero, que es la peor combinación posible. El fix no es discutirle al modelo después de que confiadamente escribió código viejo. El fix es decirle, antes de que escriba una línea, dónde su data de entrenamiento está vieja y dónde encontrar la verdad en su lugar.
Límites de confianza por repo. Cada repo tiene su propio .claude/settings.local.json que pre-aprueba una lista específica de patrones de shell y de tools. El repo del motor de agentes confía en el CLI de Railway y un par de dominios para research-fetch. El repo de la app confía en el CLI de Vercel, en las migraciones de Prisma, en los npm install, y en un set chico de operaciones de git. Ninguno de los dos confía en los tools del otro. Ninguno de los dos confía en nada destructivo sin que yo esté en el loop.
"Darle tools a la IA" y "darle mis tools a la IA" son dos frases muy distintas. Quiero que el modelo corra con el set más chico de permisos que igual deje hacer el trabajo. Cinco minutos para escribir esa lista de permitidos me compran mucha paz mental. La separación por repo además significa que si Claude trata de usar un tool desconocido en el contexto equivocado, me sale un prompt en vez de una ejecución silenciosa.
El efecto compuesto, y su costo
Una cosa sobre este tipo de velocidad: compone en direcciones que no presupuestaste.
Tres días de trabajo de compliance, en el orden equivocado, me hubieran llevado tres semanas. Con un co-autor que puede leer la FTC Negative Option Rule y convertirla en un cron schedule, me llevó tres días. Esa es la parte buena.
La parte mala es que esos tres días de compliance igual tuvieron que pasar. La superficie legal y regulatoria de una SaaS de consumo, aunque sea gratis, aunque sea un side project que estoy haciendo con presupuesto de finanzas personales, es más grande de lo que esperaba. Cada capa que iba encontrando era su propia sorpresa. Eso es el post de la semana que viene.
Por qué importa el footer
No quiero que nadie que lea esta serie se vaya pensando que construí un sistema de 75.000 líneas en cinco semanas yo solo. No fue así. Lo construí con un modelo. El modelo escribió mucho del código. Yo escribí el diseño, las decisiones de arquitectura, los prompts, los "no", y el puñado chico de momentos donde el proyecto vive o muere. El git log dice exactamente eso en casi cada commit, en un formato que cualquiera con un git blame puede chequear por su cuenta.
Esa es la parte de este experimento sobre la que estoy más comprometido a ser honesto. La tesis solamente significa algo si la contabilidad abajo de ella es real.
La semana que viene
El Post 5 es la superficie legal y de compliance que no vi venir. El pasaje de plata real a sin plata, la cercanía con gaming-law, las preguntas de IP y de propiedad cuando la IA está en el loop, y las sorpresas puntuales que se comieron esa semana de compliance de abril.
Si trabajaste en este modo y trazarías la línea en un lugar distinto al que la tracé yo, me gustaría escucharlo.
Anteriormente en esta serie: Semana 1 — la génesis · Semana 2 — el pivot (las pruebas) · Semana 3 — la data stack.
Estas son notas personales de un side project que hago en mi tiempo libre con mis propios recursos. Las opiniones acá son mías y no están conectadas, ni endosadas, ni representan a mi empleador ni ninguna parte de mi trabajo profesional.