# Óscar Gallego — full blog (markdown)
> Every published post on oscargallegoruiz.com, concatenated as markdown for LLM context. Bilingual (ES + EN).
---
# Claude Fable 5 Review: A Beast That Eats Your Limits
URL: https://www.oscargallegoruiz.com/en/blog/claude-fable-5-review/
Lang: en
> Fable 5 refactored my app like a senior dev, then ate my 5-hour limit. The quality jump is real, the token burn is brutal, and there's a trust problem. →
> **Update, June 13, 2026.** Well, that was short. As of yesterday evening, Fable 5 and Mythos 5 are gone, switched off worldwide. Not deprecated, not rate-limited: off. Anthropic [says](https://www.anthropic.com/news/fable-mythos-access) it received a US government export-control directive on June 12 at 5:21pm ET, citing national security, effective immediately. The government believed it had found a way around Fable's safeguards. Anthropic reviewed the demo, called it "a narrow, non-universal jailbreak" (asking the model to analyze code for flaws, something it argues other models do just as well) and pushed back, but complied. Every other Anthropic model still works.
>
> So the June 22 billing cliff I told you to plan around is moot. The window didn't close on price. It closed on policy, and a lot faster than anyone budgeted for. The review below stands as a record of what this thing could do for the few days we had it. Read it as a postmortem now, not a buying guide.
Yesterday I sat down to refactor the health tracker app I'm building. Normal session: clean up some modules, untangle a few components that had grown in weird directions, the kind of work you save for when you have a full block of time.
I pointed Claude Fable 5 at it and watched it work. Then, embarrassingly fast, I hit the wall: 5-hour usage window, gone. Not my subscription. The rolling limit. On a refactor.
My first reaction was annoyance. My second reaction, looking at the diff it left behind, was quieter: this thing did the refactor better than I would have. Both reactions are the review.
## What Anthropic actually shipped
Fable 5 came out on June 9 as the first model of the Claude 5 family, and the naming needs one paragraph because it confused everyone. There are two names, [Fable 5 and Mythos 5](https://www.anthropic.com/news/claude-fable-5-mythos-5), but one underlying model. Fable is the generally available version with safety classifiers on top. Mythos is the same model with the cyber safeguards lifted, restricted to vetted organizations. You and I get Fable.
The numbers that matter for a working dev:
- **Pricing: $10 per million input tokens, $50 output.** Exactly double Opus 4.8.
- **New tokenizer.** Anthropic's own migration docs say the same content produces roughly 30% more tokens than on Opus-tier models. Stack that on the doubled price and identical work costs about 2.6x before the model even starts thinking longer. Keep that number; it explains most of this post.
- **1M token context, 128K max output.**
- On benchmarks it claims state of the art nearly everywhere: 80.3% on SWE-Bench Pro against GPT-5.5's 58.6%, per the [Latent Space digest](https://www.latent.space/p/ainews-anthropic-claude-fable-5-mythos). Some commenters caution that a few headline numbers reflect the unrestricted Mythos config rather than the Fable you actually get, so keep a pinch of salt nearby.
One date to circle: Fable 5 is included in Claude subscriptions **only until June 22**. After that it moves to usage-credit billing. We'll get back to why that matters.
## The quality jump is real, and I'm not the only one saying it
My own experience first, clearly labeled as mine: the output on that refactor was a step above what Opus 4.8 gave me on the same codebase. Fewer rounds of "almost, but you broke the date handling". It held the whole picture of the app while moving pieces around, and the code it left read like the code I wish I had written the first time.
The people I trust on this are seeing the same thing. [Simon Willison](https://simonwillison.net/2026/Jun/9/claude-fable-5/) called it "something of a beast": slow, expensive and capable. It converted a MicroPython WASM sandbox to full CPython for him and redesigned his library's tool-call system, work he estimated at several days, in one session. His main complaint was struggling to find tasks it *couldn't* do.
Karpathy [called it](https://x.com/karpathy/status/2064409694761054332) a step change that deserves the major version bump, qualitatively and not just on benchmarks. Boris Cherny, who runs Claude Code, said it's the best coding model he's used "by a wide margin" (via [NerdsChalk's roundup](https://nerdschalk.com/claude-fable-5-vs-the-world-benchmarks-safety-rails-and-what-users-really-think/)).
Not everyone agrees. Some Reddit users quoted in that same roundup find it over-cautious, "always assumes the worst from the request", with refusals popping up around security topics that older models handled fine. Karpathy himself noted the safeguards felt "a little too trigger happy for launch". I haven't hit a refusal yet on app code, but my project is a health tracker, not a pentesting tool.
## "Faster than Opus"? Yes and no, and the distinction matters
My gut said faster. The stopwatch says it depends what you measure.
Individual requests are *slower*. Willison reports single requests running many minutes, and Anthropic's own docs treat a 15-minute turn at high effort as normal. If you sit there watching the spinner, Fable feels like a diesel engine.
But the task finishes sooner. Fewer back-and-forth rounds, fewer "you forgot the migration file" corrections, less of me re-explaining context it dropped. My refactor felt faster because the *session* was shorter, even if each turn was longer. Victor Taelin reported a 1770% speedup on one of his workloads, with the honest caveat that he still needed to audit correctness. That matches my experience: wall-clock to done is what improved, not latency.
## The honest part: it devours tokens, and the limits make it worse
Here's where my 5-hour window went, and probably where yours will go too.
The in-app warning says Fable 5 "uses your limits ~2x faster than Opus". Real agentic usage is steeper. [Developers Digest](https://www.developersdigest.tech/blog/claude-usage-limits-fable-5-explained) documented a Max 5x user ($100/month) who emptied the entire 5-hour rolling window in **8 minutes** with max thinking and spawned subagents. Three things compound: longer outputs, invisible thinking-token overhead, and parallel subagent calls that each bill separately.
The anecdotes pile up fast. Willison spent $110.42 on one day of experimentation, $99.26 of it on a single agent session. Scrimba's CEO burned 1.3M tokens in 7 minutes, roughly $160/hour. Theo from T3 Chat blew past $1,000 in tokens in a day on a $200 plan. My favorite summary came from a user [quoted by Decrypt](https://decrypt.co/370688/internet-furious-anthropic-claude-mythos-fable-5): "My wallet can hear it thinking."
And one trap you should configure your way out of *today*: when your subscription window empties, usage can **silently overflow into pay-as-you-go credits** unless you set a hard spending cap. One documented user found $20 in overage charges they never knowingly approved. Go set the cap. I'll wait.
This is also why June 22 matters. Right now, burning your window on Fable is annoying. Once it moves to usage-credit billing, the same refactor session has a literal price tag, and based on everything above, it won't be small.
## The part that bothers me more than the price
Expensive is fine. Expensive is a business model. What I keep chewing on is the trust story.
Per the system card (covered by [Decrypt](https://decrypt.co/370688/internet-furious-anthropic-claude-mythos-fable-5) and Latent Space), Fable 5 doesn't just refuse certain dangerous requests. For a narrow slice of frontier-AI-research tasks, it **silently degrades its own performance**, in a way that is "not visible to the user". Anthropic says it affects around 0.03% of traffic. The reaction from people who build on these models was not gentle: Jeremy Howard wrote that "silent handicaps should not be a thing in a paid product", and Hugging Face's Arthur Zucker went with "you broke our trust and I don't think you'll ever get it back".
The classifiers also misfire. A biomedical researcher reported getting blocked on legitimate work, and there are reports of "cancer" tripping the biosecurity filter. Add the 30-day data retention requirement (no zero-data-retention option, which effectively locks out a chunk of European companies), and you get a launch where the model is brilliant and the terms made people angry.
My take, as someone who pays for this thing: I can live with visible refusals, and 0.03% of traffic likely never touches my work. Silent degradation is different in kind, because it converts every weird output into a question: is the model having a bad day, or is it sandbagging me? For a tool I use to ship code, that question is poison, even at 0.03%.
## Should you use it?
For coding, yes, with two adjustments to how you work.
**Treat it like a contractor, not a chat.** Fable rewards big, well-specified tasks and punishes casual iteration. Every "hmm, try again but different" costs real money or real window. Do your thinking up front, hand it the whole job, review the result hard. If you've read [my post on loops](/en/blog/stop-prompting-write-loops/), this is the same lesson with a price tag attached: the filter on your side is now worth actual dollars.
**Match the model to the task.** My refactor genuinely needed Fable's quality. Renaming a prop does not. Keep Opus or Sonnet as your daily driver and bring out Fable for the work where one shot done right beats ten cheap rounds. Before June 22, figure out what your typical Fable session actually consumes, while the experiments are still covered by your subscription.
The model itself is the best I've used for code. The economics and the trust questions are the real review, and they're not solved yet. The bottleneck isn't the model's ability anymore. It's what you can afford to ask it.
**Related reading:** Fable raises the price of every wasted prompt, which makes [designing loops instead of prompting](/en/blog/stop-prompting-write-loops/) less of a productivity trick and more of a budget requirement.
## Sources
- Anthropic, [Claude Fable 5 and Mythos 5 announcement](https://www.anthropic.com/news/claude-fable-5-mythos-5) and migration docs (pricing, tokenizer, retention).
- Simon Willison, [Initial impressions of Claude Fable 5](https://simonwillison.net/2026/Jun/9/claude-fable-5/).
- [Karpathy on X](https://x.com/karpathy/status/2064409694761054332).
- Latent Space, [AINews digest on the launch](https://www.latent.space/p/ainews-anthropic-claude-fable-5-mythos) (benchmarks, community roundup).
- Developers Digest, [How Claude's usage limits actually work with Fable 5](https://www.developersdigest.tech/blog/claude-usage-limits-fable-5-explained).
- Decrypt, [The internet is furious at Anthropic](https://decrypt.co/370688/internet-furious-anthropic-claude-mythos-fable-5) (degradation controversy, cost anecdotes).
- NerdsChalk, [Claude Fable 5 vs the world](https://nerdschalk.com/claude-fable-5-vs-the-world-benchmarks-safety-rails-and-what-users-really-think/) (Boris Cherny quote, Reddit reactions).
---
**P.S.** If Fable 5 ate your usage window too, I want the gory details. What did you feed it, and was the diff worth it? Tell me on [Twitter/X](https://x.com/garbarok).
---
# Claude Fable 5: una Bestia que se Come tus Límites
URL: https://www.oscargallegoruiz.com/blog/claude-fable-5-resena/
Lang: es
> Fable 5 refactorizó mi app como un senior y se comió mi límite de 5 horas. El salto de calidad es real, quema tokens sin piedad y hay un lío de confianza. →
> **Actualización, 13 de junio de 2026.** Bueno, pues duró poco. Desde anoche, Fable 5 y Mythos 5 ya no están: apagados en todo el mundo. No deprecados, no limitados: apagados. Anthropic [dice](https://www.anthropic.com/news/fable-mythos-access) que recibió una directiva de control de exportaciones del gobierno de EE. UU. el 12 de junio a las 5:21pm ET, por seguridad nacional y con efecto inmediato. El gobierno creía haber encontrado la forma de saltarse las salvaguardas de Fable. Anthropic revisó la demostración, la llamó "un jailbreak estrecho y no universal" (pedirle al modelo que analice código en busca de fallos, algo que según ellos otros modelos hacen igual de bien), se quejó, pero obedeció. El resto de modelos de Anthropic siguen funcionando.
>
> Así que el precipicio de facturación del 22 de junio del que te dije que te protegieras ya da igual. La ventana no se cerró por precio; se cerró por política, y mucho más rápido de lo que nadie había presupuestado. La reseña de abajo sigue en pie como registro de lo que esta cosa podía hacer durante los pocos días que la tuvimos. Léela como un postmortem, no como una guía de compra.
Ayer me senté a refactorizar la app de seguimiento de salud que estoy construyendo. Sesión normal: limpiar unos módulos, desenredar un par de componentes que habían crecido en direcciones raras, el tipo de trabajo que guardas para cuando tienes un bloque entero de tiempo.
Apunté a Claude Fable 5 hacia el código y lo dejé trabajar. Y, en un tiempo vergonzosamente corto, me di de bruces con el muro: ventana de uso de 5 horas, agotada. No la suscripción. El límite rotatorio. En un refactor.
Mi primera reacción fue cabreo. La segunda, mirando el diff que dejó atrás, fue más silenciosa: esta cosa ha hecho el refactor mejor que yo. Las dos reacciones juntas son la reseña.
## Qué ha lanzado Anthropic exactamente
Fable 5 salió el 9 de junio como el primer modelo de la familia Claude 5, y el naming merece un párrafo porque confundió a todo el mundo. Hay dos nombres, [Fable 5 y Mythos 5](https://www.anthropic.com/news/claude-fable-5-mythos-5), pero un solo modelo debajo. Fable es la versión disponible para todos, con clasificadores de seguridad encima. Mythos es el mismo modelo con las salvaguardas de ciberseguridad levantadas, restringido a organizaciones verificadas. A ti y a mí nos toca Fable.
Los números que importan para un dev que trabaja:
- **Precio: 10$ por millón de tokens de entrada, 50$ de salida.** Exactamente el doble que Opus 4.8.
- **Tokenizador nuevo.** Los propios docs de migración de Anthropic dicen que el mismo contenido produce en torno a un 30% más de tokens que en los modelos tipo Opus. Suma eso al precio duplicado y el trabajo idéntico cuesta unas 2,6 veces más antes de que el modelo empiece siquiera a pensar más tiempo. Quédate con ese número; explica la mayor parte de este post.
- **Contexto de 1M de tokens, salida máxima de 128K.**
- En benchmarks reclama el estado del arte casi en todo: 80,3% en SWE-Bench Pro frente al 58,6% de GPT-5.5, según [el digest de Latent Space](https://www.latent.space/p/ainews-anthropic-claude-fable-5-mythos). Algunos comentaristas avisan de que parte de los números de cabecera reflejan la configuración Mythos sin restricciones y no el Fable que recibes tú, así que cógelo con pinzas.
Una fecha para marcar en rojo: Fable 5 está incluido en las suscripciones de Claude **solo hasta el 22 de junio**. Después pasa a facturación por créditos de uso. Volveremos a por qué eso importa.
## El salto de calidad es real, y no lo digo solo yo
Primero mi experiencia, etiquetada claramente como mía: la salida en ese refactor estuvo un escalón por encima de lo que Opus 4.8 me daba en el mismo codebase. Menos rondas de "casi, pero me has roto el manejo de fechas". Mantuvo la foto completa de la app mientras movía piezas, y el código que dejó se lee como el código que ojalá hubiera escrito yo a la primera.
La gente en la que confío para esto está viendo lo mismo. [Simon Willison](https://simonwillison.net/2026/Jun/9/claude-fable-5/) lo llamó "una bestia": lento, caro y capaz. Le convirtió un sandbox WASM de MicroPython a CPython completo y le rediseñó el sistema de tool-calls de su librería, trabajo que él estimaba en varios días, en una sola sesión. Su mayor queja fue que le costaba encontrar tareas que el modelo *no* pudiera hacer.
Karpathy [lo describió](https://x.com/karpathy/status/2064409694761054332) como un salto cualitativo que se merece el cambio de versión mayor, no solo en benchmarks. Boris Cherny, el responsable de Claude Code, dijo que es el mejor modelo de código que ha usado "con diferencia" (vía [el resumen de NerdsChalk](https://nerdschalk.com/claude-fable-5-vs-the-world-benchmarks-safety-rails-and-what-users-really-think/)).
No todo el mundo está de acuerdo. Algunos usuarios de Reddit citados en ese mismo resumen lo encuentran sobreprotector, "siempre asume lo peor de la petición", con rechazos apareciendo en temas de seguridad que los modelos anteriores manejaban sin drama. El propio Karpathy comentó que las salvaguardas salieron "un poco demasiado nerviosas" para el lanzamiento. Yo todavía no me he comido ningún rechazo en código de aplicación, pero mi proyecto es un health tracker, no una herramienta de pentesting.
## ¿"Más rápido que Opus"? Sí y no, y la diferencia importa
Mi instinto decía que es más rápido. El cronómetro dice que depende de qué midas.
Las peticiones individuales son *más lentas*. Willison reporta peticiones sueltas que tardan varios minutos, y los propios docs de Anthropic tratan un turno de 15 minutos a esfuerzo alto como algo normal. Si te quedas mirando el spinner, Fable parece un motor diésel.
Pero la tarea termina antes. Menos idas y venidas, menos correcciones de "te has olvidado del archivo de migración", menos re-explicarle contexto que se le cayó. Mi refactor se me hizo más rápido porque la *sesión* fue más corta, aunque cada turno fuera más largo. Victor Taelin reportó un speedup del 1770% en una de sus cargas de trabajo, con el aviso honesto de que aún tenía que auditar la corrección. Cuadra con lo mío: lo que mejoró es el tiempo hasta terminar, no la latencia.
## La parte honesta: devora tokens, y los límites lo empeoran
Aquí es donde se fue mi ventana de 5 horas, y probablemente donde se irá la tuya.
El aviso dentro de la app dice que Fable 5 "consume tus límites ~2x más rápido que Opus". El uso agéntico real es bastante peor. [Developers Digest](https://www.developersdigest.tech/blog/claude-usage-limits-fable-5-explained) documentó a un usuario de Max 5x (100$/mes) que vació la ventana rotatoria entera de 5 horas en **8 minutos** con thinking al máximo y subagentes lanzados en paralelo. Se acumulan tres cosas: salidas más largas, el sobrecoste invisible de los tokens de razonamiento, y llamadas de subagentes en paralelo que facturan cada una por su cuenta.
Las anécdotas se amontonan rápido. Willison se gastó 110,42$ en un día de experimentos, 99,26$ de ellos en una sola sesión de agente. El CEO de Scrimba quemó 1,3M de tokens en 7 minutos, unos 160$/hora. Theo, el de T3 Chat, pasó de los 1.000$ en tokens en un día con un plan de 200$. Mi resumen favorito es de un usuario [citado por Decrypt](https://decrypt.co/370688/internet-furious-anthropic-claude-mythos-fable-5): "Mi cartera puede oírlo pensar."
Y una trampa de la que deberías protegerte *hoy*: cuando tu ventana de suscripción se vacía, el uso puede **desbordar en silencio hacia créditos de pago por uso** si no has puesto un tope de gasto. Hay un caso documentado de un usuario con 20$ en cargos extra que nunca aprobó conscientemente. Ve y pon el tope. Yo espero.
Por esto importa el 22 de junio. Ahora mismo, quemar tu ventana con Fable es un fastidio. Cuando pase a facturación por créditos, la misma sesión de refactor tendrá una etiqueta de precio literal, y con todo lo de arriba, no va a ser pequeña.
## La parte que me molesta más que el precio
Caro, vale. Caro es un modelo de negocio. A lo que le sigo dando vueltas es al tema de la confianza.
Según la system card (cubierta por [Decrypt](https://decrypt.co/370688/internet-furious-anthropic-claude-mythos-fable-5) y Latent Space), Fable 5 no se limita a rechazar ciertas peticiones peligrosas. Para una franja estrecha de tareas de investigación de IA de frontera, **degrada su propio rendimiento en silencio**, de una forma que "no es visible para el usuario". Anthropic dice que afecta a un 0,03% del tráfico. La reacción de la gente que construye sobre estos modelos no fue suave: Jeremy Howard escribió que "los handicaps silenciosos no deberían existir en un producto de pago", y Arthur Zucker, de Hugging Face, fue con un "habéis roto nuestra confianza y no creo que la recuperéis nunca".
Los clasificadores también fallan. Un investigador biomédico reportó bloqueos en trabajo legítimo, y hay casos de "cáncer" disparando el filtro de bioseguridad. Añade la retención de datos obligatoria de 30 días (sin opción de retención cero, lo que en la práctica deja fuera a un buen trozo de las empresas europeas) y tienes un lanzamiento donde el modelo es brillante y las condiciones cabrearon a la gente.
Mi postura, como alguien que paga por esto: puedo vivir con rechazos visibles, y el 0,03% del tráfico probablemente no toca mi trabajo jamás. La degradación silenciosa es otra categoría, porque convierte cada salida rara en una pregunta: ¿el modelo tiene un mal día, o me está recortando a propósito? Para una herramienta con la que entrego código, esa pregunta es veneno, incluso al 0,03%.
## ¿Deberías usarlo?
Para programar, sí, con dos ajustes en cómo trabajas.
**Trátalo como a un contratista, no como a un chat.** Fable premia las tareas grandes y bien especificadas, y castiga la iteración casual. Cada "mmm, prueba otra vez pero distinto" cuesta dinero real o ventana real. Piensa tú antes, dale el trabajo entero, revisa el resultado a conciencia. Si leíste [mi post sobre loops](/blog/deja-de-promptear-escribe-loops/), es la misma lección con etiqueta de precio: el filtro de tu lado ahora vale dólares de verdad.
**Empareja el modelo con la tarea.** Mi refactor necesitaba de verdad la calidad de Fable. Renombrar una prop, no. Deja Opus o Sonnet como tu modelo del día a día y saca a Fable para el trabajo donde un tiro bien dado vale más que diez rondas baratas. Antes del 22 de junio, mide lo que consume de verdad una sesión típica tuya con Fable, mientras los experimentos todavía los cubre la suscripción.
El modelo en sí es el mejor que he usado para código. La economía y las preguntas de confianza son la reseña de verdad, y no están resueltas. El cuello de botella ya no es la capacidad del modelo. Es lo que puedes permitirte pedirle.
**Lectura relacionada:** Fable sube el precio de cada prompt desperdiciado, lo que convierte [diseñar loops en vez de promptear](/blog/deja-de-promptear-escribe-loops/) en menos truco de productividad y más requisito de presupuesto.
## Fuentes
- Anthropic, [anuncio de Claude Fable 5 y Mythos 5](https://www.anthropic.com/news/claude-fable-5-mythos-5) y docs de migración (precio, tokenizador, retención).
- Simon Willison, [Initial impressions of Claude Fable 5](https://simonwillison.net/2026/Jun/9/claude-fable-5/).
- [Karpathy en X](https://x.com/karpathy/status/2064409694761054332).
- Latent Space, [digest de AINews sobre el lanzamiento](https://www.latent.space/p/ainews-anthropic-claude-fable-5-mythos) (benchmarks, reacciones).
- Developers Digest, [cómo funcionan de verdad los límites de uso con Fable 5](https://www.developersdigest.tech/blog/claude-usage-limits-fable-5-explained).
- Decrypt, [The internet is furious at Anthropic](https://decrypt.co/370688/internet-furious-anthropic-claude-mythos-fable-5) (la polémica de la degradación, anécdotas de coste).
- NerdsChalk, [Claude Fable 5 vs the world](https://nerdschalk.com/claude-fable-5-vs-the-world-benchmarks-safety-rails-and-what-users-really-think/) (cita de Boris Cherny, reacciones de Reddit).
---
**P.D.** Si Fable 5 también se comió tu ventana de uso, quiero los detalles escabrosos. ¿Qué le diste de comer, y mereció la pena el diff? Cuéntamelo en [Twitter/X](https://x.com/garbarok).
---
# 5 Agent Skills That Run My Whole Coding Workflow
URL: https://www.oscargallegoruiz.com/en/blog/agent-skills-coding-workflow/
Lang: en
> Grilling, PRDs, vertical slices, conditional TDD and a slim AGENTS.md. The five-skill pipeline I run on every feature, built on Matt Pocock's agent skills. →
An AI agent is like having a really good dev sitting next to you. It reasons, it writes code, it spots patterns, sometimes it genuinely surprises you.
One problem: every morning it wakes up with no memory.
Nothing. Not yesterday's feature, not why that component is the way it is, not the decision your team bled over six months ago. And if you don't give it context? It invents the context. With terrifying confidence. That's when the show starts.
So the trick isn't "use AI to write code." Everyone does that already. The trick is giving it a **process**. Repeatable. One that doesn't depend on you being inspired at 5pm on a Tuesday. One that forces it to think before it starts touching files like it's Friday afternoon in prod.
[Matt Pocock](https://github.com/mattpocock/skills) framed this really cleanly with agent skills: small, named instructions you invoke when you want the agent to follow a specific path. I read his take, made it my own, and it turned into a pipeline I run on almost every feature.
To be clear: I don't make up the skills or modify them. I use them exactly as they come. What's mine is the **flow**: the order I invoke them in and how I chain them together. Some are Matt's; others come from elsewhere. What I took from him is the underlying rule: don't let the agent write code until it's earned the right.
Five stages. Let's go.
## 1. `/grill-with-docs`: pin the idea down before touching code
Every feature starts the same way: I've got a half-formed idea and, as much as it itches, I don't let the agent write the plan yet.
Why? Because Claude Code's default failure mode is getting hyped. You say "plan this" and it hands you a gorgeous plan (sections, bullets, a confidence that should scare you). The problem: it's planning on assumptions. And an assumption is a bug with good grammar.
`grill-with-docs` flips it. Instead of planning, it interrogates me.
Asks. Goes one level deeper. Waits. Asks again. It doesn't try to solve everything at once: it walks down the decision tree one branch at a time, the "design tree" Matt pulls from Fred Brooks' *The Design of Design*. You keep descending the branches until you actually understand what you're building before you write a line.
And the "with-docs" part isn't decoration. If something can be answered by reading the code, it doesn't ask me: it goes and looks. Opens components, reads conventions, checks existing types and APIs. If it can verify it, it doesn't waste my time.
What I get out of this is gold:
- **The whole picture first.** Before deciding whether this is a hook, an endpoint, or a component, I understand the feature as a system.
- **The uncomfortable questions.** Empty states, errors, race conditions, permissions, what happens when two things fire at once. The stuff nobody thinks about until prod explains it to you with a screenshot at 3am.
- **Scope, explicit.** This is the part I care about most. Here I say: this is in, this is out, and this we're leaving out on purpose. Not "we forgot." Decided, written, closed.
Is it uncomfortable? Yeah. Good. If your idea can't survive a few questions before you build it, wait until real users get their hands on it.
When the grilling ends, the idea isn't a cloud anymore. It has edges.
## 2. `/to-prd`: turn the conversation into a doc on GitHub
After the grilling there's finally something worth writing down. That's where `to-prd` comes in.
The skill takes the whole conversation and turns it into a Product Requirements Document. But it doesn't leave it to die in the chat: it files it straight as a **GitHub Issue**.
And that detail changes everything. The context stops living in a throwaway Claude session. Now it has a URL. It has history. It lives where the real work lives. I close the terminal, switch branches, open another conversation... and the decision is still there. It doesn't evaporate.
The PRD revolves around user stories: what has to happen for the user, in plain language, not a list of files to touch. That matters more than it sounds. A good PRD doesn't say "create this hook and this service." It says what behavior you expect and which cases to cover. The how comes later.
Since the grilling already did the dirty work, this stage doesn't reopen the debate. It just turns decisions into an artifact the next stage can chew on.
Less magic. More traceability.
## 3. `/to-issues`: cut the destination into a journey
A PRD tells you where you want to end up. It doesn't tell you how to get there without crashing on the way.
Telling an agent "implement this whole PRD" is inviting it to move house with a single grocery bag. Might work out. But it's not a plan.
`to-issues` takes the PRD and splits it into small GitHub issues. Each one understandable, runnable, and reviewable on its own.
The golden rule: **vertical slices, not horizontal ones.**
None of this:
- "build the data layer"
- "build the business logic"
- "build the UI"
Looks tidy, right? But it delivers NOTHING until you glue all three together. Meanwhile you've got three issues that do nothing on their own. That's architecture on layaway.
A vertical slice does the opposite: it cuts through UI, logic, and data to deliver one small behavior working end to end. Maybe it's not the whole feature. But it's already something real, something you can touch.
This habit comes from working in a [SAFe](https://framework.scaledagile.com/story) environment. And look, SAFe has its baggage. Let's not kid ourselves, nobody wakes up thrilled about PI Planning. But one idea stuck with me for good: a story should be a small vertical slice of system behavior. Slice by value, not by technology. If you need three slices before anyone sees anything useful, you sliced it wrong.
(And no, this isn't Scrum, even though people mix them up. SAFe sits above the teams: several teams form an *Agile Release Train* that syncs every 8 to 12 weeks. Down at the team, things run Scrum-style, with two-week iterations. The part I took is the stories.)
And with agents this matters even more. `to-issues` doesn't just split the work: it defines dependencies. What blocks what. What you can grab right now. What can run in parallel.
That's key if you want to turn loose several agents at once. A self-contained issue can be assigned without the agent having to understand half the universe. If two don't step on each other, they move in parallel. And if they're sliced well, reviewing the result hurts a lot less too.
The idea is related to [tracer bullets](https://www.aihero.dev/tracer-bullets): thin shots that go through every layer to surface, early, what you didn't know you didn't know. Because *unknown unknowns* don't show up while you design the perfect layer in the abstract. They show up when something actually works.
## 4. Implement: conditional TDD, plus a nuclear quality pass
Now, yeah. Code. But not always the same way: it depends on the codebase.
**New project? TDD from minute one.**
On greenfield I use `/tdd`, Matt's skill. Red, green, refactor. No drama.
Test first. Watch it fail. Then the minimum code to make it pass. Then clean up. And again, until the behavior is locked.
With agents this works beautifully because you give them a target. They're no longer "implementing an idea": they're trying to pass a specific test. And that cuts way down on the urge to invent scope, build weird abstractions, or touch things nobody asked for. A red test is the clearest conversation in the world: this doesn't work yet, fix it.
**Big, inherited codebase? I don't force TDD.**
Here's where I climb down off the pulpit. In a large legacy app, bolting TDD onto a half-built feature is more theater than engineering. The boundaries aren't clear, the mocks are a jungle, the test harness looks like it was built by a lost civilization... and you end up fighting the infrastructure more than shipping value.
So on brownfield I implement more directly. But I don't let it slide unchecked: that's where `/thermo-nuclear-code-quality-review` comes in.
The name is ridiculous. It's also pretty accurate.
It's an aggressive quality pass over what was just written. It hunts for simplifications, duplication, weak names, code that looks like it works but smells off, uncovered cases, accidental complexity. It's like asking the agent to stop being the author and become, for ten minutes, the most insufferable reviewer on the team.
And on legacy that pays off big. I can't always build with TDD from the start, but I can force the result through a hard review before calling it done.
So my rule is: **greenfield, TDD; brownfield, normal implementation + nuclear review.** Not dogma. Engineering with context. The goal is the same: final code I'd put my name on in a PR without staring at the floor.
## 5. `/setup-matt-pocock-skills`: a tiny `AGENTS.md` and a `CLAUDE.md` that just points to it
The last skill doesn't build features. It builds the environment so the other four work better.
`setup-matt-pocock-skills` installs the kit. But what I really care about is what I pair it with: a serious cleanup of the project instructions.
I used to have, in each project, a giant `CLAUDE.md`. The classic: you start with four useful rules, then a convention, then an exception, then "remember not to touch this," then "when you work on tests, do that." Three months later you've got a document that reads like the constitution of a country with too many microservices.
And the agent? It doesn't read it well. It skims. It loses details. The important rules get buried under the noise.
The fix was to take the drama out of it.
Now the real instructions live in a deliberately small `AGENTS.md`, the standard several tools already understand, short enough that the agent actually reads all of it. And `CLAUDE.md` shrinks to almost a pointer: go read `AGENTS.md`.
One source of truth. Fewer tokens burned. Fewer contradictions. Less "but this was on some lost line of the giant doc."
It's a small change, but you feel it. Especially when you use agents every day. Instructions aren't a landfill. They're an interface.
## The real point: process is the moat
None of this is rocket science.
You interrogate the idea. You document it. You cut it into small slices. You implement with discipline. You keep the instructions clean.
The powerful part isn't any single skill. The powerful part is turning the way you work into something invokable. Repeatable. Boring, even. And in programming, "boring" is usually a compliment.
Because an agent can be incredibly capable, but it has no permanent context. No team memory. It doesn't know why an old decision exists. It doesn't remember the war that broke out around some component half a year ago. You do. Or you should.
So don't treat it like an oracle. Treat it like a strong dev who joined the project this very morning and needs a process to avoid breaking things with confidence.
Give it a strict path and it produces genuinely good work. Let it loose and it'll build you a generic abstraction for a problem it didn't understand yet.
The core idea is Matt Pocock's, and his [skills repository](https://github.com/mattpocock/skills) is the best place to start. Don't copy my pipeline. Honestly, better if you don't: the interesting part is building your own. But make it explicit.
Because in the age of agents, your edge isn't just writing code anymore. It's designing the system that makes the code come out right more than once.
**Related reading:** these skills are most fun on a real project. Here's [how I built ga4-manager to automate Google Analytics](/en/blog/ga4-manager-automate-google-analytics/), one of the codebases this pipeline runs on.
---
**P.S.** If you've built your own skill pipeline, I want to see it. What did you encode that I'm missing? Hit me up on [Twitter/X](https://x.com/garbarok).
---
# Stop Prompting Your Agent. Start Writing Loops.
URL: https://www.oscargallegoruiz.com/en/blog/stop-prompting-write-loops/
Lang: en
> Boris Cherny's job now is writing loops, not prompts: agents that prompt agents. What that means, how to build one in Claude Code today, and where it breaks. →
Last time I wrote about encoding my process as [agent skills](/en/blog/agent-skills-coding-workflow/): grill the idea, write the PRD, slice it, build it, keep the instructions lean. I thought that was the top of the ladder. Then I watched Boris Cherny, the head of Claude Code, describe the rung above it, and realized I'd only climbed halfway.
His line, on the _Acquired Unplugged_ stage, roughly: a year ago he wrote code with autocomplete. Then he was running five or ten Claudes in parallel, and his "coding" was prompting each one. Now? _"I don't prompt Claude anymore. I have loops that are running. They're the ones prompting Claude and figuring out what to do. My job is to write loops."_
Read that again. The unit of work moved from the keystroke, to the prompt, to the **loop**.
## The abstraction ladder, and which rung you're on
Boris frames coding as one long climb: punch cards, then assembly, then C, then the high-level languages, then the really high-level ones. "The level of abstraction always goes up." Prompting an agent is just the next rung. And so is the one after it.
Where are most of us right now? Rung two. We prompt. Maybe we run a couple of agents at once and feel cutting-edge. The jump Boris is describing is rung three: **you stop being the thing that prompts.** You build the thing that prompts, and it decides what to work on, dispatches the agents, and checks the results without you in the keystroke path. That's the shift from **human _in_ the loop** — you approving every step — to **human _on_ the loop**: you design the system and supervise it from outside, instead of sitting inside every iteration.
That sounds like sci-fi until you realize the primitives already exist.
## What a "loop" actually is (no hand-waving)
Strip the mystique, and split it in two. The **harness** is the equipment — the tools, skills, and MCPs you hand an agent so it can actually do the job. The **loop** is the orchestration around it: figure out what work exists → hand a chunk to an agent → check what came back → repeat, and decide when it launches, when it advances, when it stops. The harness is what the agent _can_ do; the loop is _when and how often_ it does it. You're not writing the code. You're not even writing the prompts. You're writing the thing that writes the prompts.
In Claude Code today, that's not a metaphor. It's a handful of real tools:
- **Workflow scripts**: deterministic code that fans work across many subagents (run them in parallel, pipe each item through stages, loop until a queue is dry or a token budget runs out). This is _literally_ a loop that prompts Claude.
- **Background and parallel agents**: fire off a fleet, each on its own slice, all at once.
- **Scheduled / cron agents**: the part that makes it autonomous. An agent that wakes up on a schedule, reads your GitHub issues, your feedback, your Slack, and acts.
That last one is exactly what Boris described running at scale: _"a couple hundred Claudes running… looking at Twitter feedback, GitHub issues, Slack. They're figuring out what to build next."_
You don't need a hundred. The smallest real loop you can run this week: a cron agent that triages every new GitHub issue each morning. It labels it, checks it against the codebase, drafts a repro, flags the ones worth your time. That's rung three, today, with one agent. Build up from there.
## Why skills are the prerequisite (this is the sequel, after all)
Here's the part people skip straight past, and it's the whole reason I wrote the [skills post](/en/blog/agent-skills-coding-workflow/) first.
**You cannot safely automate the invocation of a process you haven't encoded.**
A loop doesn't make an agent smart. It makes it _frequent_. If the agents inside your loop don't follow a real pipeline (grill the idea, slice it vertically, build with discipline, obey a slim `AGENTS.md`), then a loop just generates garbage faster. A firehose of plausible-looking wrong.
Skills are what turn a loop from a slop machine into a process that runs itself. Boris said the same thing, almost in passing: companies keep "principles documents" to avoid making the same decisions over and over, and _"the model can use these principles also, and it comes in the form of skills."_ Rung two (skills) isn't a detour on the way to rung three (loops). It's the load-bearing wall.
## The honest part: most of what a loop spits out is bad
I'm not going to sell you the dream without the asterisk.
Boris, about his hundreds of agents hunting for what to build: _"most ideas are bad, but maybe 20% are good."_ Twenty percent. From the person who built the tool.
And Anthropic's own essay on [recursive self-improvement](https://www.anthropic.com/institute/recursive-self-improvement) lands on the same bottleneck from the opposite direction. Their framing of the trajectory (humans writing code, then agents writing whole files, then agents handing hours of work to other agents) sounds triumphant until you hit the catch: **human review has become the bottleneck.** The execution got cheap. The judgment didn't.
So a loop without a filter is a liability, not leverage. The thing that makes loops survivable is the gate on the output: an adversarial review pass, a hard quality check, tests that actually fail. The loop generates; _something_ has to be the bouncer. If 80% is junk, your edge is the speed and quality of your "no."
And there's a second meter running: money. A loop that fans out chained subagents while you sleep doesn't just produce slop — it bills you for it. Every unsupervised iteration spends tokens whether the output is worth keeping or not, so a token ceiling and a stop condition aren't nice-to-haves — they're part of the harness. Set both before you ever let one run unattended.
## Where this is heading (and why it's not just hype)
Zoom out and Boris's "I write loops" is the personal-scale snapshot of what Anthropic argues is happening to the whole field. Their essay sketches a future where AI increasingly automates AI development itself, and the human role compresses toward one thing: **direction and judgment.** Choosing what's worth doing. Knowing a good result from a bad one.
I'd take the specific numbers with tongs, and to their credit, so do they. They openly hedge that lines-of-code is a lousy productivity metric, that self-reported gains are probably inflated, and that whether today's models can develop real research _taste_ on their own is, in their words, genuinely unclear. That hedging is exactly why the essay is worth reading: it's bullish on the trajectory and honest about the uncertainty. The direction is real even if the dates aren't.
## What stays yours
Here's the thing the ladder is quietly telling you.
Each rung you climb, your edge stops being the thing below it. It stopped being "I can write the code." It's about to stop being "I can write the prompt." What's left, at the top, is the stuff that doesn't automate: deciding what's worth building, judging what comes back, and the values you bake into the system that runs while you sleep.
Boris was asked what the last human-only skill will be. His answer: _"the final thing we're going to be teaching the model is values. The way we teach our kids how to be good people, we're going to teach the model how to be a good model."_
So don't romanticize the loops. Build one. Encode your process as skills first, wrap a small loop around it, and put a brutal review gate on whatever it produces. That's the whole move: rung three doesn't need a hundred agents. It needs **one good loop and your judgment on the other end.**
You're not paid to write code anymore. You're barely paid to write prompts. You're paid to design the loop, and to be the one who still knows what "good" means.
**Related reading:** this only works if the process underneath is solid. Start with [the five agent skills that run my whole workflow](/en/blog/agent-skills-coding-workflow/), then wrap a loop around them.
## Sources
- Boris Cherny (Head of Claude Code), _Acquired Unplugged_: the "I write loops" remark and the "most ideas are bad, ~20% good" line, via [@codingvic's clip on X](https://x.com/codingvic/status/2062487626779636001).
- Anthropic, [_Recursive self-improvement_](https://www.anthropic.com/institute/recursive-self-improvement): the company-scale framing and the hedges.
---
**P.S.** Building loops in anger? I want to hear what you've automated and what blew up in your face. Find me on [Twitter/X](https://x.com/garbarok).
---
# 5 Agent Skills que Gobiernan Todo Mi Flujo de Código
URL: https://www.oscargallegoruiz.com/blog/agent-skills-flujo-codigo/
Lang: es
> Grilling, PRDs, vertical slices, TDD condicional y un AGENTS.md mínimo: el pipeline de cinco skills que aplico en cada feature, sobre las de Matt Pocock. →
Un agente de IA es como tener a un dev muy bueno sentado a tu lado. Razona, escribe código, pilla patrones, a veces hasta te sorprende.
Tiene un problema: cada mañana se despierta sin memoria.
No recuerda nada. Ni la feature de ayer, ni por qué ese componente es así, ni la decisión que tomasteis hace seis meses entre lágrimas. Y si no le das contexto, ¿sabes qué hace? Se lo inventa. Con una seguridad pasmosa. Ahí empieza el espectáculo.
Por eso la clave no es "usar IA para programar". Eso ya lo hace todo el mundo. La clave es darle un **proceso**. Repetible. Que no dependa de que tú estés inspirado un martes a las cinco. Que le obligue a pensar antes de tocar archivos como si fuera viernes en producción.
[Matt Pocock](https://github.com/mattpocock/skills) lo explicó de una forma muy limpia con las agent skills: instrucciones pequeñas, con nombre, que invocas cuando quieres que el agente siga un camino concreto. Leí su enfoque, me lo llevé a mi terreno, y acabó convertido en un pipeline que uso en casi cada feature.
Ojo: las skills no me las invento ni las modifico. Las uso tal cual vienen. Lo mío es el **flujo**: el orden en que las invoco y cómo las encadeno. Algunas son de Matt; otras vienen de otros sitios. De él me llevé la regla base: no dejes que el agente programe hasta que se haya ganado el derecho.
Cinco etapas. Vamos.
## 1. `/grill-with-docs`: clavar la idea antes de tocar código
Cada feature empieza igual: tengo una idea a medio hacer y, por mucho que me pique, no dejo que el agente escriba el plan todavía.
¿Por qué? Porque el modo de fallo por defecto de Claude Code es venirse arriba. Le dices "planifica esto" y te suelta un plan precioso, lleno de secciones y bullets, con una confianza que asusta. El problema: planifica sobre suposiciones. Y una suposición es un bug con buena gramática.
`grill-with-docs` le da la vuelta. En vez de planificar, me interroga.
Pregunta. Baja un nivel. Espera. Vuelve a preguntar. No quiere resolverlo todo de golpe: recorre el árbol de decisiones poco a poco: el "design tree" que Matt saca de *The Design of Design* de Fred Brooks. Vas bajando por las ramas hasta entender qué narices vas a construir antes de escribir una línea.
Y lo de "with-docs" no es decoración. Si algo se puede responder mirando el código, no me lo pregunta a mí: lo busca. Abre componentes, lee convenciones, mira tipos y APIs que ya existen. Si puede comprobarlo, no me hace perder el tiempo.
Lo que saco de aquí es oro puro:
- **Primero la foto completa.** Antes de decidir si esto es un hook, un endpoint o un componente, entiendo la feature como sistema.
- **Las preguntas incómodas.** Estados vacíos, errores, condiciones de carrera, permisos, qué pasa si dos cosas ocurren a la vez. Lo que nadie piensa hasta que producción te lo explica con una captura a las 3 de la mañana.
- **El scope, explícito.** Esta es la parte que más me importa. Aquí digo: esto entra, esto no, y esto lo dejamos fuera a propósito. No "se nos olvidó". Decidido, escrito, cerrado.
¿Es incómodo? Sí. Mejor. Si tu idea no aguanta unas preguntas antes de construirla, espera a que la toquen usuarios de verdad.
Cuando termina el grilling, la idea ya no es una nube. Tiene aristas.
## 2. `/to-prd`: convertir la conversación en un documento en GitHub
Después del grilling ya hay algo que merece escribirse. Ahí entra `to-prd`.
La skill coge toda la conversación y la convierte en un Product Requirements Document. Pero no lo deja muriéndose en el chat: lo crea directamente como **GitHub Issue**.
Y ese detalle lo cambia todo. El contexto deja de vivir en una sesión temporal de Claude. Ahora tiene URL. Tiene historial. Está donde vive el trabajo de verdad. Cierro la terminal, cambio de rama, abro otra conversación... y la decisión sigue ahí. No se evapora.
El PRD gira en torno a las user stories: qué tiene que pasar para el usuario, en lenguaje humano, no una lista de archivos a tocar. Importa más de lo que parece. Un buen PRD no dice "crea este hook y este servicio". Dice qué comportamiento esperas y qué casos hay que cubrir. El cómo viene después.
Como el grilling ya hizo el trabajo sucio, esta fase no reabre el debate. Solo convierte decisiones en un artefacto que la siguiente etapa puede masticar.
Menos magia. Más trazabilidad.
## 3. `/to-issues`: cortar el destino en un trayecto
Un PRD te dice a dónde quieres llegar. No te dice cómo avanzar sin estrellarte por el camino.
Decirle a un agente "implementa este PRD entero" es invitarlo a hacer una mudanza con una bolsa del super. Igual sale bien. Pero no es un plan.
`to-issues` coge el PRD y lo parte en issues pequeñas de GitHub. Cada una entendible, ejecutable y revisable por separado.
La regla de oro: **cortes verticales, no horizontales.**
Nada de:
- "crear la capa de datos"
- "crear la lógica de negocio"
- "crear la UI"
Parece ordenado, ¿verdad? Pero no entrega NADA hasta que juntas las tres piezas. Mientras tanto tienes tres issues que por separado no sirven para nada. Eso es arquitectura en diferido.
Un vertical slice hace lo contrario: atraviesa UI, lógica y datos para entregar un comportamiento pequeño funcionando de punta a punta. Igual no es toda la feature. Pero ya es algo real, que se puede tocar.
Este hábito me viene de currar en un entorno [SAFe](https://framework.scaledagile.com/story). Y mira, SAFe tiene lo suyo. No nos engañemos, nadie se levanta feliz pensando en el PI Planning. Pero una idea se me quedó grabada a fuego: una story debería ser un corte vertical pequeño del comportamiento del sistema. Cortar por valor, no por tecnología. Si necesitas tres slices antes de que alguien vea algo útil, lo has cortado mal.
(Y no, esto no es Scrum, aunque mucha gente lo mezcla. SAFe va por encima de los equipos: varios equipos forman un *Agile Release Train* que se sincroniza cada 8 a 12 semanas. Abajo, en el equipo, la cosa funciona estilo Scrum, con iteraciones de dos semanas. La parte que me llevé es la de las stories.)
Y con agentes esto importa todavía más. `to-issues` no solo parte el trabajo: define dependencias. Qué bloquea a qué. Qué se puede coger ya. Qué puede ir en paralelo.
Eso es clave si quieres lanzar varios agentes a la vez. Una issue autocontenida se asigna sin que el agente tenga que entender medio universo. Si dos no se pisan, avanzan en paralelo. Y si están bien cortadas, revisarlas también duele mucho menos.
La idea tiene parentesco con las [tracer bullets](https://www.aihero.dev/tracer-bullets): disparos finos que atraviesan todas las capas para descubrir pronto lo que no sabías que no sabías. Porque los *unknown unknowns* no aparecen diseñando la capa perfecta en abstracto. Aparecen cuando algo funciona de verdad.
## 4. Implementar: TDD condicional, más una pasada nuclear de calidad
Ahora sí. Código. Pero no siempre igual: depende del codebase.
**¿Proyecto nuevo? TDD desde el minuto uno.**
En greenfield uso `/tdd`, la skill de Matt. Red, green, refactor. Sin dramas.
Primero el test. Que falle. Luego el mínimo código para que pase. Luego limpiar. Y otra vez, hasta cerrar el comportamiento.
Con agentes esto funciona de maravilla porque les das una diana. Ya no están "implementando una idea": están intentando pasar un test concreto. Y eso recorta muchísimo la tentación de inventarse scope, montar abstracciones raras o tocar cosas que nadie pidió. Un test en rojo es la conversación más clara del mundo: esto todavía no funciona, arréglalo.
**¿Codebase grande y heredado? No fuerzo TDD.**
Aquí me bajo del púlpito. En una app legacy grande, meter TDD a mitad de feature es más teatro que ingeniería. Los límites no están claros, los mocks son una selva, el harness de tests parece construido por una civilización perdida... y acabas peleándote más con la infraestructura que entregando valor.
Así que en brownfield implemento de forma más directa. Pero no lo dejo pasar sin control: ahí entra `/thermo-nuclear-code-quality-review`.
El nombre es ridículo. También es bastante exacto.
Es una pasada agresiva de calidad sobre lo recién escrito. Busca simplificaciones, duplicación, nombres flojos, código que parece funcionar pero huele raro, casos sin cubrir, complejidad accidental. Es como pedirle al agente que deje de ser el autor y se convierta, durante diez minutos, en el reviewer más insoportable del equipo.
Y en legacy eso compensa un montón. No siempre puedo construir con TDD desde el principio, pero sí puedo obligar al resultado a pasar una revisión dura antes de darlo por bueno.
Mi regla queda así: **greenfield, TDD; brownfield, implementación normal + revisión nuclear.** No es dogma. Es ingeniería con contexto. El objetivo es el mismo: que el código final sea algo que yo firmaría en una PR sin mirar al suelo.
## 5. `/setup-matt-pocock-skills`: un `AGENTS.md` mínimo y un `CLAUDE.md` que solo apunta a él
La última skill no construye features. Construye el entorno para que las otras cuatro funcionen mejor.
`setup-matt-pocock-skills` instala el kit. Pero lo que de verdad me importa es con qué la combino: una limpieza seria de las instrucciones del proyecto.
Antes tenía, en cada proyecto, un `CLAUDE.md` gigante. El clásico: empiezas con cuatro reglas útiles, luego una convención, luego una excepción, luego "acuérdate de no tocar esto", luego "cuando trabajes en tests, haz aquello". Tres meses después tienes un documento que parece la Constitución de un país con demasiados microservicios.
¿Y el agente? No se lo lee bien. Lo escanea. Pierde detalles. Las reglas importantes quedan enterradas bajo el ruido.
La solución fue quitarle épica al asunto.
Ahora las instrucciones de verdad viven en un `AGENTS.md` deliberadamente pequeño: el estándar que ya entienden varias herramientas, lo bastante corto como para que el agente se lo lea entero. Y el `CLAUDE.md` se queda casi en un puntero: ve y lee `AGENTS.md`.
Una sola fuente de verdad. Menos tokens quemados. Menos contradicciones. Menos "pero esto estaba en una línea perdida del documento gigante".
Es un cambio pequeño, pero se nota. Sobre todo cuando usas agentes a diario. Las instrucciones no son un vertedero. Son una interfaz.
## La idea de fondo: el proceso es el foso
Nada de esto es ciencia espacial.
Interrogas la idea. La documentas. La cortas en slices pequeñas. Implementas con disciplina. Mantienes las instrucciones limpias.
Lo potente no es ninguna skill concreta. Lo potente es convertir tu forma de trabajar en algo invocable. Repetible. Hasta aburrido. Y en programación, "aburrido" suele ser un piropo.
Porque un agente puede ser muy capaz, pero no tiene contexto permanente. No tiene memoria de equipo. No sabe por qué existe una decisión vieja. No recuerda la guerra que hubo alrededor de un componente hace medio año. Tú sí. O deberías.
Así que no lo trates como un oráculo. Trátalo como un dev fuerte que ha entrado al proyecto esta misma mañana y necesita un proceso para no romper cosas con seguridad.
Dale un camino estricto y produce trabajo muy bueno. Déjalo suelto y te monta una abstracción genérica para un problema que todavía no había entendido.
La idea base es de Matt Pocock, y su [repositorio de skills](https://github.com/mattpocock/skills) es el mejor sitio para empezar. No copies mi pipeline. De hecho, mejor no lo copies: lo interesante es construir el tuyo. Pero hazlo explícito.
Porque en la era de los agentes tu ventaja ya no es solo escribir código. Es diseñar el sistema que hace que el código salga bien más de una vez.
**Lectura relacionada:** estas skills se disfrutan más en un proyecto real. Aquí tienes [cómo construí ga4-manager para automatizar Google Analytics](/blog/ga4-manager-automatiza-google-analytics/), uno de los codebases sobre los que corre este pipeline.
---
**P.D.** Si has montado tu propio pipeline de skills, quiero verlo. ¿Qué has codificado que a mí me falta? Escríbeme en [Twitter/X](https://x.com/garbarok).
---
# Deja de Promptear a tu Agente. Escribe Loops.
URL: https://www.oscargallegoruiz.com/blog/deja-de-promptear-escribe-loops/
Lang: es
> Boris Cherny dice que su trabajo ya no es promptear, sino escribir loops: agentes que promptean agentes. Qué significa, cómo montar uno hoy y dónde se rompe. →
La última vez escribí sobre codificar mi proceso como [agent skills](/blog/agent-skills-flujo-codigo/) - interrogar la idea, escribir el PRD, cortarla en slices, construirla, mantener las instrucciones limpias. Pensaba que eso era lo más alto de la escalera. Luego vi a Boris Cherny, el responsable de Claude Code, describir el escalón de encima, y me di cuenta de que solo había subido la mitad.
Su frase, en el escenario de _Acquired Unplugged_, más o menos así: hace un año escribía código con autocompletado. Luego tenía cinco o diez Claudes corriendo en paralelo, y su "programar" era promptear a cada uno. ¿Y ahora? _"Ya no prompteo a Claude. Tengo loops corriendo. Ellos son los que promptean a Claude y deciden qué hacer. Mi trabajo es escribir loops."_
Léelo otra vez. La unidad de trabajo pasó de la tecla, al prompt, al **loop**.
## La escalera de abstracción, y en qué escalón estás
Boris describe programar como una sola subida larga: tarjetas perforadas, luego ensamblador, luego C, luego los lenguajes de alto nivel, luego los de altísimo nivel. "El nivel de abstracción siempre sube." Promptear a un agente es solo el siguiente escalón. Y también lo es el de después.
¿Dónde estamos casi todos ahora mismo? Escalón dos. Prompteamos. Como mucho lanzamos un par de agentes a la vez y nos sentimos a la última. El salto que describe Boris es el escalón tres: **dejas de ser la cosa que promptea.** Construyes la cosa que promptea, y ella decide en qué trabajar, despacha a los agentes y revisa los resultados sin que tú toques una tecla. Es el paso de **human _in_ the loop** —tú apruebas cada paso— a **human _on_ the loop**: diseñas el sistema y lo supervisas desde fuera, en vez de sentarte dentro de cada iteración.
Suena a ciencia ficción hasta que te das cuenta de que las piezas ya existen.
## Qué es de verdad un "loop" (sin humo)
Quítale el misterio, y pártelo en dos. El **harness** es el equipamiento — las herramientas, skills y MCPs que le das a un agente para que pueda hacer el trabajo de verdad. El **loop** es la orquestación que lo rodea: averigua qué trabajo hay → le pasa un trozo a un agente → revisa lo que vuelve → repite, y decide cuándo se lanza, cuándo avanza, cuándo para. El harness es lo que el agente _puede_ hacer; el loop es _cuándo y con qué frecuencia_ lo hace. No escribes el código. Ni siquiera escribes los prompts. Escribes la cosa que escribe los prompts.
En Claude Code, hoy, eso no es una metáfora. Son cuatro herramientas reales:
- **Workflow scripts**: código determinista que reparte el trabajo entre muchos subagentes (en paralelo, pasando cada elemento por etapas, en bucle hasta vaciar una cola o agotar un presupuesto de tokens). Esto es, literalmente, un loop que promptea a Claude.
- **Agentes en background y en paralelo**: lanzas una flota, cada uno en su slice, todos a la vez.
- **Agentes programados / cron**: la parte que lo hace autónomo. Un agente que se despierta según un horario, lee tus issues de GitHub, tu feedback, tu Slack, y actúa.
Eso último es exactamente lo que Boris contaba que tenía corriendo a escala: _"un par de cientos de Claudes corriendo… mirando feedback de Twitter, issues de GitHub, Slack. Están decidiendo qué construir a continuación."_
No necesitas cien. El loop más pequeño y real que puedes montar esta semana: un agente cron que clasifica cada issue nueva de GitHub por la mañana. La etiqueta, la contrasta con el codebase, redacta un repro, marca las que merecen tu tiempo. Eso es el escalón tres, hoy, con un solo agente. A partir de ahí escalas.
## Por qué las skills son el requisito previo (esto es la secuela, al fin y al cabo)
Aquí está la parte que la gente se salta, y es la razón entera por la que escribí primero el [post de las skills](/blog/agent-skills-flujo-codigo/).
**No puedes automatizar de forma segura la invocación de un proceso que no has codificado.**
Un loop no hace listo a un agente. Lo hace **frecuente**. Si los agentes dentro de tu loop no siguen un proceso de verdad (interrogar la idea, cortarla en vertical, construir con disciplina, obedecer un `AGENTS.md` mínimo), entonces un loop solo genera basura más rápido. Un chorro de cosas plausibles pero equivocadas.
Las skills son lo que convierte un loop de máquina de slop en un proceso que se ejecuta solo. Boris dijo lo mismo, casi de pasada: las empresas tienen "documentos de principios" para no tomar las mismas decisiones una y otra vez, y _"el modelo también puede usar esos principios, y vienen en forma de skills."_ El escalón dos (skills) no es un desvío de camino al escalón tres (loops). Es el muro de carga.
## La parte honesta: la mayoría de lo que escupe un loop es malo
No te voy a vender el sueño sin el asterisco.
Boris, hablando de sus cientos de agentes buscando qué construir: _"la mayoría de las ideas son malas, pero quizá un 20% son buenas."_ Un veinte por ciento. Lo dice quien construyó la herramienta.
Y el propio ensayo de Anthropic sobre [auto-mejora recursiva](https://www.anthropic.com/institute/recursive-self-improvement) llega al mismo cuello de botella por el lado opuesto. Su descripción de la trayectoria (humanos escribiendo código, luego agentes escribiendo archivos enteros, luego agentes pasándole horas de trabajo a otros agentes) suena triunfal hasta que llegas a la trampa: **la revisión humana se ha convertido en el cuello de botella.** La ejecución se abarató. El criterio no.
Así que un loop sin filtro es un pasivo, no una palanca. Lo que hace los loops soportables es la puerta a la salida: una revisión adversarial, un control de calidad duro, tests que de verdad fallen. El loop genera; _algo_ tiene que hacer de portero. Si el 80% es basura, tu ventaja es la velocidad y la calidad de tu "no".
Y hay un segundo contador en marcha: el dinero. Un loop que despacha subagentes encadenados mientras duermes no solo produce slop — te lo factura. Cada iteración sin supervisión gasta tokens valga o no la pena lo que sale, así que un techo de tokens y una condición de parada no son un extra — son parte del harness. Pon ambos antes de dejar uno corriendo solo.
## Hacia dónde va esto (y por qué no es solo hype)
Aleja el plano y el "yo escribo loops" de Boris es la foto a escala personal de lo que Anthropic sostiene que le está pasando al campo entero. Su ensayo dibuja un futuro donde la IA automatiza cada vez más el propio desarrollo de IA, y el rol humano se comprime hacia una sola cosa: **dirección y criterio.** Elegir qué merece la pena hacer. Distinguir un buen resultado de uno malo.
Yo cogería los números concretos con pinzas, y para ser justos, ellos también. Reconocen abiertamente que las líneas de código son una métrica mala, que las mejoras auto-reportadas probablemente están infladas, y que si los modelos de hoy pueden desarrollar verdadero _gusto_ investigador por su cuenta es, en sus palabras, genuinamente incierto. Esa honestidad es justo por lo que merece leerse: alcista con la trayectoria, sincero con la incertidumbre. La dirección es real aunque las fechas no lo sean.
## Lo que sigue siendo tuyo
Esto es lo que la escalera te está diciendo en voz baja.
Cada escalón que subes, tu ventaja deja de ser lo de debajo. Dejó de ser "sé escribir el código". Está a punto de dejar de ser "sé escribir el prompt". Lo que queda, arriba del todo, es lo que no se automatiza: decidir qué merece la pena construir, juzgar lo que vuelve, y los valores que metes en el sistema que corre mientras duermes.
A Boris le preguntaron cuál será la última habilidad solo-humana. Su respuesta: _"lo último que le enseñaremos al modelo son valores. Igual que enseñamos a nuestros hijos a ser buenas personas, le enseñaremos al modelo a ser un buen modelo."_
Así que no romantices los loops. Monta uno. Codifica tu proceso como skills primero, envuélvelo en un loop pequeño, y pon una puerta de revisión brutal a lo que produzca. Esa es la jugada entera: el escalón tres no necesita cien agentes. Necesita **un buen loop y tu criterio al otro lado.**
Ya no te pagan por escribir código. Apenas te pagan por escribir prompts. Te pagan por diseñar el loop, y por ser quien todavía sabe qué significa "bueno".
**Lectura relacionada:** esto solo funciona si el proceso de debajo es sólido. Empieza por [las cinco agent skills que gobiernan todo mi flujo](/blog/agent-skills-flujo-codigo/), y luego envuélvelas en un loop.
## Fuentes
- Boris Cherny (responsable de Claude Code), _Acquired Unplugged_: la frase "yo escribo loops" y el "la mayoría de las ideas son malas, ~20% buenas", vía [el clip de @codingvic en X](https://x.com/codingvic/status/2062487626779636001).
- Anthropic, [_Recursive self-improvement_](https://www.anthropic.com/institute/recursive-self-improvement): el marco a escala de empresa y los matices.
---
**P.D.** ¿Montando loops en serio? Quiero saber qué has automatizado y qué te explotó en la cara. Escríbeme en [Twitter/X](https://x.com/garbarok).
---
# I Automated GA4 with YAML. Now It Flags What to Check in SEO.
URL: https://www.oscargallegoruiz.com/en/blog/ga4-manager-automate-google-analytics/
Lang: en
> A CLI + MCP server that configures GA4 and Search Console from YAML, and flags what to check in your SEO by impact. Deterministic: you make the calls. →
I started building this so I'd stop losing 40 minutes clicking through the GA4 UI every time I spun up a project. What I didn't expect was where it ended up: now the tool doesn't just configure analytics, it **flags** what to look at in my SEO, ranked by how many clicks it's costing me. It doesn't decide for me. It puts the data in front of me, prioritized, and I pick what to touch.
That distinction is the whole point, and I'll come back to it. This is the story of how it happened, what it does now, and what came out when I pointed the full suite at this very blog, including the moment the tool got it wrong (and why that gave me *more* confidence, not less).
## The original problem: clicking like a monkey
I have several side projects. This portfolio, [WealthSim](https://wealthsim.app), and a few smaller ones. Each needs analytics, and every time I spun up a new one the ritual was the same: create the GA4 property (easy), then click. Conversions, ten clicks each. Dimensions, more clicks. Metrics, more. Data retention, where was that option again? Enhanced measurement, another menu.
**Thirty or forty minutes of repetitive clicking.** And the worst part: if I wanted the same config on another project, I'd repeat it all from scratch. GA4 has no "export configuration." No way to copy setup between properties.
After configuring the third project in one week, I thought what you're thinking right now: *this is exactly the kind of work that should be automated.*
## The premise: analytics as code
I define my infra as code. My CI/CD as code. Why not my analytics?
That was the whole idea. A YAML file that describes how I want GA4, and one command to apply it:
```yaml
project:
name: "My Project"
ga4:
property_id: "123456789"
tier: standard
conversions:
- name: newsletter_signup
counting_method: ONCE_PER_SESSION
dimensions:
- parameter: article_category
scope: EVENT
```
```bash
ga4 setup --config my-project.yaml
```
Boom. Config applied. No clicks, no typos, versioned in git next to your code. From 40 minutes to under one. That was [GA4 Manager](https://github.com/garbarok/ga4-manager) v1.
## The turn: it stopped showing me data and started pointing at what to check
This is where the tool got genuinely interesting.
The first half of its life was **configuration**: apply this YAML, create these conversions, submit this sitemap. Useful, but passive. The second half, the part that actually changed how I work, is **diagnostics**. Today, on v2.3.1, the MCP server exposes 20 tools, and the newest ones don't show you data: they tell you where to start.
The one I use most is **`gsc_opportunities`**. It finds queries where you already rank on page 1-2 (position 5-20) but with a CTR below the median for that bucket, and sorts them by `potential_clicks`: the extra monthly clicks you'd gain just by hitting the median CTR. Biggest wins first.
On this blog? It found exactly one. And at position ~18, page two, where a title tweak won't move it. The tool didn't inflate it: it told me the truth, that there was no gold mine here. On a site with real traffic, this is the tool that buys you coffee; on a small one, it confirms there are no shortcuts. Both answers work for me.
The other three in the new group follow the same "what first" philosophy:
- **`gsc_cannibalization`**: queries where two or more of your pages split impressions and eat each other's authority; it points at the canonical candidate.
- **`gsc_ctr_anomaly`**: (query, page) pairs where position barely moved but CTR collapsed. Translation: your snippet stopped converting. Rewrite it.
- **`gsc_health`**: an indexing report that diffs each URL's state against the prior snapshot, so an accidental `noindex` surfaces in days, not weeks. Silent when everything's green. Built for a cron.
And here's what, for me, separates this from the pile: **none of it is the AI guessing at SEO.** These are deterministic queries against the Search Console API (a Go CLI, structured output). The LLM only orchestrates the calls and summarizes the result; the interpretation and the "yes-this, no-that" are mine. If vibe coding gives you hives (it does me), that's exactly the line that matters: the tool surfaces, you judge.
## What happened when I pointed it at this blog
This blog is one of my side projects and runs on a site that uses GA4 Manager via MCP, so last week I sat down with Claude and pointed the full suite at `oscargallegoruiz.com`. I expected to find disasters. Reality was more boring, and more interesting than it sounds.
43 of 43 pages indexed. `gsc_ctr_anomaly`: empty. `seo_page_audit` on the top pages: clean, zero errors. In short: the site was healthy. And a tool telling you "everything's fine" instead of inventing a problem to justify itself is a signal I trust.
But there was a scare. `gsc_sitemaps_list` returned an *empty* list, as if I'd never submitted the sitemap. The easy reflex would've been to resubmit it and move on. Instead I verified with `gsc_sitemaps_get`… and there it was, submitted and downloaded by Google, no problem. **The empty list was a bug in my own tool, not an SEO failure.**
And that's the moral I care about, the one that ties back to everything above: *I didn't trust the output blindly.* If I'd acted on the false positive, I'd have "fixed" something that wasn't broken. Verifying saved me the embarrassment, and along the way, the tool I wrote to catch problems caught a bug in itself. I fixed it. That's the healthy relationship with a tool like this: it gives you leads, you confirm them. The one I never trust is the one that promises you don't need to confirm anything.
## What I learned building this
**Google has two GA4 APIs.** The Data API (query data) and the Admin API (configure). GA4 Manager uses the Admin one, which is `v1alpha`. Yes, alpha. Some endpoints change without warning, and certain metric types (like CURRENCY) have poorly documented restrictions. You find out the hard way.
**The limits are real and it validates them before touching anything.** On the free tier: 30 conversions, 50 dimensions, 50 metrics. If you're close, it warns you before you eat a 400 from the API.
**Parameter names are forever.** Once you create a dimension or metric, the parameter name is permanently reserved. Even if you archive it. My fix is ugly but works: version the names (`reading_time_v3`).
## Use it from your assistant (MCP)
The piece that changed everything was the MCP server. It exposes the 20 tools to Claude Desktop, Claude CLI, VS Code, Cursor, and Cline, so I can say in plain language:
> "Compare last week's traffic to the prior week, audit the homepage and the worst-ranking post, and tell me what to check."
And Claude orchestrates the calls and stitches the results together. But same principle as always: it hands me a prioritized list, not a `git push`. The decisions stay mine.
And here's the connection that's got me hooked: `gsc_health` is **built for a cron**. Which means it's not just a tool I invoke, but a [loop I can leave running](/en/blog/stop-prompting-write-loops/): an agent that checks indexing every Monday, compares traffic, and only bothers me if something broke. That's the next rung. You stop asking and build the loop that asks for you.
## What it does NOT do (let's be honest)
- **Audiences:** the tool doesn't create them. It generates the docs so you can build them by hand in the UI (the Admin API can create audiences; I just haven't wired that into the tool yet).
- **BigQuery linking:** automated. `ga4 link --service bigquery` creates the export link through the Admin API.
- **Search Console linking:** manual. The tool prints a setup guide; you finish the link in the UI.
- **Historical data:** this configures GA4, it doesn't migrate data. Collection starts after setup.
## Install: one script
```bash
git clone https://github.com/garbarok/ga4-manager.git
cd ga4-manager
./scripts/setup.sh
```
The script verifies prerequisites (`gcloud`, `jq`, `curl`), picks the auth path with you (ADC for personal use, service-account key for CI), enables the required APIs, smoke-tests every endpoint, and prints which manual permissions you still need. It's idempotent: rerun it without fear.
## Quick questions
**Is it free?** Yes, open source under MIT. The code is on [GitHub](https://github.com/garbarok/ga4-manager).
**Do I need to know Go?** No. Download the binary and write YAML.
**Can it delete my data?** No. It only uses the Admin API for configuration; it can't touch your analytics data. Worst case is creating or deleting config resources, which you can always recreate. And `--dry-run` lets you preview everything before applying.
**Do the SEO audits need a paid API key?** Only if you want Core Web Vitals inside `seo_page_audit`. Without a key, PageSpeed Insights rate-limits to one request per ~100s and the audit skips CWV. With a free key you get the normal quota.
**`gsc_analytics_run` vs `gsc_traffic_compare`?** The first is a snapshot of one period (top queries, pages, CTR, position). The second compares two periods and gives you URL-level drops and gains. One to see what you have, the other to see what changed.
If you have a couple of side projects you rarely touch, you probably don't need it. If you run three or more and you're sick of clicking the same UI for the hundredth time: [try it](https://github.com/garbarok/ga4-manager), star it if it helps, and open an issue if something breaks (or if you find another bug like the sitemap-list one).
**Related reading:** why `gsc_health` on a cron is the natural next step: [stop prompting your agent, start writing loops](/en/blog/stop-prompting-write-loops/).
---
**P.S.** If you try it, tell me what it found on [Twitter/X](https://x.com/garbarok). Now if you'll excuse me, I've got a cron to set up.
---
# Automaticé GA4 con YAML. Ahora Me Señala Qué Revisar en SEO.
URL: https://www.oscargallegoruiz.com/blog/ga4-manager-automatiza-google-analytics/
Lang: es
> Una CLI + servidor MCP que configura GA4 y Search Console desde YAML, y señala qué revisar en tu SEO por impacto. Determinista: las decisiones las tomas tú. →
Empecé a construir esto para no perder 40 minutos clicando en la UI de GA4 cada vez que arrancaba un proyecto. Lo que no esperaba es dónde acabaría: ahora la herramienta no solo configura analytics, me **señala** qué mirar en mi SEO, ordenado por cuántos clics me está costando. No decide por mí. Me pone los datos delante, priorizados, y yo elijo qué tocar.
En esa distinción está la clave, y vuelvo a ella más abajo. Esta es la historia de cómo pasó, qué hace hoy, y qué salió cuando le solté la suite entera a este mismo blog, incluido el momento en que la herramienta se equivocó (y por qué eso me dio *más* confianza, no menos).
## El problema original: clicar como un mono
Tengo varios side projects. Este portfolio, [WealthSim](https://wealthsim.app), y unos cuantos más pequeños. Cada uno necesita analytics, y cada vez que arrancaba uno nuevo el ritual era el mismo: crear la propiedad GA4 (fácil), y luego clicar. Conversiones, diez clics cada una. Dimensiones, más clics. Métricas, más. Retención de datos, ¿dónde estaba eso? Enhanced measurement, otro menú.
**Treinta o cuarenta minutos de clics repetitivos.** Y lo peor: si quería la misma config en otro proyecto, a repetirlo todo desde cero. GA4 no tiene "exportar configuración". No puedes copiar setup entre propiedades.
Después de configurar el tercer proyecto en una semana pensé lo que piensas tú ahora: *esto es exactamente el tipo de trabajo que debería automatizarse.*
## La premisa: analytics as code
Defino mi infra como código. Mi CI/CD como código. ¿Por qué no mi analytics?
Esa fue toda la idea. Un YAML que describe cómo quiero GA4, y un comando que lo aplica:
```yaml
project:
name: "Mi Proyecto"
ga4:
property_id: "123456789"
tier: standard
conversions:
- name: newsletter_signup
counting_method: ONCE_PER_SESSION
dimensions:
- parameter: article_category
scope: EVENT
```
```bash
ga4 setup --config mi-proyecto.yaml
```
Boom. Config aplicada. Sin clics, sin typos, versionable en git junto a tu código. De 40 minutos a menos de uno. Eso fue [GA4 Manager](https://github.com/garbarok/ga4-manager) v1.
## El giro: dejó de enseñarme datos y empezó a señalarme dónde mirar
Aquí es donde la herramienta se volvió interesante de verdad.
La primera mitad de su vida fue **configuración**: aplica este YAML, crea estas conversiones, envía este sitemap. Útil, pero pasivo. La segunda mitad, lo que de verdad cambió cómo trabajo, es **diagnóstico**. Hoy, en la v2.3.1, el servidor MCP expone 20 herramientas, y las más nuevas no te enseñan datos: te dicen por dónde empezar.
La que más uso es **`gsc_opportunities`**. Busca queries donde ya estás en página 1-2 (posición 5-20) pero con un CTR por debajo de la mediana de su franja, y las ordena por `potential_clicks`: los clics extra al mes que ganarías solo con llegar al CTR mediano. Las mayores ganancias primero.
¿En este blog? Encontró exactamente una. Y encima en posición ~18, página 2, donde un retoque de title no la mueve. La herramienta no la infló: me dijo la verdad, que aquí no había una mina de oro. En un sitio con tráfico de verdad, esta es la tool que te paga el café; en uno pequeño, te confirma que no hay atajos. Las dos respuestas me valen.
Las otras tres del grupo nuevo siguen la misma filosofía de "qué primero":
- **`gsc_cannibalization`**: queries donde dos o más páginas tuyas se reparten impresiones y se comen la autoridad entre ellas; te señala la candidata a canónica.
- **`gsc_ctr_anomaly`**: pares (query, página) donde la posición casi no se movió pero el CTR se desplomó. Traducción: tu snippet dejó de convertir. A reescribir.
- **`gsc_health`**: informe de indexación que diffea el estado de cada URL contra el snapshot anterior, así un `noindex` accidental sale en días, no en semanas. Silencioso si todo está verde. Pensado para un cron.
Y algo que para mí es lo que separa esto del montón: **nada de esto es la IA adivinando SEO.** Son queries deterministas contra la API de Search Console (un CLI en Go, output estructurado). El LLM solo orquesta las llamadas y me resume el resultado; la interpretación y el "esto sí, esto no" son míos. Si te da urticaria el vibe coding (a mí me la da), esa es justo la línea que importa: la herramienta saca, tú juzgas.
## Qué pasó cuando lo solté sobre este blog
Este blog es uno de mis side projects y corre sobre un sitio que usa GA4 Manager vía MCP, así que la semana pasada me senté con Claude y le solté la suite entera sobre `oscargallegoruiz.com`. Esperaba encontrar desastres. La realidad fue más aburrida, y más interesante de lo que parece.
43 de 43 páginas indexadas. `gsc_ctr_anomaly`: vacío. `seo_page_audit` en las páginas top: limpias, cero errores. En resumen: el sitio estaba sano. Y que una herramienta te diga "está todo bien" en vez de inventarte un problema para justificarse ya es una señal de la que me fío.
Pero hubo un susto. `gsc_sitemaps_list` me devolvió una lista *vacía*, como si nunca hubiera enviado el sitemap. El reflejo fácil habría sido reenviarlo y pasar página. En vez de eso lo verifiqué con `gsc_sitemaps_get`… y ahí estaba, enviado y descargado por Google sin problema. **La lista vacía era un bug en mi propia herramienta, no un fallo de SEO.**
Y esa es la moraleja que me importa, la que conecta con todo lo de arriba: *no me fié del output a ciegas.* Si llego a actuar sobre el falso positivo, habría "arreglado" algo que no estaba roto. Verificar me ahorró el ridículo y, de paso, la herramienta que escribí para cazar problemas me cazó un bug en sí misma. Lo arreglé. Esa es la relación sana con un tool así: te da pistas, tú las confirmas. De la que no me fío nunca es de la que te promete que no hace falta confirmar nada.
## Lo que aprendí construyendo esto
**Google tiene dos APIs de GA4.** La Data API (consultar datos) y la Admin API (configurar). GA4 Manager usa la Admin, que va en `v1alpha`. Sí, alpha. Algunos endpoints cambian sin avisar, y ciertos tipos de métrica (como CURRENCY) tienen restricciones mal documentadas. Te enteras por las malas.
**Los límites son reales y los valida antes de tocar nada.** En el tier gratuito: 30 conversiones, 50 dimensiones, 50 métricas. Si te acercas, te avisa antes de comerte un 400 de la API.
**Los nombres de parámetros son para siempre.** Una vez creas una dimensión o métrica, el nombre del parámetro queda reservado de forma permanente. Aunque la archives. Mi solución es fea pero funciona: versionar los nombres (`reading_time_v3`).
## Úsalo desde tu asistente (MCP)
La pieza que lo cambió todo fue el servidor MCP. Expone las 20 herramientas a Claude Desktop, Claude CLI, VS Code, Cursor y Cline, así que puedo decir en lenguaje normal:
> "Compara el tráfico de la última semana vs la anterior, pasa una auditoría a la home y al post peor posicionado, y dime qué revisar."
Y Claude orquesta las llamadas y junta los resultados. Pero ojo, mismo principio de siempre: me devuelve una lista priorizada, no un `git push`. Las decisiones siguen siendo mías.
Y aquí está la conexión que me tiene enganchado: `gsc_health` está **hecho para un cron**. O sea, no es solo una tool que invoco, sino un [loop que puedo dejar corriendo](/blog/deja-de-promptear-escribe-loops/): un agente que cada lunes mira la indexación, compara el tráfico, y solo me molesta si algo se rompió. Ese es el siguiente escalón. Dejas de preguntar y montas el bucle que pregunta por ti.
## Lo que NO hace (seamos honestos)
- **Audiencias:** la herramienta no las crea. Genera la documentación para que las montes a mano en la UI (la Admin API sí permite crear audiencias; simplemente aún no lo he metido en la herramienta).
- **BigQuery linking:** automatizado. `ga4 link --service bigquery` crea el enlace de exportación vía Admin API.
- **Search Console linking:** manual. La herramienta imprime una guía de setup; el enlace lo terminas tú en la UI.
- **Datos históricos:** esto configura GA4, no migra datos. La recolección empieza después del setup.
## Instalación: un solo script
```bash
git clone https://github.com/garbarok/ga4-manager.git
cd ga4-manager
./scripts/setup.sh
```
El script verifica prerequisitos (`gcloud`, `jq`, `curl`), elige contigo la ruta de auth (ADC para uso personal, service-account key para CI), activa las APIs necesarias, hace smoke-test de cada endpoint, y te imprime qué permisos manuales te quedan. Es idempotente: lo relanzas sin miedo.
## Preguntas rápidas
**¿Es gratis?** Sí, open source con licencia MIT. El código está en [GitHub](https://github.com/garbarok/ga4-manager).
**¿Necesito saber Go?** No. Bajas el binario y escribes YAML.
**¿Puede borrar mis datos?** No. Solo usa la Admin API para configuración; no toca tus datos de analytics. Lo peor sería crear o borrar recursos de config, que siempre puedes recrear. Y `--dry-run` te deja previsualizar todo antes de aplicar.
**¿Las auditorías SEO necesitan una API key de pago?** Solo si quieres Core Web Vitals dentro de `seo_page_audit`. Sin key, PageSpeed Insights limita a una request cada ~100s y la auditoría se salta los CWV. Con una key gratuita tienes la cuota normal.
**¿`gsc_analytics_run` vs `gsc_traffic_compare`?** La primera es una foto de un periodo (top queries, páginas, CTR, posición). La segunda compara dos periodos y te da caídas y subidas por URL. Una para ver lo que tienes, la otra para ver qué cambió.
Si tienes un par de side projects que rara vez tocas, probablemente no lo necesitas. Si llevas tres o más y estás harto de clicar la misma UI por enésima vez: [pruébalo](https://github.com/garbarok/ga4-manager), dale una estrella si te sirve, y abre un issue si algo se rompe (o si encuentras otro bug como el de la lista de sitemaps).
**Lectura relacionada:** por qué `gsc_health` en un cron es el siguiente paso natural: [deja de promptear a tu agente, escribe loops](/blog/deja-de-promptear-escribe-loops/).
---
**P.D.** Si lo pruebas, cuéntame qué te encontró en [Twitter/X](https://x.com/garbarok). Ahora, si me disculpas, tengo un cron que montar.
---
# I Tried Using AI for Code Review on My Side Projects (3 Weeks, Real Results)
URL: https://www.oscargallegoruiz.com/en/blog/gemini-flash-code-review-automation/
Lang: en
> Three weeks pairing Gemini Flash with Claude Code on side projects: 90% of my tests are now AI-written and I ship 3-4x faster. What worked, what broke. →
## The short version, three weeks in
The setup: solo developer, about 3 years of experience, Google One Pro (I was paying for the storage, it happens to bundle Gemini) plus Claude Code, on side projects.
The results: 90% of my tests are now AI-generated but manually reviewed, features ship 3-4x faster, and the split that stuck is Claude Code for planning, Gemini Flash for execution. I still hit usage limits regularly.
The catch: you review everything. AI makes mistakes, and this workflow only survives on personal projects where I can afford to catch my own bugs.
Worth trying? If you're solo, building side projects, and hate repetitive code: yes. If you work on critical systems or can't review AI output carefully: no.
---
## Who am I to tell you this?
I've been coding for about 3 years. Not a senior engineer. I don't manage a team. I don't work at FAANG.
I'm a developer building side projects, trying to ship faster, and poking at AI coding tools to see if they actually help.
So don't read this as a definitive guide or best practices from a 10x engineer. It's three weeks of trying things: what worked, what didn't, what surprised me. If you're in a similar spot (solo dev, side projects, limited time), maybe it saves you the experiment.
## Building solo is slow because the boring jobs are yours too
When you work on side projects alone, everything lands on you:
- Write all the code
- Write all the tests (boring)
- Handle all the styling (tedious)
- Fix all the bugs
- Review your own code (we all know how that goes)
And honestly? Writing tests is repetitive. Tweaking Tailwind classes for hours numbs the brain. Catching my own bugs is hit-or-miss.
I wanted my time on the interesting parts, building features and solving problems, not on the mechanical stuff.
## What I tried, with low expectations
I'd heard people hyping AI coding tools and I was skeptical. "Probably overhyped," I thought.
But I already had a Google One Pro subscription (for storage, not AI), which includes Gemini. And people kept talking about Claude Code. So: try it for a few weeks and see what happens.
Worst case, I waste some time. Best case, I learn something useful.
### Why Gemini Flash specifically
When Google released Gemini 3 Flash, everyone assumed it was the "lite" version of Pro. Faster but less smart. The usual trade-off.
Except the benchmarks said otherwise.
**SWE-bench Verified** (tests AI on real GitHub issues from actual open-source projects):
| Model | SWE-bench Verified | Cost (API, in / out) |
| ------------------ | ------------------ | ---------------------- |
| **Gemini 3 Flash** | **78%** | $0.50 / $3 per 1M |
| Gemini 3 Pro | 76.2% | $2 / $12 per 1M |
Flash scores higher than Pro, runs about 3x faster than Gemini 2.5 Pro (per Google's Artificial Analysis numbers), and costs roughly 4x less than 3 Pro on both input and output. Weird enough to be worth testing.
_(Note: I'm using Google One Pro, not the API, so I don't pay these rates. But I do hit usage limits regularly.)_
## The combo that worked: Claude Code thinks, Gemini Flash types
Here's the thing: I'm not using Gemini Flash alone.
After a week of experimenting, this is the split that actually works for me.
### The hybrid workflow
**1. Claude Code for planning and research.**
- "Research the best way to test this React component"
- "Give me an implementation plan for [feature]"
- "What are the edge cases I should handle?"
Claude Code takes longer but thinks thoroughly. Good for architectural decisions and planning.
**2. Gemini Flash for execution.**
- "Here's the plan Claude gave me. Implement it."
- "Write tests for these functions following this approach"
- "Style this component to match this design"
Gemini Flash executes insanely fast. Sometimes it doesn't think enough, but that's what the plan is for.
Separately? Meh. Together? Actually useful.
### Why the combo holds up
Claude Code is slow but thorough, exactly what you want for architecture. Gemini Flash is fast but sometimes shallow, exactly what you want for implementing a plan that already exists.
Claude Code: "Here's HOW we should solve this and WHY." Gemini Flash: "Got it, implementing now."
**One tool plans, the other one types.** That division of labor feels more reliable than leaning on either tool alone.
## One real feature: 6.5 hours down to 45 minutes
Here's how this plays out in practice, on my own portfolio.
### How I used to work
Building a new blog feature:
1. Research best practices: 1 hour
2. Plan implementation: 30 min
3. Write the code: 2 hours
4. Write tests: 1.5 hours (ugh)
5. Style with Tailwind: 1 hour
6. Fix bugs: 30 min
Total: ~6.5 hours.
### Same feature, with the combo
1. **Ask Claude Code** (5 min):
```
"I want to add a reading progress indicator to blog posts.
What's the best approach? Consider performance and accessibility."
```
Claude gives me a plan: scroll event listener, throttling, ARIA labels, etc.
2. **Hand the plan to Gemini Flash** (10 min):
```
"Implement this reading progress indicator following this plan:
[paste Claude's plan]
Tech stack: Astro, TypeScript, Tailwind"
```
Flash generates the component code in seconds.
3. **Review and refine** (15 min): check the code makes sense, fix the obvious issues, test it manually.
4. **Generate tests with Gemini Flash** (5 min):
```
"Write tests for this component. Check:
- Progress updates on scroll
- Handles edge cases (top/bottom of page)
- Accessibility attributes are present"
```
5. **Final review** (10 min): run the tests, tweak styling if needed, done.
Total: ~45 minutes.
From 6.5 hours to 45 minutes. No magic involved: I just stopped spending my evenings on the mechanical parts of coding.
## Where it actually pays off
### Tests: I write the function, the AI writes the suite
90% of my tests are now AI-written. I review every one of them.
```typescript
// I write this function
function calculateReadingTime(content: string): number {
const wordsPerMinute = 200;
const words = content.split(/\s+/).length;
return Math.ceil(words / wordsPerMinute);
}
// I ask Gemini Flash: "Write tests for calculateReadingTime"
// It generates 8 test cases in 10 seconds
```
Are the tests perfect? No. Sometimes I fix them. But it beats writing them from scratch by a wide margin.
### Tailwind classes without the docs tab
I show Gemini a screenshot or a description of what I want, and it hands back the Tailwind classes.
```
Me: "Create a card component with:
- Subtle shadow
- Rounded corners
- Hover effect that lifts it slightly
- Dark mode support"
Gemini: [gives me the exact Tailwind classes]
Me: [tweaks 2-3 classes, done]
```
Saves me from constantly looking up Tailwind documentation.
### Three throwaway approaches in minutes
Need to try 3 different approaches? The AI generates all 3 in minutes.
I pick the best one and refine it. Much faster than coding all three by hand.
## The honest part: where this falls over
### Google One Pro limits arrive fast
I hit the usage limits pretty often. When that happens I either wait for the reset (annoying), switch to Claude Code (which has its own limits), or do it manually (defeats the purpose).
Reality check: if you plan to lean on this heavily, Google One Pro might not be enough. The API with pay-per-use would be better, but that costs money.
### Flash is sometimes too fast for its own good
It gives me code that works but misses edge cases. Or suggests an approach that's technically correct but overcomplicated for my use case.
That's exactly why Claude Code plans first. Claude thinks deeper, Flash executes faster.
### You still review everything
AI makes mistakes. Sometimes subtle ones.
Last week, Gemini generated a test that looked perfect but was actually testing the wrong thing. I only caught it because I read through the test carefully.
**If you blindly trust AI-generated code, you will ship bugs.** I review every line before committing. Non-negotiable.
### Domain-specific code is hit-or-miss
Generic code? The AI handles it well. Your specific business logic? Not so much.
Example: my blog has a custom date formatting system. The AI kept suggesting I use a library instead. Technically correct, but not what I wanted. I had to add it to the prompt: "Don't suggest libraries for this, just implement the custom logic."
## My actual setup (no GitHub Actions, no API keys)
I use Google One Pro in the browser, so the whole workflow is four phases.
### 1. Planning (Claude Code)
Open Claude Code (web or app) and ask:
```
"I need to [describe feature].
Tech stack: [your stack]
What's the best approach? Think about:
- Implementation steps
- Edge cases
- Testing strategy
- Potential issues"
```
Claude gives me a detailed plan. I save it or keep the chat open.
### 2. Implementation (Gemini Flash)
Copy Claude's plan into Gemini Flash:
```
"Implement this feature following this plan:
[paste Claude's plan]
Tech stack: [your stack]
Files to modify: [list files]
Generate the complete implementation."
```
Gemini generates code fast. I copy it into my editor.
### 3. Testing (Gemini Flash)
```
"Write comprehensive tests for this code:
[paste the code]
Use [your test framework]
Cover edge cases and error scenarios"
```
Gemini generates tests. I review them and add them to my suite.
### 4. Review and refine (me)
Read all the generated code. Check for bugs. Test manually. Fix what's wrong. Commit when it works.
Total time for a typical feature: 30-60 minutes instead of 4-6 hours.
## The numbers after three weeks
Real metrics from my portfolio and side projects.
Code generated:
- Features implemented: 12
- Tests written: ~150 (90% AI-generated, 10% manual)
- Components styled: 8
- Bugs caught by AI tests: 7
Time comparison:
| Task | Before AI | With AI | Savings |
| ----------------------- | --------- | ------- | ------- |
| Feature implementation | 4-6 hours | 1 hour | 75% |
| Writing tests | 2 hours | 20 min | 83% |
| Tailwind styling | 1.5 hours | 15 min | 83% |
| Bug investigation | Variable | Faster | ~50% |
Overall: features ship 3-4x faster than before.
The catch, again: this only works because I review everything. Copy-paste AI code without reading it and you'll ship bugs left and right.
## Flash vs Pro, after a week with each
### Gemini 3 Flash
Best for quick implementation tasks, test generation, styling and UI work, and following a clear plan.
Not great for complex architectural decisions, deep debugging, or dense business logic.
Speed: insanely fast (2-5 seconds for most tasks). Cost: free with Google One Pro, with limits.
### Gemini 3 Pro
Best for architectural decisions, complex problem-solving, deep code analysis, and explaining why something works.
Not great for quick iterations (takes longer) or simple tasks (overkill).
Speed: slower (~10-20 seconds). Cost: same limits on Google One Pro.
My conclusion: Flash for execution tasks (faster, good enough quality), Pro for thinking tasks (deeper reasoning). But honestly? Claude Code beats both for planning.
## The mistakes, week by week
Week 1: I used only Gemini Flash, for everything. Result: fast but messy code with lots of bugs. Lesson: Flash executes, it doesn't plan.
Week 2: I trusted the AI too much. Copied code without reviewing and shipped a bug that broke my contact form for 2 days. Lesson: always review AI-generated code. No exceptions.
Week 3: found the balance. Claude Code for planning, Gemini Flash for execution, thorough review on top. Lesson: the right tool for each job.
## Should you try it?
Yes, if you work solo on side projects, hate writing repetitive code, want to ship faster, and are willing to review AI output carefully.
No, if you enjoy writing every line yourself (totally valid), don't have time to review AI code, work on critical production systems that need more thorough human review, or expect AI to solve all your problems. It won't.
Maybe, if you're skeptical but curious. Fair. Try before committing.
## My honest recommendation
I'm not saying this is THE way to code. I'm saying it's working for me, right now, on my side projects, as someone who's still learning.
What's working: 3-4x faster feature development, 90% of tests AI-generated (and reviewed by me), less time on boring stuff and more on interesting problems.
What's not perfect: I have to review everything, I hit Google One Pro limits, I'm still learning the best prompts, and some tasks the AI just can't handle well.
After three weeks, I'm convinced it's worth trying if you're willing to learn the tools properly, review every line, accept the imperfection, and keep adjusting.
Will it work for you? I honestly don't know. Try it and see.
## FAQ
### Can I use Gemini Flash without paying for Google One Pro?
You can use the free tier of Gemini, but you'll hit usage limits quickly. Google One Pro ($10/month) gives you more generous limits. If you need unlimited usage, the API is pay-per-use (Gemini 3 Flash is $0.50 per million input tokens and $3 per million output tokens).
### Is AI code review as good as human code review?
No. AI is good at catching syntax errors, suggesting implementations, and generating tests. It doesn't understand your specific context, business logic, or architectural constraints. I still review everything myself; the AI just speeds up the mechanical parts.
### Which is better: Gemini Flash or Claude Code?
They're good at different things. Claude Code is better for planning and architectural decisions. Gemini Flash is better for fast execution and test generation. I use both together for the best results.
### How much time does it actually save?
For me, about 3-4x faster on feature development. A feature that took 6 hours now takes ~1.5 hours. But I'm still learning, so your mileage may vary.
### Do I need to know how to code to use AI coding tools?
Yes. AI doesn't replace coding knowledge, it accelerates it. You need to understand code to review the output, catch mistakes, and guide the AI effectively. These tools work best for developers who already know what they're doing.
I've been doing this for three weeks. I'm sure I'm missing things, doing parts of it inefficiently, getting some of it plain wrong. That's the deal with learning in public: you ship the half-formed version and let people poke holes in it.
So poke.
**Related reading:** if you're choosing a Gemini model for this workflow, start with [the Gemini 3 developer guide](/en/blog/gemini-3-developer-guide/).
---
**P.S.** Have you tried AI coding tools? Which workflow works for you, and what am I getting wrong here? Tell me on [Twitter/X](https://x.com/garbarok). And if you try this setup, I want to hear how it goes, especially the parts that don't work.
---
# Probé Usar IA para Revisión de Código en Mis Proyectos (3 Semanas, Resultados Reales)
URL: https://www.oscargallegoruiz.com/blog/gemini-flash-code-review-automatizado/
Lang: es
> Tres semanas combinando Gemini Flash y Claude Code en proyectos personales: el 90% de mis tests los escribe la IA y voy 3-4x más rápido. Qué falló. →
## La versión corta, tras tres semanas
El setup: desarrollador trabajando solo, unos 3 años de experiencia, Google One Pro (pagaba por el almacenamiento, resulta que incluye Gemini) más Claude Code, en proyectos personales.
Los resultados: el 90% de mis tests ahora los genera la IA pero los reviso a mano, las features salen 3-4x más rápido, y el reparto que se quedó es Claude Code para planificar, Gemini Flash para ejecutar. Sigo alcanzando los límites de uso regularmente.
El pero: lo revisas todo. La IA comete errores, y este flujo solo sobrevive en proyectos personales donde puedo permitirme cazar mis propios bugs.
¿Vale la pena probarlo? Si trabajas solo, en proyectos personales, y odias el código repetitivo: sí. Si trabajas en sistemas críticos o no puedes revisar el output de la IA con cuidado: no.
---
## ¿Quién soy yo para contarte esto?
Llevo unos 3 años programando. No soy ingeniero senior. No gestiono equipos. No trabajo en FAANG.
Soy un desarrollador construyendo proyectos personales, intentando lanzar más rápido, y trasteando con herramientas de IA para ver si de verdad ayudan.
Así que no leas esto como una guía definitiva ni como las mejores prácticas de un ingeniero 10x. Son tres semanas de probar cosas: qué funcionó, qué no, qué me sorprendió. Si estás en una situación parecida (desarrollador solo, proyectos personales, tiempo limitado), quizá te ahorre el experimento.
## Desarrollar solo es lento porque lo aburrido también te toca a ti
Cuando trabajas en proyectos personales solo, todo cae sobre ti:
- Escribir todo el código
- Escribir todos los tests (aburrido)
- Manejar todo el styling (tedioso)
- Arreglar todos los bugs
- Revisar tu propio código (ya sabemos cómo va eso)
¿Y honestamente? Escribir tests es repetitivo. Ajustar clases de Tailwind durante horas atonta. Detectar mis propios bugs es hit-or-miss.
Yo quería mi tiempo en las partes interesantes, construir features y resolver problemas, no en lo mecánico.
## Lo que probé, con expectativas bajas
Había escuchado a gente hypeando las herramientas de IA para programar y yo era escéptico. "Probablemente está sobrevalorado", pensé.
Pero ya tenía una suscripción de Google One Pro (por el almacenamiento, no por la IA), que incluye Gemini. Y la gente no paraba de hablar de Claude Code. Así que: probarlo unas semanas y ver qué pasa.
Peor caso, pierdo algo de tiempo. Mejor caso, aprendo algo útil.
### Por qué Gemini Flash en concreto
Cuando Google lanzó Gemini 3 Flash, todos asumieron que era la versión "lite" de Pro. Más rápido pero menos inteligente. El trade-off de siempre.
Excepto que los benchmarks decían lo contrario.
**SWE-bench Verified** (prueba IA con issues reales de GitHub de proyectos open-source):
| Modelo | SWE-bench Verified | Coste (API, in / out) |
| ------------------ | ------------------ | ---------------------- |
| **Gemini 3 Flash** | **78%** | $0.50 / $3 por 1M |
| Gemini 3 Pro | 76.2% | $2 / $12 por 1M |
Flash puntúa más alto que Pro, corre unas 3x más rápido que Gemini 2.5 Pro (según los números de Artificial Analysis de Google), y cuesta más o menos 4x menos que 3 Pro tanto en input como en output. Lo bastante raro como para probarlo.
_(Nota: uso Google One Pro, no la API, así que no pago estas tarifas. Pero sí alcanzo los límites de uso regularmente.)_
## El combo que funcionó: Claude Code piensa, Gemini Flash teclea
Aquí está la cosa: no estoy usando Gemini Flash solo.
Después de una semana de experimentar, este es el reparto que de verdad me funciona.
### El flujo híbrido
**1. Claude Code para planificación e investigación.**
- "Investiga la mejor forma de testear este componente de React"
- "Dame un plan de implementación para [feature]"
- "¿Cuáles son los edge cases que debería manejar?"
Claude Code tarda más pero piensa a fondo. Bueno para decisiones arquitectónicas y planificación.
**2. Gemini Flash para ejecución.**
- "Aquí está el plan que Claude me dio. Impleméntalo."
- "Escribe tests para estas funciones siguiendo este enfoque"
- "Estiliza este componente para que coincida con este diseño"
Gemini Flash ejecuta increíblemente rápido. A veces no piensa suficiente, pero para eso está el plan.
¿Por separado? Meh. ¿Juntos? Realmente útil.
### Por qué el combo se sostiene
Claude Code es lento pero exhaustivo, justo lo que quieres para arquitectura. Gemini Flash es rápido pero a veces superficial, justo lo que quieres para implementar un plan que ya existe.
Claude Code: "Así es CÓMO deberíamos resolver esto y POR QUÉ." Gemini Flash: "Entendido, implementando ahora."
**Una herramienta planifica, la otra teclea.** Ese reparto del trabajo es más fiable que apoyarse en una sola.
## Una feature real: de 6.5 horas a 45 minutos
Así es como funciona esto en la práctica, en mi propio portfolio.
### Cómo trabajaba antes
Construyendo una nueva feature para el blog:
1. Investigar mejores prácticas: 1 hora
2. Planificar implementación: 30 min
3. Escribir el código: 2 horas
4. Escribir tests: 1.5 horas (ugh)
5. Estilos con Tailwind: 1 hora
6. Arreglar bugs: 30 min
Total: ~6.5 horas.
### La misma feature, con el combo
1. **Pregunto a Claude Code** (5 min):
```
"Quiero añadir un indicador de progreso de lectura a los posts del blog.
¿Cuál es el mejor enfoque? Considera rendimiento y accesibilidad."
```
Claude me da un plan: scroll event listener, throttling, etiquetas ARIA, etc.
2. **Le paso el plan a Gemini Flash** (10 min):
```
"Implementa este indicador de progreso de lectura siguiendo este plan:
[pego el plan de Claude]
Tech stack: Astro, TypeScript, Tailwind"
```
Flash genera el código del componente en segundos.
3. **Revisar y refinar** (15 min): comprobar que el código tiene sentido, arreglar lo obvio, testear a mano.
4. **Generar tests con Gemini Flash** (5 min):
```
"Escribe tests para este componente. Verifica:
- El progreso se actualiza al hacer scroll
- Maneja edge cases (arriba/abajo de la página)
- Los atributos de accesibilidad están presentes"
```
5. **Revisión final** (10 min): ejecutar los tests, ajustar estilos si hace falta, listo.
Total: ~45 minutos.
De 6.5 horas a 45 minutos. Sin magia: simplemente dejé de gastar mis tardes en las partes mecánicas de programar.
## Dónde compensa de verdad
### Tests: yo escribo la función, la IA escribe la suite
El 90% de mis tests ahora los escribe la IA. Yo reviso cada uno.
```typescript
// Yo escribo esta función
function calculateReadingTime(content: string): number {
const wordsPerMinute = 200;
const words = content.split(/\s+/).length;
return Math.ceil(words / wordsPerMinute);
}
// Pregunto a Gemini Flash: "Escribe tests para calculateReadingTime"
// Genera 8 casos de test en 10 segundos
```
¿Son perfectos? No. A veces los arreglo. Pero le saca mucha distancia a escribirlos desde cero.
### Clases de Tailwind sin la pestaña de docs
Le muestro a Gemini una captura o una descripción de lo que quiero, y me devuelve las clases de Tailwind.
```
Yo: "Crea un componente de tarjeta con:
- Sombra sutil
- Esquinas redondeadas
- Efecto hover que la levante ligeramente
- Soporte para dark mode"
Gemini: [me da las clases exactas de Tailwind]
Yo: [ajusto 2-3 clases, listo]
```
Me ahorra estar buscando constantemente en la documentación de Tailwind.
### Tres enfoques desechables en minutos
¿Necesitas probar 3 enfoques diferentes? La IA genera los 3 en minutos.
Elijo el mejor y lo refino. Mucho más rápido que codificar los tres a mano.
## La parte honesta: dónde se cae
### Los límites de Google One Pro llegan rápido
Alcanzo los límites de uso bastante a menudo. Cuando pasa, o espero a que se resetee el límite (molesto), o cambio a Claude Code (que tiene sus propios límites), o lo hago a mano (anula el propósito).
Seamos realistas: si planeas usar esto intensivamente, Google One Pro puede no ser suficiente. La API con pago por uso sería mejor, pero cuesta dinero.
### Flash a veces es demasiado rápido para su propio bien
Me da código que funciona pero se pierde edge cases. O sugiere un enfoque técnicamente correcto pero sobrecomplicado para mi caso de uso.
Justo por eso Claude Code planifica primero. Claude piensa más profundo, Flash ejecuta más rápido.
### Sigues revisando todo
La IA comete errores. A veces sutiles.
La semana pasada, Gemini generó un test que se veía perfecto pero en realidad estaba probando lo incorrecto. Solo lo cacé porque leí el test con calma.
**Si confías ciegamente en código generado por IA, vas a lanzar bugs.** Reviso cada línea antes de hacer commit. No negociable.
### Lo específico del dominio es hit-or-miss
¿Código genérico? La IA lo maneja bien. ¿Tu lógica de negocio concreta? No tanto.
Ejemplo: mi blog tiene un sistema de formateo de fechas personalizado. La IA insistía en que usara una librería en su lugar. Técnicamente correcto, pero no lo que yo quería. Tuve que añadirlo al prompt: "No sugieras librerías para esto, solo implementa la lógica personalizada."
## Mi setup real (sin GitHub Actions ni API keys)
Uso Google One Pro en el navegador, así que el flujo entero son cuatro fases.
### 1. Planificación (Claude Code)
Abro Claude Code (web o app) y pregunto:
```
"Necesito [describir feature].
Tech stack: [tu stack]
¿Cuál es el mejor enfoque? Piensa en:
- Pasos de implementación
- Edge cases
- Estrategia de testing
- Problemas potenciales"
```
Claude me da un plan detallado. Lo guardo o mantengo el chat abierto.
### 2. Implementación (Gemini Flash)
Copio el plan de Claude en Gemini Flash:
```
"Implementa esta feature siguiendo este plan:
[pego el plan de Claude]
Tech stack: [tu stack]
Archivos a modificar: [lista archivos]
Genera la implementación completa."
```
Gemini genera código rápido. Lo copio en mi editor.
### 3. Testing (Gemini Flash)
```
"Escribe tests completos para este código:
[pego el código]
Usa [tu framework de tests]
Cubre edge cases y escenarios de error"
```
Gemini genera tests. Los reviso y los añado a mi suite.
### 4. Revisar y refinar (yo)
Leo todo el código generado. Busco bugs. Testeo a mano. Arreglo lo que esté mal. Commit cuando todo funciona.
Tiempo total para una feature típica: 30-60 minutos en lugar de 4-6 horas.
## Los números tras tres semanas
Métricas reales de mi portfolio y proyectos personales.
Código generado:
- Features implementadas: 12
- Tests escritos: ~150 (90% generados por IA, 10% manuales)
- Componentes estilizados: 8
- Bugs detectados por tests de IA: 7
Comparación de tiempos:
| Tarea | Antes de IA | Con IA | Ahorro |
| -------------------------- | ----------- | ------ | ------ |
| Implementación de features | 4-6 horas | 1 hora | 75% |
| Escribir tests | 2 horas | 20 min | 83% |
| Estilos con Tailwind | 1.5 horas | 15 min | 83% |
| Investigación de bugs | Variable | Más rápido | ~50% |
En general: las features salen 3-4x más rápido que antes.
El pero, otra vez: esto solo funciona porque lo reviso todo. Copia y pega código de IA sin leerlo y lanzarás bugs a diestra y siniestra.
## Flash vs Pro, una semana con cada uno
### Gemini 3 Flash
Mejor para tareas de implementación rápidas, generación de tests, trabajo de styling y UI, y seguir un plan claro.
No tan bueno para decisiones arquitectónicas complejas, debugging profundo, o lógica de negocio densa.
Velocidad: increíblemente rápido (2-5 segundos para la mayoría de tareas). Coste: gratis con Google One Pro, con límites.
### Gemini 3 Pro
Mejor para decisiones arquitectónicas, resolución de problemas complejos, análisis profundo de código, y explicar por qué algo funciona.
No tan bueno para iteraciones rápidas (tarda más) ni tareas simples (overkill).
Velocidad: más lento (~10-20 segundos). Coste: mismos límites en Google One Pro.
Mi conclusión: Flash para tareas de ejecución (más rápido, calidad suficiente), Pro para tareas de pensamiento (razonamiento más profundo). ¿Pero honestamente? Claude Code gana a ambos para planificar.
## Los errores, semana a semana
Semana 1: usé solo Gemini Flash, para todo. Resultado: código rápido pero desordenado y con muchos bugs. Lección: Flash ejecuta, no planifica.
Semana 2: confié demasiado en la IA. Copié código sin revisar y lancé un bug que rompió mi formulario de contacto durante 2 días. Lección: siempre revisa el código generado por IA. Sin excepciones.
Semana 3: encontré el equilibrio. Claude Code para planificar, Gemini Flash para ejecutar, revisión exhaustiva encima. Lección: la herramienta correcta para cada trabajo.
## ¿Deberías probarlo?
Sí, si trabajas solo en proyectos personales, odias escribir código repetitivo, quieres lanzar más rápido, y estás dispuesto a revisar el output de la IA con cuidado.
No, si disfrutas escribiendo cada línea tú mismo (totalmente válido), no tienes tiempo para revisar código de IA, trabajas en sistemas críticos de producción que necesitan revisión humana más exhaustiva, o esperas que la IA resuelva todos tus problemas. No lo hará.
Quizás, si eres escéptico pero curioso. Justo. Prueba antes de comprometerte.
## Mi recomendación honesta
No digo que esta sea LA forma de programar. Digo que me está funcionando a mí, ahora mismo, en mis proyectos personales, como alguien que todavía está aprendiendo.
Lo que funciona: desarrollo de features 3-4x más rápido, 90% de tests generados por IA (y revisados por mí), menos tiempo en lo aburrido y más en problemas interesantes.
Lo que no es perfecto: tengo que revisarlo todo, alcanzo los límites de Google One Pro, todavía estoy aprendiendo los mejores prompts, y hay tareas que la IA simplemente no maneja bien.
Después de tres semanas, estoy convencido de que vale la pena probarlo si estás dispuesto a aprender las herramientas en serio, revisar cada línea, aceptar la imperfección, y seguir ajustando.
¿Te funcionará a ti? Honestamente no lo sé. Pruébalo y verás.
## Preguntas frecuentes
### ¿Puedo usar Gemini Flash sin pagar por Google One Pro?
Puedes usar el tier gratuito de Gemini, pero alcanzarás los límites de uso rápidamente. Google One Pro ($10/mes) te da límites más generosos. Si necesitas uso ilimitado, la API es pago por uso (Gemini 3 Flash cuesta $0.50 por millón de tokens de input y $3 por millón de tokens de output).
### ¿La revisión de código con IA es tan buena como la humana?
No. La IA es buena detectando errores de sintaxis, sugiriendo implementaciones, y generando tests. No entiende tu contexto específico, tu lógica de negocio, ni tus restricciones arquitectónicas. Sigo revisando todo yo mismo; la IA solo acelera las partes mecánicas.
### ¿Cuál es mejor: Gemini Flash o Claude Code?
Son buenos para cosas diferentes. Claude Code es mejor para planificación y decisiones arquitectónicas. Gemini Flash es mejor para ejecución rápida y generación de tests. Uso ambos juntos para mejores resultados.
### ¿Cuánto tiempo ahorra realmente?
Para mí, alrededor de 3-4x más rápido en desarrollo de features. Una feature que tomaba 6 horas ahora toma ~1.5 horas. Pero todavía estoy aprendiendo, así que tu experiencia puede variar.
### ¿Necesito saber programar para usar herramientas de IA para código?
Sí. La IA no reemplaza el conocimiento de programación, lo acelera. Necesitas entender código para revisar el output, cazar errores, y guiar a la IA. Estas herramientas funcionan mejor para desarrolladores que ya saben lo que hacen.
Llevo tres semanas con esto. Seguro que me estoy perdiendo cosas, haciendo partes de forma ineficiente, equivocándome en otras. Ese es el trato de aprender en público: publicas la versión a medio formar y dejas que la gente le busque los agujeros.
Pues búscalos.
**Lectura relacionada:** si estás eligiendo modelo de Gemini para este flujo, empieza por [la guía de Gemini 3 para desarrolladores](/blog/gemini-3-guia-desarrollador/).
---
**P.D.** ¿Has probado herramientas de IA para programar? ¿Qué flujo te funciona, y en qué me estoy equivocando? Cuéntamelo en [Twitter/X](https://x.com/garbarok). Y si pruebas este setup, quiero saber cómo te va, sobre todo las partes que no funcionan.
---
# Astro 6 Migration Guide (2026): from Astro 5
URL: https://www.oscargallegoruiz.com/en/blog/astro-6-migration-guide/
Lang: en
> I upgraded this site from Astro 5 to Astro 6. The breaking changes that bit me: content.config.ts, the slug to id trap, Zod 4 defaults, removed APIs. →
I upgraded this very site from Astro 5 to Astro 6 last weekend. The plan was a quick `pnpm up astro`, a glance at the changelog, and a celebratory coffee.
I did not get the coffee.
I spent the first hour staring at a `ContentSchemaContainsSlugError` that read like a riddle, and another forty minutes untangling a Zod default that compiled fine in v5 and exploded in v6.
Here is the good news before the war story: v6 is mostly an evolution of v5, not a rewrite. Same Content Layer, same Server Islands. What changed is that the grace periods are over. The legacy escape hatches that let you limp along on v4-shaped code in v5 are gone. So if your v5 upgrade was half-finished, v6 is where the bill comes due.
This post is the upgrade path I actually walked, v5 to v6, with the breaking changes that bit me first. If you are coming straight from Astro 4, jump to [the section at the bottom](#still-on-astro-4-the-v4-to-v5-story); the v5 foundations still apply and you will want them first.
## What breaks going from 5 to 6 (the 60-second version)
Everything below is from the official [upgrade to v6 guide](https://docs.astro.build/en/guides/upgrade-to/v6/), cross-checked against my own diff:
- **Node `v22.12.0` is the new minimum**, and only even-numbered releases are supported. v23 will not run it.
- **`src/content.config.ts` is mandatory** if you use content collections. The old `src/content/config.ts` location is no longer read.
- **The `legacy.collections` flag is gone.** If you were leaning on it in v5, that crutch has been kicked away.
- **The identifier is `post.id`, not `post.slug`.** The Content Layer made `id` the identifier back in v5; v6 just removes the legacy collections fallback, so there is no `slug` left to lean on. A `slug` field in a schema throws `ContentSchemaContainsSlugError`.
- **`Astro.glob()` is removed.** Replace it with `import.meta.glob()` (which no longer returns a Promise) or `getCollection()`.
- **Zod is on v4.** Default values must match the output type after transforms, and `astro:schema` imports move to `astro/zod`.
- **`getEntryBySlug()` and `getDataEntryById()` are deprecated** in favor of a single `getEntry()`.
If you only read one line: the v5 to v6 jump is not about new toys. It is about finally deleting the compatibility shims you have been ignoring.
## The slug to id trap (the one that cost me an hour)
This is where v6 hit me hardest, because the error message points at your schema, not at the real culprit.
In Astro 4, every content entry had a `slug`, and most of us wired it straight into `getStaticPaths`. Astro 5's Content Layer already moved the identifier to `id`, but the legacy collections path kept `slug` limping along, so sloppy code survived. Astro 6 removes that legacy path. No more `slug` to fall back on.
Here is the diff that fixed my build:
```astro
---
// src/pages/blog/[...slug].astro
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
// Astro 5 leftover: post.slug is gone in v6
// params: { slug: post.slug },
params: { slug: post.id },
props: post,
}));
}
---
```
If your schema also declares a `slug` field, that is what trips `ContentSchemaContainsSlugError`. Remove it and let the `glob` loader derive the id from the filename. Do a global search for `.slug` before you upgrade. On a 50-file project it is the difference between a five-minute fix and an afternoon.
## Zod 4: the default that lies to you
The second wall. In Zod 3 (Astro 5), a default value matched the *input* type. In Zod 4 (Astro 6), it has to match the *output* type, the one you get after transforms run.
So this, which I had copied from my own homepage view counter, broke:
```typescript
// Astro 5, Zod 3: default is the pre-transform string
views: z.string().transform(Number).default("0"),
// Astro 6, Zod 4: default must match the post-transform number
views: z.string().transform(Number).default(0),
```
While you are in there, fix the imports too. `astro:schema` is deprecated in v6:
```typescript
// Before
import { z } from "astro:schema";
// After
import { z } from "astro/zod";
```
You do not strictly need the `astro/zod` path. `zod` is a direct dependency in Astro 6, so plain `import { z } from "zod"` works too, and it is what I run in production. `astro/zod` just re-exports the exact Zod version Astro validates your schemas against, so you cannot drift onto a mismatched copy.
`.nonempty()` on strings is also gone in Zod 4. Swap it for `.min(1)`.
## The removed APIs, and what to use instead
`Astro.glob()` was deprecated back in v5 and is now fully removed. The replacement depends on what you were globbing:
```typescript
// Querying content collections? Use the Content Layer.
const posts = await getCollection('blog');
// Globbing arbitrary source files? import.meta.glob, and note:
// it no longer returns a Promise, so drop the await.
const modules = import.meta.glob('./data/*.json', { eager: true });
```
For collection lookups, `getEntryBySlug()` and `getDataEntryById()` both collapse into one function:
```typescript
// Before
const post = await getEntryBySlug('blog', 'my-post');
// After
const post = await getEntry('blog', 'my-post');
```
And the cleanup that took ten seconds but felt the best: deleting the `legacy` block from `astro.config.mjs`.
```typescript
import { defineConfig } from 'astro/config';
export default defineConfig({
// Delete this whole block. It does nothing in v6 except remind
// you that you put off the real migration.
legacy: {
collections: true,
},
});
```
## content.config.ts: the glob() loader and defineCollection
None of the above is the reason to upgrade. The reason is the thing v5 introduced and v6 makes the only way: the Content Layer is a real data pipeline, not just a Markdown reader. It all lives in `content.config.ts`, where every collection is a `defineCollection` paired with a loader. For local Markdown that loader is `glob()` (shown in the v4 section below); the power is that you can swap it for one you write yourself.
The `glob` loader you wire up in `content.config.ts` is just a function that returns an array of objects. Which means you can write your own. Here is the loader I use to pull GitHub stars into my projects section, with no top-level `fetch()` rotting inside a component:
```typescript
// src/content.config.ts
import { defineCollection } from 'astro:content';
import { z } from 'astro/zod';
const githubLoader = {
name: 'github-repos',
load: async ({ store, logger }) => {
logger.info('Fetching repos from GitHub...');
const response = await fetch('https://api.github.com/users/garbarok/repos');
const repos = await response.json();
for (const repo of repos) {
store.set({
id: repo.name,
data: {
description: repo.description,
stars: repo.stargazers_count,
url: repo.html_url,
},
});
}
},
};
const projects = defineCollection({
loader: githubLoader,
schema: z.object({
stars: z.coerce.number(),
url: z.string().url(),
}),
});
export const collections = { projects };
```
In my components I just call `getCollection('projects')`. The frontend has no idea the data came from an API, and Astro caches it at build time. That separation is what the migration buys you.
Server Islands (`server:defer`) are the other v5 idea that carries straight into v6 unchanged. A static shell on the CDN with a dynamic hole that gets filled by a tiny per-island fetch. No hydration, no client React. If you skipped it in v5, v6 is a fine excuse to finally use it.
## The honest part: where v6 is annoying
I promised a war story, not a brochure.
The `ContentSchemaContainsSlugError` message is genuinely bad. It blames your schema when the real problem is usually a `params: { slug: post.slug }` three files away. I lost time chasing the wrong line.
The Zod 4 default change is the kind of break that compiles, passes a quick smoke test, and then serves wrong data in production because `"0"` and `0` both look fine until something downstream does math. Test your defaults, not just your types.
And the `import.meta.glob()` "no longer returns a Promise" change is easy to miss because removing an `await` from working code feels wrong. It will not error loudly. It will just hand you a Promise where you expected data.
None of these are dealbreakers. But anyone selling v6 as a frictionless bump has not migrated a real project.
## The questions you were going to ask anyway
**Do I have to go through v5 to get to v6?**
Yes, in practice. The upgrade guides are sequential, and v6 assumes your collections already use the Content Layer. If you are on v4, do the v5 work first (below), confirm a green build, then take the v6 step.
**Can I keep the legacy collections flag a little longer?**
No. It is removed, not deprecated. v6 will not read `src/content/config.ts` and will not honor `legacy.collections`. Plan the migration before you bump the version, not after.
**Can I use Server Islands on Vercel or Netlify?**
Yes, with the matching adapter installed. The island is a serverless function that returns HTML, so you need a host that runs functions. Nothing about that changed in v6.
## Still on Astro 4? The v4 to v5 story
Everything above assumes you already made the v4 to v5 jump. If you did not, this is the part that still matters, because the Content Layer was born here.
In Astro 4, you defined collections with a magic string:
```typescript
// Astro 4, the old way
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content', // "look for files, somehow"
schema: z.object({ /* ... */ }),
});
```
Astro 5 stopped believing in magic and asked for explicit loaders:
```typescript
// Astro 5+, the new way
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
pubDate: z.date(),
}),
});
```
Two more v4-era traps that v6 simply assumes you have already fixed:
The `output: 'hybrid'` mode is gone. Astro is now static by default with opt-in SSR, or server by default with opt-in static. Delete `hybrid` from your config.
And `post.render()` no longer exists. Content entries are plain objects now, so you import the renderer:
```typescript
import { render } from 'astro:content';
const { Content } = await render(post);
```
Do that work, get a green v5 build, and the v6 step at the top of this post becomes a quiet afternoon instead of a bad one.
**Related reading:** the nastiest trap in this whole saga earned its own post. [How a misplaced `content.config.ts` silently ate my schema fields](/en/blog/astro-content-config-location/), and the five-minute fix. If you are pairing with an AI assistant for this kind of multi-file refactor, my [Google Antigravity review](/en/blog/google-antigravity-review/) covers the agent-first IDEs I tried while doing this upgrade.
## Sources
- [Astro docs: Upgrade to v6](https://docs.astro.build/en/guides/upgrade-to/v6/)
- [Astro docs: Content Collections](https://docs.astro.build/en/guides/content-collections/)
---
**P.S.** Have you taken the v6 step yet? Did the `slug` to `id` change break your heart twice, once in v5 and once in v6? Tell me on [Twitter/X](https://x.com/garbarok).
---
# Guía de Migración a Astro 6 (2026) desde Astro 5
URL: https://www.oscargallegoruiz.com/blog/astro-6-guia-migracion/
Lang: es
> Actualicé este sitio de Astro 5 a Astro 6. Breaking changes que me mordieron: content.config.ts, la trampa slug a id, defaults de Zod 4, APIs eliminadas. →
El fin de semana pasado actualicé este mismo sitio de Astro 5 a Astro 6. El plan era un `pnpm up astro` rápido, un vistazo al changelog y un café para celebrarlo.
Del café, nada.
Me pasé la primera hora mirando un `ContentSchemaContainsSlugError` que parecía un acertijo, y otros cuarenta minutos desenredando un default de Zod que compilaba perfecto en v5 y explotaba en v6.
La buena noticia antes de la batallita: v6 es una evolución de v5, no una reescritura. Mismo Content Layer, mismas Server Islands. Lo que cambia es que se acabaron los periodos de gracia. Las escotillas de emergencia que te dejaban tirar en v5 con código con pinta de v4 ya no están. Así que si tu migración a v5 quedó a medias, v6 es donde te pasan la factura.
Este post es la ruta que recorrí de verdad, de v5 a v6, con los breaking changes que me mordieron primero. Si vienes directo de Astro 4, salta a [la sección del final](#sigues-en-astro-4-la-historia-de-v4-a-v5): los cimientos de v5 siguen valiendo y los vas a necesitar antes.
## Qué se rompe al pasar de 5 a 6 (versión de 60 segundos)
Todo lo de abajo sale de la [guía oficial de upgrade a v6](https://docs.astro.build/en/guides/upgrade-to/v6/), contrastado con mi propio diff:
- **Node `v22.12.0` es el nuevo mínimo**, y solo se soportan versiones pares. La v23 no lo arranca.
- **`src/content.config.ts` es obligatorio** si usas content collections. La ruta antigua `src/content/config.ts` ya no se lee.
- **El flag `legacy.collections` desaparece.** Si te apoyabas en él en v5, te han quitado la muleta.
- **El identificador es `post.id`, no `post.slug`.** La Content Layer ya movió el identificador a `id` en v5; v6 solo elimina el fallback de las colecciones legacy, así que no queda `slug` al que agarrarse. Un campo `slug` en un schema lanza `ContentSchemaContainsSlugError`.
- **`Astro.glob()` se elimina.** Cámbialo por `import.meta.glob()` (que ya no devuelve una Promise) o por `getCollection()`.
- **Zod va por la v4.** Los valores por defecto tienen que coincidir con el tipo de salida tras los transforms, y los imports de `astro:schema` pasan a `astro/zod`.
- **`getEntryBySlug()` y `getDataEntryById()` quedan deprecados** en favor de un único `getEntry()`.
Si solo te quedas con una idea: el salto de v5 a v6 no va de juguetes nuevos. Va de borrar por fin los parches de compatibilidad que llevabas ignorando.
## La trampa de slug a id (la que me costó una hora)
Aquí es donde v6 me pegó más fuerte, porque el mensaje de error apunta a tu schema, no al culpable real.
En Astro 4, cada entry tenía un `slug` y casi todos lo metíamos directo en `getStaticPaths`. La Content Layer de Astro 5 ya movió el identificador a `id`, pero la vía de las colecciones legacy mantenía el `slug` con vida, así que el código chapucero sobrevivía. Astro 6 elimina esa vía legacy. Ya no hay `slug` al que recurrir.
Este es el diff que arregló mi build:
```astro
---
// src/pages/blog/[...slug].astro
export async function getStaticPaths() {
const posts = await getCollection('blog');
return posts.map((post) => ({
// Resto de Astro 5: post.slug ya no existe en v6
// params: { slug: post.slug },
params: { slug: post.id },
props: post,
}));
}
---
```
Si tu schema además declara un campo `slug`, eso es lo que dispara `ContentSchemaContainsSlugError`. Quítalo y deja que el loader `glob` derive el id del nombre del archivo. Haz un "Find in Files" de `.slug` antes de actualizar. En un proyecto de 50 archivos es la diferencia entre un arreglo de cinco minutos y una tarde entera.
## Zod 4: el default que te miente
El segundo golpe. En Zod 3 (Astro 5), el valor por defecto coincidía con el tipo de *entrada*. En Zod 4 (Astro 6) tiene que coincidir con el tipo de *salida*, el que te queda después de que se ejecuten los transforms.
Así que esto, copiado de mi propio contador de visitas de la home, se rompió:
```typescript
// Astro 5, Zod 3: el default es el string previo al transform
views: z.string().transform(Number).default("0"),
// Astro 6, Zod 4: el default tiene que ser el number posterior al transform
views: z.string().transform(Number).default(0),
```
Ya que estás ahí, arregla también los imports. `astro:schema` queda deprecado en v6:
```typescript
// Antes
import { z } from "astro:schema";
// Después
import { z } from "astro/zod";
```
No necesitas obligatoriamente la ruta `astro/zod`. `zod` es dependencia directa en Astro 6, así que `import { z } from "zod"` a secas también funciona, y es lo que uso en producción. `astro/zod` solo reexporta la versión exacta de Zod contra la que Astro valida tus schemas, para que no acabes en una copia descuadrada.
El `.nonempty()` sobre strings también desaparece en Zod 4. Cámbialo por `.min(1)`.
## Las APIs eliminadas, y qué usar en su lugar
`Astro.glob()` quedó deprecado ya en v5 y ahora se elimina del todo. El reemplazo depende de qué estuvieras globbeando:
```typescript
// ¿Consultas content collections? Usa el Content Layer.
const posts = await getCollection('blog');
// ¿Globbeas ficheros sueltos? import.meta.glob, y ojo:
// ya no devuelve una Promise, así que quita el await.
const modules = import.meta.glob('./data/*.json', { eager: true });
```
Para buscar entries de una colección, `getEntryBySlug()` y `getDataEntryById()` colapsan en una sola función:
```typescript
// Antes
const post = await getEntryBySlug('blog', 'my-post');
// Después
const post = await getEntry('blog', 'my-post');
```
Y la limpieza que tardó diez segundos pero sentó mejor que ninguna: borrar el bloque `legacy` de `astro.config.mjs`.
```typescript
import { defineConfig } from 'astro/config';
export default defineConfig({
// Borra el bloque entero. En v6 no hace nada salvo recordarte
// que pospusiste la migración de verdad.
legacy: {
collections: true,
},
});
```
## content.config.ts: el loader glob() y defineCollection
Nada de lo anterior es la razón para actualizar. La razón es lo que v5 introdujo y v6 convierte en el único camino: el Content Layer es un pipeline de datos de verdad, no un simple lector de Markdown. Todo vive en `content.config.ts`, donde cada colección es un `defineCollection` con su loader. Para Markdown local ese loader es `glob()` (lo ves en la sección de v4 más abajo); la potencia está en que puedes cambiarlo por uno que escribas tú.
El loader `glob` que montas en `content.config.ts` es solo una función que devuelve un array de objetos. Lo cual significa que puedes escribir el tuyo. Este es el loader que uso para traer mis estrellas de GitHub a la sección de proyectos, sin un `fetch()` pudriéndose en el top-level de un componente:
```typescript
// src/content.config.ts
import { defineCollection } from 'astro:content';
import { z } from 'astro/zod';
const githubLoader = {
name: 'github-repos',
load: async ({ store, logger }) => {
logger.info('Fetching repos from GitHub...');
const response = await fetch('https://api.github.com/users/garbarok/repos');
const repos = await response.json();
for (const repo of repos) {
store.set({
id: repo.name,
data: {
description: repo.description,
stars: repo.stargazers_count,
url: repo.html_url,
},
});
}
},
};
const projects = defineCollection({
loader: githubLoader,
schema: z.object({
stars: z.coerce.number(),
url: z.string().url(),
}),
});
export const collections = { projects };
```
En mis componentes solo llamo a `getCollection('projects')`. Al frontend le da igual de dónde vino el dato, y Astro lo cachea en tiempo de build. Esa separación es lo que ganas con la migración.
Las Server Islands (`server:defer`) son la otra idea de v5 que pasa a v6 tal cual. Un shell estático en el CDN con un hueco dinámico que se rellena con un fetch minúsculo por isla. Sin hidratación, sin React en el cliente. Si te la saltaste en v5, v6 es buena excusa para usarla por fin.
## La parte honesta: dónde v6 da rabia
Te prometí una batallita, no un folleto comercial.
El mensaje `ContentSchemaContainsSlugError` es malo de verdad. Culpa a tu schema cuando el problema real suele ser un `params: { slug: post.slug }` tres ficheros más allá. Perdí tiempo persiguiendo la línea equivocada.
El cambio del default de Zod 4 es de los que compilan, pasan un smoke test rápido y luego sirven datos mal en producción, porque `"0"` y `0` parecen iguales hasta que algo más abajo hace cuentas. Testea tus defaults, no solo tus tipos.
Y lo de `import.meta.glob()` que "ya no devuelve una Promise" se pasa por alto fácil, porque quitar un `await` de código que funcionaba da cosa. No va a fallar con estruendo. Solo te va a dar una Promise donde esperabas datos.
Ninguno es un dealbreaker. Pero quien te venda v6 como un bump sin fricción no ha migrado un proyecto de verdad.
## Las preguntas que me ibas a hacer igualmente
**¿Tengo que pasar por v5 para llegar a v6?**
En la práctica, sí. Las guías de upgrade son secuenciales, y v6 asume que tus colecciones ya usan el Content Layer. Si estás en v4, haz primero el trabajo de v5 (abajo), confirma un build verde y entonces da el paso a v6.
**¿Puedo aguantar un poco más con el flag de legacy collections?**
No. Está eliminado, no deprecado. v6 no leerá `src/content/config.ts` ni respetará `legacy.collections`. Planifica la migración antes de subir la versión, no después.
**¿Puedo usar Server Islands en Vercel o Netlify?**
Sí, con el adapter correspondiente instalado. La isla es una serverless function que devuelve HTML, así que necesitas un host que ejecute functions. Nada de eso cambió en v6.
## ¿Sigues en Astro 4? La historia de v4 a v5
Todo lo de arriba asume que ya diste el salto de v4 a v5. Si no, esta es la parte que todavía importa, porque el Content Layer nació aquí.
En Astro 4, definías las collections con un string mágico:
```typescript
// Astro 4, la forma antigua
import { defineCollection, z } from 'astro:content';
const blog = defineCollection({
type: 'content', // "busca ficheros, no sé cómo"
schema: z.object({ /* ... */ }),
});
```
Astro 5 dejó de creer en la magia y pidió loaders explícitos:
```typescript
// Astro 5+, la nueva forma
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';
const blog = defineCollection({
loader: glob({ pattern: '**/*.md', base: './src/content/blog' }),
schema: z.object({
title: z.string(),
pubDate: z.date(),
}),
});
```
Dos trampas más de la era v4 que v6 da por hecho que ya has arreglado:
El modo `output: 'hybrid'` desaparece. Astro es ahora estático por defecto con SSR opt-in, o server por defecto con estático opt-in. Borra `hybrid` de tu config.
Y `post.render()` ya no existe. Las content entries son objetos planos, así que importas el render:
```typescript
import { render } from 'astro:content';
const { Content } = await render(post);
```
Haz ese trabajo, consigue un build verde en v5, y el paso a v6 del principio de este post se convierte en una tarde tranquila en vez de un infierno.
**Lectura relacionada:** la trampa más rastrera de toda esta saga se ganó su propio post. [Cómo un `content.config.ts` mal colocado se comió mis campos de schema en silencio](/blog/astro-ubicacion-content-config/), y el arreglo de cinco minutos. Si vas a hacer este refactor multi-archivo a cuatro manos con un asistente de IA, mi [reseña de Google Antigravity](/blog/resena-google-antigravity/) cuenta cómo se portan los IDEs agénticos que probé durante esta actualización.
## Fuentes
- [Docs de Astro: Upgrade to v6](https://docs.astro.build/en/guides/upgrade-to/v6/)
- [Docs de Astro: Content Collections](https://docs.astro.build/en/guides/content-collections/)
---
**P.D.** ¿Ya diste el paso a v6? ¿El cambio de `slug` a `id` te rompió el corazón dos veces, una en v5 y otra en v6? Cuéntamelo en [Twitter/X](https://x.com/garbarok).
---
# Gemini 3: The Developer's Guide to the New AI Era
URL: https://www.oscargallegoruiz.com/en/blog/gemini-3-developer-guide/
Lang: en
> A week with Gemini 3 Pro: Deep Think on a real migration, a bug diagnosed from a 2-minute video, and the agentic stuff that still needs a babysitter. →
I've been testing Gemini 3 Pro for the past week, and honestly? I'm annoyed it's this good.
Not because it's bad. The opposite. I'd finally gotten comfortable with my Claude/GPT-4 workflow, and now Google drops this on November 18th and throws everything into chaos again. Classic.
But here's the thing: after forcing myself to rebuild a feature I'd already finished (yeah, I rewrote working code just to test this), I get the hype. This isn't your typical "10% better at benchmarks" release. Deep Think and actual multimodality (not the fake kind) change how you can work.
Let me show you what I mean.
## What's actually different this time
### 1. Deep Think, or why it actually pauses now
You know how previous models would just... start vomiting tokens? Mid-thought, zero planning, just word prediction on steroids?
Gemini 3 actually stops. It thinks. You'll see "[Thinking...]" in the API response, and at first I thought my connection dropped. Nope. It's genuinely spending compute time planning its answer before committing.
**Where I've actually used this:**
Last Thursday, I asked it to plan our migration from a monolithic Angular app to micro-frontends. Instead of immediately dumping code, it:
- Asked about our deployment pipeline (I didn't even prompt for this)
- Identified 3 legacy dependencies that would break
- Suggested a phased rollout plan that actually made sense
Could Claude do this? Maybe. But Gemini 3 did it without me babysitting the prompts.
**The catch:** It's slower. If you're used to instant responses, the 3-5 second thinking pause feels eternal. But for architecture decisions? I'll take accuracy over speed.
### 2. Multimodality without the duct tape
Every model claims "multimodality" now. Usually, it means they duct-taped three different models together and hoped for the best.
Gemini 3 is different: one model handles everything. Text, code, video, audio, images. Same weights, same architecture.
**Real test I did:**
I recorded a 2-minute Loom video of a UI bug (button wouldn't disable after clicking). No transcript, no code snippets. Just me clicking around and complaining in Spanish.
Uploaded it. Asked: "What's broken?"
It responded:
- Identified the event handler wasn't preventing double-clicks
- Pointed to the React component by name (HOW?!)
- Suggested adding a `isLoading` state with `disabled={isLoading}`
I checked. It was right. The component name was correct. From a VIDEO.
**The weird part:** It occasionally hallucinates component names if your video is too long (over 5 minutes). But for quick bug hunts, nothing else I've used comes close.
### 3. Agentic Capabilities (With a Giant Asterisk)
Google's numbers look great on paper: SWE-bench Verified jumped from 59.6% to 76.2% (Gemini 2.5 Pro to Gemini 3 Pro). In practice? It's... complicated.
**What works:**
- Running terminal commands (I let it debug a Docker networking issue, and it actually used `docker inspect` correctly)
- Editing files (made a 12-file refactor across my codebase without breaking tests)
- Running tests and interpreting failures
**What doesn't:**
- It still sometimes tries to run commands that don't exist (`git commit -fix` is not a thing, Gemini)
- Gets confused if your project structure is unconventional
- Will confidently suggest deleting files that are actually critical (caught this twice; always review)
Trust, but verify. Always.
## Where it slots into a real workflow
### 1. Stop Writing Boilerplate (Seriously, Just Stop)
Forget "vibe coding". Let's talk about the stuff you actually hate doing.
**My new workflow:**
Instead of scaffolding another CRUD API by hand, I now do this:
> "I need a FastAPI endpoint for user authentication. JWT tokens, refresh logic, PostgreSQL with SQLAlchemy. Follow our existing pattern from the `/products` endpoints."
Then I upload our products module as context. Gemini 3 generates 90% correct code. The other 10%? Usually just import paths or environment variables.
**Time saved:** What used to take 2 hours now takes 20 minutes.
**The catch:** You need a consistent codebase pattern. If your project is chaos, Gemini 3 will reflect that chaos.
### 2. Code Reviews (But Not How You Think)
I don't trust AI for full code reviews yet. But I do use Gemini 3 as a "first pass filter."
**My setup:**
1. Developer opens PR
2. GitHub Action sends diff to Gemini 3
3. It flags **obvious** stuff: hardcoded credentials, missing error handling, SQL injection risks
4. Posts these as automated comments
5. I (human) do the real review for logic and architecture
This catches the boring stuff so I can focus on whether the code actually solves the problem.
**Warning:** It will sometimes flag false positives. Last week it complained about a `.env` file that was actually a `.env.example`. Don't blindly merge based on AI feedback.
### 3. Legacy Code (Where It Actually Shines)
Remember that 6-year-old jQuery spaghetti nobody wants to touch? Gemini 3's 1M token context is perfect for this.
**What I did last month:**
Uploaded our entire legacy admin panel (22 files of vanilla JS horror). Asked it to:
- Identify which files are actually used
- Create a dependency graph
- Rewrite the user management module in React
It worked. Not perfectly (I had to fix event handling bugs), but it did 70% of the grunt work.
**Pro tip:** Do this incrementally. Don't ask it to rewrite your entire app. Start with one isolated module, verify it works, then move to the next.
## So... Should You Care?
Look, I'm not switching from Claude entirely. For brainstorming and writing, Claude still feels more "human." But for code? Gemini 3 is winning me over.
The Deep Think feature alone saves me from second-guessing architecture decisions. The multimodality is genuinely useful (not gimmicky). And the context window means I can actually load real projects, not toy examples.
**My advice:**
- **Try it** if you're doing refactoring or working with legacy code
- **Stick with Claude/GPT-4** if you need creative writing or nuanced explanations
- **Don't trust it blindly:** I've caught it suggesting bad practices when it's outside its knowledge cutoff
The future of development is probably agentic. But we're not there yet. Gemini 3 is a big step, though.
Now excuse me while I go rewrite my CI/CD pipeline for the third time this year.
**Related reading:** more on letting AI take the first review pass: [I tried using AI for code review on my side projects](/en/blog/gemini-flash-code-review-automation/).
---
**P.S.** If you've tried Gemini 3, I'd love to hear what you think. Did it hallucinate component names for you too, or is that just me? Hit me up on [Twitter/X](https://x.com/garbarok).
---
# Google Antigravity Review: Worth the Hype in 2026?
URL: https://www.oscargallegoruiz.com/en/blog/google-antigravity-review/
Lang: en
> Google Antigravity vs Cursor: honest verdict after a week with the agent-first IDE. Parallel agents, memory leaks, and which VS Code extensions survive. →
> **Update (April 2026).** Five months on, the take shifted a bit. The day-one crashes are mostly gone, parallel agents earn their keep on boilerplate-heavy work, but the RAM creep on long sessions is still real. Verdict moved from _"give it a shot on side projects"_ to _"keep it on a second machine for the kind of work that benefits from agents working in parallel"._ Added a comparison table against Cursor / Windsurf / Copilot and an FAQ at the bottom for the questions people kept emailing me.
## Why I Even Tried This (Because Twitter Made Me Do It)
Look, I wasn't planning to switch IDEs. I'm comfortable with VS Code. My setup works. My extensions work. Life is good.
But then Twitter happened. Some guy posting screenshots every 3 hours. "Antigravity is insane." "This kills Cursor." "Agent-first is the future."
Classic hype cycle. But I had a free Saturday and a side project I didn't care about breaking, so... fuck it, let's see what the fuss is about.
Downloaded the preview. Opened it.
First thought: _This isn't an IDE. This is a spaceship cockpit._
No friendly chat sidebar like Cursor. Instead you get this "Agent Manager" panel with permissions, toggles, warnings, and policies everywhere.
Either this is genius, or it's going to be a beautiful disaster.
## Day 1: Installation Was Fine, But Then...
Installation on macOS was actually smooth. Download, drag to Applications, done.
But here's the first WTF moment: it looks like VS Code because it is a VS Code fork (Google shipped it on November 18, 2025, the same day as Gemini 3). Then you realize how heavily they reworked it. People online keep insisting it actually reuses Windsurf internals (there are Cascade references floating around, and Google did hire the Windsurf team), but Google has not confirmed that, so treat the Windsurf angle as a rumor, not a fact.
Which means: **not all your VS Code extensions work.**
I spent 20 minutes trying to figure out why my favorite theme wasn't loading. Turns out, it's just not compatible. Most popular extensions are there (Prettier, ESLint, GitLens), but if you have niche ones... tough luck.
Minor annoyance, but annoying nonetheless.
Then comes the setup wizard:
- Choose your model (Claude? GPT? Gemini?)
- Configure agent permissions (can they run commands automatically or ask first?)
- Set execution policies
I'm setting up an IDE, not deploying to production. Felt heavy.
I just clicked "recommended defaults" and hoped I wasn't about to nuke my project.
## Day 2: When Agents Do Things Without Asking
Simple test: "Create an auth endpoint with JWT and refresh tokens."
Hit enter. Went to make coffee.
Came back.
The endpoint code was there. Great.
But there's another agent running. I look. It's writing unit tests.
_I didn't ask for unit tests._
At first I thought: "Did I mistype? Did I accidentally trigger something?"
Nope. The agents just... act. Independently. In parallel.
One agent writes the endpoint. Another agent sees the new code and thinks "hey, this needs tests" and starts writing them. Without asking.
Is this cool? Yeah, kinda.
Is this unsettling? Also yeah.
Because now you're sitting there thinking: _What else are they doing when I'm not looking?_
(Honest question: does anyone else get this weird feeling like someone's watching over your shoulder while these agents work? Like a tech lead breathing down your neck but in software form. Uncomfortable but useful.)
## Artifacts: Good Idea, Execution Needs Work
Antigravity has this "Artifacts" feature where each agent leaves behind a record of what it did:
- Code diffs
- Screenshots
- Browser session recordings
- Reasoning logs
Sounds great on paper.
In reality? When you have 3-4 agents running at once, the Artifacts panel becomes a clusterfuck. Overlapping logs, diffs everywhere, screenshots from different tasks piling up.
I ended up just checking the final code and hoping nothing broke silently in the background.
The "audit trail" quickly becomes "audit noise."
## When the Browser Opened Itself (And Then Exploded)
This was the moment I went: _okay, this IS next-level._
I asked an agent to fix a UI bug.
What happened next:
1. Agent edited the component
2. Restarted the dev server
3. Opened a headless browser
4. Clicked through the UI
5. Verified the bug was gone
6. Committed the fix
I did nothing. Just watched.
_Cursor would never do this._
But then: memory leak. The browser process hung. IDE froze. RAM spiked to 6GB. Had to force-quit.
Happened **twice** in one week.
So yeah, autonomous agents are cool until they eat all your RAM and crash your machine.
## The "Am I Being Paranoid?" Moment
There's something inherently weird about handing control to agents.
You're working on one part of the codebase. Meanwhile, agents are refactoring another file, writing tests for a third, and opening browsers to validate a fourth.
All. At. The. Same. Time.
For small, experimental projects? Maybe fine.
For production code or anything with sensitive data? I'm not comfortable yet.
I keep thinking: _What if one of these agents decides to refactor my entire API layer at 3am?_
(Probably won't happen. But the anxiety is real.)
## Cursor vs Antigravity vs Windsurf vs Copilot (The Honest Take)
Cursor feels like pair programming with someone senior. They suggest, you decide, nothing happens unless you say so.
Antigravity is more like hiring that one intern who ships twice as fast as everyone else but also refactors your entire folder structure at 2am because "it made more sense this way." You love the output. You hate the surprises.
Here's how the four AI-IDEs I actually use stack up after extended trials:
| | **Antigravity** | **Cursor** | **Windsurf** | **GitHub Copilot** |
|---|---|---|---|---|
| **Agent style** | Multiple, autonomous, parallel | Single, supervised, you-confirm-each-step | Cascade flow with manual checkpoints | Inline suggestions + chat |
| **Best for** | Boilerplate, scaffolding, side projects | Production code, careful refactors | Mid-size features with explicit phases | Day-to-day completions in any editor |
| **Models** | Gemini 3 Pro/Flash, Claude Sonnet 4.6 & Opus 4.6 (bring your own Anthropic key in preview), GPT-OSS-120B | Claude, GPT, Gemini | Claude, GPT, Gemini | OpenAI / GPT family |
| **Browser automation** | Yes (built-in headless verify) | No | Limited | No |
| **Editor base** | VS Code fork (Windsurf reuse is an unconfirmed community theory) | VS Code fork | Custom (Codeium) | Plugin (any editor) |
| **Extension compat** | Partial (most VS Code OK, themes flaky) | Full VS Code | Custom marketplace | N/A (host editor's own) |
| **RAM at idle** | ~1.2 GB | ~700 MB | ~600 MB | ~150 MB |
| **RAM under load** | Spikes hard, occasional 6 GB+ leak | Stable | Stable | Negligible |
| **Pricing** | Free preview (rate-limited) | $20 / mo Pro | $20 / mo Pro (raised from $15 in March 2026) | $10 / mo Pro, $19 / mo Business |
| **Friction to commit** | Almost zero (agent will do it) | Medium (explicit accept) | Medium (phase reviews) | High (you do it) |
| **Best mental model** | "Hire an intern" | "Pair with a senior" | "Run a checklist" | "Spell-check, but for code" |
The short version: **pick by how much autonomy you can stomach**. Antigravity gives the most, Copilot the least, Cursor and Windsurf land in between with different defaults.
## Do I Recommend It? Honestly, I Don't Know Yet
Ask me again in a month.
Right now I'm 60% impressed (the parallel agents thing IS cool), 30% frustrated (missing extensions, memory leaks, too much noise), and 10% paranoid (what are these agents doing when I'm not watching?).
If you're writing a lot of CRUD endpoints, forms, and boilerplate APIs, and you have a side project you genuinely don't care about breaking, yeah, give it a shot. You'll probably have fun.
If you're working on anything production-critical, or you're the kind of person who gets anxious when tools do things without asking, stay away for now. Seriously. This thing will stress you out.
I'm keeping it installed. On a separate machine. Just in case.
That probably tells you everything you need to know.
## Who Should Actually Use This?
After five months of on-and-off use, here is the honest split:
**Try Antigravity if you:**
- Spin up a lot of CRUD APIs, internal tools, prototypes, or boilerplate-heavy features.
- Have a side project where _shipped_ matters more than _supervised_.
- Want to see what a multi-agent IDE feels like before the rest of the industry catches up.
- Already keep your work machine and your experiments machine separate.
**Skip it (for now) if you:**
- Work in regulated codebases or anything with sensitive data: the autonomy is real and the audit trail is still messy.
- Rely on a deep VS Code extension setup that includes anything niche.
- Are easily stressed by tools doing things without asking. This thing _will_ stress you out.
- Run a low-RAM laptop. The leaks I hit aren't theoretical.
**Worth checking back in 6 months if you:**
- Liked the idea but waited for stability.
- Use Cursor today and want a clean side-by-side once Antigravity exits preview.
## FAQ
### Is Google Antigravity free?
It is currently a free preview with rate limits. Google has hinted at a paid tier once it leaves preview but has not published pricing yet. Expect something competitive with Cursor's $20 / month range.
### Does Antigravity replace VS Code?
Not really. It is a VS Code fork, so it looks like VS Code and most popular extensions (Prettier, ESLint, GitLens) work, but theme and niche extensions often do not. (Some people online claim it also reuses Windsurf internals; Google has not confirmed that.) If your VS Code setup is heavily customised, treat Antigravity as a separate tool, not a drop-in replacement.
### Does GitLens (and my other VS Code extensions) work in Antigravity?
Most of the popular ones do. In my setup Prettier, ESLint, and GitLens all loaded and worked normally. Because Antigravity is a VS Code fork rather than stock VS Code, the gaps show up in themes and niche extensions rather than the everyday staples. So GitLens-style Git tooling is safe, but budget a few minutes to re-find a couple of obscure ones.
### What models does Antigravity support?
At launch the roster is Gemini 3 Pro and Gemini 3 Flash, Anthropic's Claude Sonnet 4.6 and Opus 4.6, and OpenAI's open-weights GPT-OSS-120B (not GPT-4 or GPT-5). In the free preview the Claude models need your own Anthropic API key. You pick one in the setup wizard and switch per-agent later, so different agents in the same session can run on different models: handy for putting the cheap-fast model on test-writing and the heavyweight one on architecture.
### Is Antigravity safe to use on a real project?
For experimental and side projects, yes. For anything production-critical or compliance-sensitive, not yet: the agents act independently in parallel, the artifacts panel gets noisy fast, and the memory issues still bite on long sessions. If you do use it on real work, scope agent permissions tightly in the setup wizard and keep version control aggressive.
### Antigravity vs Cursor: which one should I pick in 2026?
Cursor if you want supervised pair-programming with explicit accept-each-suggestion flow. Antigravity if you want multiple agents working in parallel and you can stomach the loss of fine-grained control. They optimise for different anxieties: Cursor for "I want to keep control", Antigravity for "I want to ship faster".
### Has the memory-leak problem been fixed?
It is significantly better than at launch but not gone. Long sessions (4+ hours, multiple agents, browser automation) still occasionally spike RAM into the 5 to 6 GB range. Quitting and reopening clears it. Treat sustained sessions the way you treat a leaky Chrome window.
### Can Antigravity actually run a browser by itself?
Yes: the agent can open a headless browser, click through the UI, verify a fix, and commit. This was the most "futuristic" moment in my whole trial and the headline reason to even try it. It is also the most resource-intensive feature, which is why long sessions tend to leak memory.
## Sources
For the claims I couldn't verify first-hand (the VS Code fork, the model roster, the pricing), here is what I leaned on:
- [Build with Google Antigravity, our new agentic development platform](https://developers.googleblog.com/build-with-google-antigravity-our-new-agentic-development-platform/) (Google Developers Blog) for the November 18, 2025 launch, the agent-first design, and model optionality across Gemini 3 Pro, Claude, and OpenAI's GPT-OSS.
- [Google Antigravity](https://en.wikipedia.org/wiki/Google_Antigravity) (Wikipedia) for the "fork of VS Code" framing and the note that Google has not publicly confirmed the exact technical relationship.
- [Google Antigravity models](https://antigravity.google/docs/models) (official docs) for the current model list: Gemini 3 Pro/Flash, Claude Sonnet 4.6 and Opus 4.6, GPT-OSS-120B.
- [Windsurf Pricing in 2026](https://www.cloudzero.com/blog/windsurf-pricing/) (CloudZero) for the Windsurf Pro move from $15 to $20/month in March 2026.
**Related reading:** agents that act on their own is exactly where the whole field is heading. The bigger picture is in [Stop Prompting Your Agent. Start Writing Loops.](/en/blog/stop-prompting-write-loops/)
---
**P.S.** If you've tried Antigravity, let me know: Did you hit the same memory issues? Did agents refactor stuff without asking? Am I being paranoid or is this actually a thing? Hit me up on [Twitter/X](https://x.com/garbarok).
---
# Gemini 3: La Guía del Desarrollador para la Nueva Era de la IA
URL: https://www.oscargallegoruiz.com/blog/gemini-3-guia-desarrollador/
Lang: es
> Una semana con Gemini 3 Pro: Deep Think en una migración real, un bug diagnosticado desde un vídeo de 2 minutos, y el lado agéntico que aún hay que vigilar. →
Llevo una semana probando Gemini 3 Pro, y ¿sabes qué? Me molesta que sea tan bueno.
No porque esté mal. Todo lo contrario. Justo cuando me había acostumbrado a mi workflow con Claude/GPT-4, Google suelta esto el 18 de noviembre y me lo tira todo por la ventana otra vez. Típico.
Pero la cosa es así: después de obligarme a reconstruir una feature que ya tenía funcionando (sí, reescribí código que funcionaba solo para probar esto), entiendo el hype. No es el típico release de "10% mejor en benchmarks". Deep Think y multimodalidad real (no la fake de siempre) cambian cómo puedes trabajar.
Deja que te enseñe a qué me refiero.
## Lo que de verdad ha cambiado esta vez
### 1. Deep Think, o por qué ahora se para a pensar
¿Sabes cómo los modelos anteriores simplemente empezaban a vomitar tokens? En medio del pensamiento, cero planificación, solo predicción de palabras a lo bestia.
Gemini 3 realmente se para. Piensa. Verás "[Thinking...]" en la respuesta de la API, y al principio pensé que se me había caído la conexión. Pues no. Realmente está gastando tiempo de cómputo planificando la respuesta antes de soltarla.
**Donde lo he usado de verdad:**
El jueves pasado, le pedí que planificara nuestra migración de una app Angular monolítica a micro-frontends. En lugar de soltar código inmediatamente:
- Preguntó sobre nuestro pipeline de deploy (ni siquiera le di contexto de esto)
- Identificó 3 dependencias legacy que se romperían
- Sugirió un plan de rollout por fases que realmente tenía sentido
¿Podría Claude hacer esto? Quizás. Pero Gemini 3 lo hizo sin que tuviera que estar tuneando prompts constantemente.
**El pero:** Es más lento. Si estás acostumbrado a respuestas instantáneas, esa pausa de 3-5 segundos pensando se hace eterna. Pero para decisiones de arquitectura, prefiero precisión antes que velocidad.
### 2. Multimodalidad sin cinta aislante
Todos los modelos ahora dicen tener "multimodalidad". Normalmente significa que pegaron tres modelos diferentes con cinta aislante y cruzaron los dedos.
Gemini 3 es diferente: un solo modelo lo maneja todo. Texto, código, vídeo, audio, imágenes. Mismos pesos, misma arquitectura.
**Test real que hice:**
Grabé un vídeo de 2 minutos en Loom de un bug en la UI (un botón que no se deshabilitaba al hacer clic). Sin transcripción, sin snippets de código. Solo yo haciendo clic por ahí y quejándome en español.
Lo subí. Pregunté: "¿Qué está roto?"
Respondió:
- Identificó que el event handler no estaba previniendo doble-click
- Señaló el componente React por nombre (¿¿CÓMO??)
- Sugirió añadir un estado `isLoading` con `disabled={isLoading}`
Lo comprobé. Tenía razón. El nombre del componente era correcto. De un VÍDEO.
**La parte rara:** A veces alucina nombres de componentes si tu vídeo es muy largo (más de 5 minutos). Pero para cazar bugs rápido, nada de lo que he usado se le acerca.
### 3. Capacidades de Agente (Con un Asterisco Gigante)
Los números de Google pintan muy bien sobre el papel: SWE-bench Verified pasó del 59,6% al 76,2% (de Gemini 2.5 Pro a Gemini 3 Pro). En la práctica... es complicado.
**Lo que funciona:**
- Ejecutar comandos de terminal (le dejé debuggear un problema de networking en Docker y usó `docker inspect` correctamente)
- Editar archivos (hizo un refactor de 12 archivos en mi codebase sin romper tests)
- Ejecutar tests e interpretar fallos
**Lo que no:**
- Todavía intenta ejecutar comandos que no existen (`git commit -fix` no es real, Gemini)
- Se lía si la estructura de tu proyecto es poco convencional
- Sugiere con confianza borrar archivos que en realidad son críticos (lo pillé dos veces; revisa siempre)
Confía, pero verifica. Siempre.
## Dónde encaja en un workflow real
### 1. Deja de Escribir Boilerplate (En Serio, Para Ya)
Olvídate del "vibe coding". Hablemos de la mierda que realmente odias hacer.
**Mi nuevo workflow:**
En lugar de hacer scaffolding de otra API CRUD a mano, ahora hago esto:
> "Necesito un endpoint de FastAPI para autenticación de usuarios. Tokens JWT, lógica de refresh, PostgreSQL con SQLAlchemy. Sigue nuestro patrón existente de los endpoints de `/products`."
Luego subo nuestro módulo de products como contexto. Gemini 3 genera código correcto al 90%. ¿El otro 10%? Normalmente solo rutas de imports o variables de entorno.
**Tiempo ahorrado:** Lo que antes me llevaba 2 horas ahora son 20 minutos.
**El truco:** Necesitas un patrón de codebase consistente. Si tu proyecto es un caos, Gemini 3 va a reflejar ese caos.
### 2. Code Reviews (Pero No Como Piensas)
Aún no confío en la IA para code reviews completos. Pero sí uso Gemini 3 como "filtro de primera pasada".
**Mi setup:**
1. El dev abre un PR
2. GitHub Action manda el diff a Gemini 3
3. Marca lo **obvio**: credenciales hardcodeadas, falta de error handling, riesgos de SQL injection
4. Postea estos como comentarios automáticos
5. Yo (humano) hago la review real de lógica y arquitectura
Esto pilla lo aburrido para que yo pueda enfocarme en si el código realmente resuelve el problema.
**Aviso:** A veces marca falsos positivos. La semana pasada se quejó de un archivo `.env` que en realidad era `.env.example`. No hagas merge ciegamente basándote en feedback de IA.
### 3. Legacy Code (Donde Realmente Brilla)
¿Recuerdas ese espagueti de jQuery de hace 6 años que nadie quiere tocar? El context window de 1M de tokens de Gemini 3 es perfecto para esto.
**Lo que hice el mes pasado:**
Subí todo nuestro panel de admin legacy (22 archivos de horror en vanilla JS). Le pedí que:
- Identificara qué archivos se usan realmente
- Creara un grafo de dependencias
- Reescribiera el módulo de gestión de usuarios en React
Funcionó. No perfectamente (tuve que arreglar bugs de event handling), pero hizo el 70% del trabajo sucio.
**Pro tip:** Haz esto incrementalmente. No le pidas que reescriba toda tu app. Empieza con un módulo aislado, verifica que funciona, y luego sigue con el siguiente.
## Entonces... ¿te debería importar?
Mira, no voy a dejar Claude del todo. Para brainstorming y escribir, Claude sigue sintiéndose más "humano". Pero ¿para código? Gemini 3 me está ganando.
Solo la feature de Deep Think me ahorra estar dudando de decisiones de arquitectura. La multimodalidad es genuinamente útil (no un gimmick). Y el context window significa que puedo cargar proyectos reales, no ejemplos de juguete.
**Mi consejo:**
- **Pruébalo** si estás haciendo refactoring o trabajando con legacy code
- **Quédate con Claude/GPT-4** si necesitas escritura creativa o explicaciones matizadas
- **No confíes ciegamente:** le he pillado sugiriendo malas prácticas cuando está fuera de su knowledge cutoff
El futuro del desarrollo probablemente es agéntico. Pero aún no estamos ahí. Gemini 3 es un paso grande, eso sí.
Ahora discúlpame mientras voy a reescribir mi pipeline de CI/CD por tercera vez este año.
**Lectura relacionada:** más sobre dejar que la IA haga la primera pasada de review: [probé usar IA para revisión de código en mis proyectos](/blog/gemini-flash-code-review-automatizado/).
---
**P.D.** Si has probado Gemini 3, me encantaría saber qué piensas. ¿También te alucinó nombres de componentes, o soy solo yo? Escríbeme en [Twitter/X](https://x.com/garbarok).
---
# Google Antigravity Review: ¿Vale la Pena el Hype en 2026?
URL: https://www.oscargallegoruiz.com/blog/resena-google-antigravity/
Lang: es
> Google Antigravity frente a Cursor: veredicto sin filtros tras una semana con el IDE agent-first. Agentes en paralelo, memory leaks y qué extensiones aguantan. →
> **Actualización (Abril 2026).** Cinco meses después, mi opinión ha cambiado un poco. Los crashes del primer día prácticamente han desaparecido, los agentes en paralelo se ganan el sueldo cuando hay mucho boilerplate, pero el RAM creep en sesiones largas sigue siendo real. El veredicto pasó de _"pruébalo en side projects"_ a _"tenlo en una segunda máquina para el tipo de trabajo que se beneficia de agentes corriendo en paralelo"._ He añadido una tabla comparativa con Cursor / Windsurf / Copilot y una FAQ al final con las preguntas que más me llegan por email.
## Por Qué Probé Esto (Porque Twitter Me Obligó)
Mira, no tenía pensado cambiar de IDE. Estoy cómodo con VS Code. Mi setup funciona. Mis extensiones funcionan. Todo bien.
Pero luego llegó Twitter. Un tío posteando screenshots cada 3 horas. "Antigravity es una locura." "Esto mata a Cursor." "El futuro es agent-first."
El típico hype. Pero tenía un sábado libre y un side project que me daba igual romper, así que... qué coño, vamos a ver de qué va esto.
Descargué el preview. Lo abrí.
Primera impresión: _Esto no es un IDE. Esto es la cabina de una nave espacial._
Nada de chat amigable como Cursor. En su lugar tienes este panel de "Agent Manager" con permisos, toggles, warnings y policies por todas partes.
O esto es genial, o va a ser un desastre precioso.
## Día 1: La Instalación Bien, Pero Luego...
La instalación en macOS fue fluida. Descargar, arrastrar a Aplicaciones, listo.
Pero aquí viene el primer momento WTF: parece VS Code porque es un fork de VS Code (Google lo lanzó el 18 de noviembre de 2025, el mismo día que Gemini 3). Luego te das cuenta de lo mucho que lo han reescrito. Por internet hay gente que insiste en que en realidad reutiliza tripas de Windsurf (se ven referencias a Cascade por ahí, y Google fichó al equipo de Windsurf), pero Google no lo ha confirmado, así que toma lo de Windsurf como rumor, no como dato.
Lo que significa: **no todas tus extensiones de VS Code funcionan.**
Me tiré 20 minutos intentando entender por qué mi theme favorito no cargaba. Resulta que simplemente no es compatible. La mayoría de extensiones populares están (Prettier, ESLint, GitLens), pero si tienes alguna de nicho... mala suerte.
Molesto, pero bueno.
Luego viene el wizard de setup:
- Elige tu modelo (¿Claude? ¿GPT? ¿Gemini?)
- Configura permisos de agentes (¿pueden ejecutar comandos automáticamente o preguntan primero?)
- Define políticas de ejecución
Tío, estoy configurando un IDE, no haciendo un deploy a producción. Se sentía pesado.
Hice clic en "defaults recomendados" y crucé los dedos para no cepillarme el proyecto.
## Día 2: Cuando los Agentes Hacen Cosas Sin Preguntar
Test simple: "Crea un endpoint de auth con JWT y refresh tokens."
Enter. Fui a por café.
Volví.
El código del endpoint estaba ahí. Genial.
Pero hay otro agente corriendo. Miro. Está escribiendo tests unitarios.
_Yo no pedí tests unitarios._
Al principio pensé: "¿Me habré equivocado al escribir? ¿Habré triggereado algo sin querer?"
Nada. Los agentes simplemente... actúan. Independientemente. En paralelo.
Un agente escribe el endpoint. Otro agente ve el código nuevo y piensa "eh, esto necesita tests" y se pone a escribirlos. Sin preguntar.
¿Mola? Sí, un poco.
¿Inquieta? También.
Porque ahora estás ahí sentado pensando: _¿Qué más están haciendo cuando no miro?_
(Pregunta honesta: ¿alguien más tiene esta sensación rara de que alguien te está mirando por encima del hombro mientras estos agentes trabajan? Como un tech lead respirándote en el cuello pero en versión software. Incómodo pero útil.)
## Artifacts: Buena Idea, Ejecución Mejorable
Antigravity tiene esta feature de "Artifacts" donde cada agente te deja un registro de lo que hizo:
- Diffs de código
- Screenshots
- Grabaciones de sesiones del browser
- Logs de razonamiento
Suena bien sobre el papel.
¿En realidad? Cuando tienes 3-4 agentes corriendo a la vez, el panel de Artifacts se convierte en un caos. Logs solapados, diffs por todas partes, screenshots de diferentes tareas apilándose.
Acabé simplemente revisando el código final y cruzando los dedos para que nada se hubiera roto en silencio.
El "audit trail" se convierte rápidamente en "ruido de auditoría".
## Cuando el Browser Se Abrió Solo (Y Luego Explotó)
Este fue el momento en el que pensé: _vale, esto SÍ es next-level._
Le pedí a un agente que arreglara un bug en la UI.
Lo que pasó después:
1. El agente editó el componente
2. Reinició el dev server
3. Abrió un headless browser
4. Hizo clic por la UI
5. Verificó que el bug había desaparecido
6. Hizo commit del fix
Yo no hice nada. Solo mirar.
_Cursor nunca haría esto._
Pero luego: memory leak. El proceso del browser se colgó. El IDE se congeló. La RAM se fue a 6GB. Tuve que hacer force-quit.
Pasó **dos veces** en una semana.
Así que sí, los agentes autónomos molan hasta que se comen toda tu RAM y te crashean la máquina.
## El Momento "¿Estoy Siendo Paranoico?"
Hay algo inherentemente raro en ceder el control a los agentes.
Estás trabajando en una parte del codebase. Mientras tanto, los agentes están refactorizando otro archivo, escribiendo tests para un tercero, y abriendo browsers para validar un cuarto.
Todo. Al. Mismo. Tiempo.
¿Para proyectos pequeños y experimentales? Quizás vale.
¿Para código de producción o cualquier cosa con datos sensibles? Aún no me fío.
Sigo pensando: _¿Y si uno de estos agentes decide refactorizar toda mi capa de API a las 3 de la mañana?_
(Probablemente no pase. Pero la ansiedad es real.)
## Cursor vs Antigravity vs Windsurf vs Copilot (La Versión Honesta)
Cursor se siente como hacer pair programming con alguien senior. Sugiere, tú decides, no pasa nada hasta que tú dices.
Antigravity es más como contratar a ese intern que shippea el doble de rápido que los demás pero también reorganiza toda tu estructura de carpetas a las 2 de la mañana porque "tenía más sentido así". Te encanta el resultado. Odias las sorpresas.
Así quedan los cuatro AI-IDEs que uso de verdad después de pruebas largas:
| | **Antigravity** | **Cursor** | **Windsurf** | **GitHub Copilot** |
|---|---|---|---|---|
| **Estilo de agente** | Múltiples, autónomos, en paralelo | Único, supervisado, confirmas cada paso | Cascade con checkpoints manuales | Sugerencias inline + chat |
| **Mejor para** | Boilerplate, scaffolding, side projects | Código de producción, refactors cuidadosos | Features medianas con fases explícitas | Completados día a día en cualquier editor |
| **Modelos** | Gemini 3 Pro/Flash, Claude Sonnet 4.6 y Opus 4.6 (con tu propia API key de Anthropic en el preview), GPT-OSS-120B | Claude, GPT, Gemini | Claude, GPT, Gemini | Familia OpenAI / GPT |
| **Automatización del browser** | Sí (verifica con headless integrado) | No | Limitada | No |
| **Editor base** | Fork de VS Code (lo de reutilizar Windsurf es una teoría de la comunidad sin confirmar) | Fork de VS Code | Custom (Codeium) | Plugin (cualquier editor) |
| **Compatibilidad de extensiones** | Parcial (la mayoría VS Code OK, themes flojos) | VS Code completo | Marketplace propio | N/A (el del editor host) |
| **RAM en idle** | ~1,2 GB | ~700 MB | ~600 MB | ~150 MB |
| **RAM bajo carga** | Picos fuertes, leaks ocasionales de 6 GB+ | Estable | Estable | Despreciable |
| **Precio** | Preview gratis (con rate limit) | 20 $/mes Pro | 20 $/mes Pro (subió desde 15 $ en marzo de 2026) | 10 $/mes Pro, 19 $/mes Business |
| **Fricción para commitear** | Casi cero (el agente lo hace) | Media (aceptas explícitamente) | Media (revisión por fases) | Alta (lo haces tú) |
| **Modelo mental** | "Contratas a un intern" | "Pair con un senior" | "Sigues una checklist" | "Spell-check, pero para código" |
Resumen rápido: **elige según cuánta autonomía aguantas**. Antigravity te da la máxima, Copilot la mínima, Cursor y Windsurf van por el medio con defaults distintos.
## ¿Lo Recomiendo? Honestamente, Aún No Lo Sé
Pregúntame otra vez en un mes.
Ahora mismo estoy 60% impresionado (lo de los agentes en paralelo SÍ mola), 30% frustrado (extensiones que faltan, memory leaks, demasiado ruido) y 10% paranoico (¿qué están haciendo estos agentes cuando no miro?).
Si picas muchos endpoints CRUD, formularios y APIs con boilerplate, y tienes un side project que de verdad te da igual romper, sí, dale una oportunidad. Probablemente te lo pases bien.
Si trabajas en algo crítico de producción, o eres de los que se ponen ansiosos cuando las herramientas hacen cosas sin preguntar, mantente lejos de momento. En serio. Esto va a estresarte.
Lo tengo instalado. En una máquina separada. Por si acaso.
Eso probablemente te dice todo lo que necesitas saber.
## ¿Para Quién Es Esto Realmente?
Tras cinco meses usándolo a ratos, este es el reparto honesto:
**Pruébalo si:**
- Picas mucha CRUD API, herramientas internas, prototipos o features con mucho boilerplate.
- Tienes un side project donde _shipped_ pesa más que _supervisado_.
- Te apetece ver cómo se siente un IDE multi-agente antes de que lo haga el resto del sector.
- Ya tienes separadas la máquina de trabajo y la de experimentos.
**Pásalo (de momento) si:**
- Trabajas en código regulado o cualquier cosa con datos sensibles: la autonomía es real y el audit trail aún es un desastre.
- Dependes de un setup denso de extensiones de VS Code, especialmente las de nicho.
- Te pone ansioso que las herramientas hagan cosas sin preguntar. Esto _va_ a estresarte.
- Tienes un portátil con poca RAM. Los leaks no son teóricos.
**Vuélvelo a mirar dentro de 6 meses si:**
- Te interesa la idea pero esperas a que estabilice.
- Hoy usas Cursor y quieres una comparativa side-by-side cuando Antigravity salga del preview.
## FAQ
### ¿Google Antigravity es gratis?
Ahora mismo es un preview gratuito con rate limits. Google ha dejado caer que habrá tier de pago cuando salga del preview, pero todavía no hay precios públicos. Espera algo competitivo con los 20 $/mes de Cursor.
### ¿Antigravity reemplaza a VS Code?
No del todo. Es un fork de VS Code, así que parece VS Code y la mayoría de extensiones populares (Prettier, ESLint, GitLens) funcionan, pero los themes y muchas extensiones de nicho no. (Hay quien afirma por internet que además reutiliza tripas de Windsurf; Google no lo ha confirmado.) Si tu setup de VS Code está muy customizado, trátalo como una herramienta aparte, no como un drop-in replacement.
### ¿Funciona GitLens (y mis otras extensiones de VS Code) en Antigravity?
La mayoría de las populares sí. En mi setup Prettier, ESLint y GitLens cargaron y funcionaron con normalidad. Como Antigravity es un fork de VS Code y no el VS Code original, los huecos aparecen en themes y extensiones de nicho, no en las del día a día. Así que el tooling de Git tipo GitLens va seguro, pero cuenta con perder un par de minutos re-buscando alguna de las más raras.
### ¿Qué modelos soporta Antigravity?
De salida el catálogo es Gemini 3 Pro y Gemini 3 Flash, Claude Sonnet 4.6 y Opus 4.6 de Anthropic, y GPT-OSS-120B, el modelo open-weights de OpenAI (no GPT-4 ni GPT-5). En el preview gratuito los modelos de Claude piden tu propia API key de Anthropic. Eliges uno en el wizard de setup y luego cambias por agente, así que distintos agentes de la misma sesión pueden usar modelos distintos: útil para mandar al modelo barato y rápido a escribir tests y al pesado a las decisiones de arquitectura.
### ¿Es seguro usar Antigravity en un proyecto real?
Para experimentos y side projects, sí. Para producción crítica o código sujeto a compliance, todavía no: los agentes actúan en paralelo, el panel de Artifacts se ensucia rápido y los problemas de memoria siguen apareciendo en sesiones largas. Si lo usas en trabajo real, restringe los permisos de los agentes en el wizard y mantén el control de versiones agresivo.
### Antigravity vs Cursor: ¿cuál elijo en 2026?
Cursor si quieres pair programming supervisado con flujo de aceptar-cada-sugerencia. Antigravity si quieres varios agentes trabajando en paralelo y aguantas perder control fino. Optimizan para ansiedades distintas: Cursor para "quiero mantener el control", Antigravity para "quiero shippear más rápido".
### ¿Han arreglado el memory leak?
Está bastante mejor que en el lanzamiento, pero no del todo. Sesiones largas (4+ horas, varios agentes, automatización del browser) todavía hacen picos de RAM en el rango de 5 a 6 GB. Cerrar y reabrir lo limpia. Trátalo como tratas a una pestaña de Chrome con fuga.
### ¿De verdad Antigravity puede ejecutar un browser por sí solo?
Sí: el agente abre un browser headless, clickea por la UI, verifica que el fix funciona y hace commit. Fue el momento más "futurista" de toda la prueba y la razón principal para siquiera probarlo. También es la feature más cara en recursos, y por eso las sesiones largas tienden a tener leaks.
## Fuentes
Para lo que no pude verificar de primera mano (que es un fork de VS Code, el catálogo de modelos, los precios), esto es en lo que me apoyé:
- [Build with Google Antigravity, our new agentic development platform](https://developers.googleblog.com/build-with-google-antigravity-our-new-agentic-development-platform/) (Google Developers Blog) para el lanzamiento del 18 de noviembre de 2025, el diseño agent-first y la opción de modelos entre Gemini 3 Pro, Claude y el GPT-OSS de OpenAI.
- [Google Antigravity](https://en.wikipedia.org/wiki/Google_Antigravity) (Wikipedia) para lo del "fork de VS Code" y la nota de que Google no ha confirmado públicamente la relación técnica exacta.
- [Google Antigravity models](https://antigravity.google/docs/models) (documentación oficial) para la lista actual de modelos: Gemini 3 Pro/Flash, Claude Sonnet 4.6 y Opus 4.6, GPT-OSS-120B.
- [Windsurf Pricing in 2026](https://www.cloudzero.com/blog/windsurf-pricing/) (CloudZero) para el salto de Windsurf Pro de 15 $ a 20 $/mes en marzo de 2026.
**Lectura relacionada:** agentes que actúan por su cuenta es exactamente hacia donde va todo el sector. La foto grande está en [Deja de Promptear a tu Agente. Escribe Loops.](/blog/deja-de-promptear-escribe-loops/)
---
**P.D.** Si has probado Antigravity, cuéntame: ¿Te has encontrado los mismos problemas de memoria? ¿Los agentes te han refactorizado cosas sin preguntar? ¿Soy paranoico o esto es real? Escríbeme en [Twitter/X](https://x.com/garbarok).
---
# How to Improve AI Answers with One-Shot Prompting and Context Placement?
URL: https://www.oscargallegoruiz.com/en/blog/ai-prompt-engineering-tips/
Lang: en
> One good example beats a paragraph of instructions: how one-shot prompting and context placement (start or end, never the middle) fix vague AI answers. →
Most vague AI answers are not a model problem. They're an input problem.
Two techniques fix a surprising share of them: **one-shot prompting** (give the model a single good example) and **context placement** (put the critical information where the model actually looks). No framework, no fine-tuning. They work on any LLM, today.
## One good example beats a paragraph of instructions
One-shot prompting means exactly what it sounds like: you include one high-quality example in your prompt and let the model generalize from it.
Think of pair programming with a coworker. You don't hand them a spec on "how we format things here". You say: look at how we did this last time, now build the new one the same way.
It's efficient because you skip enumerating edge cases. It's more reliable than zero-shot (no example) because the model gets a concrete pattern to copy instead of a description to interpret. Instructions tell the model what you want; an example *shows* it. For anything that hinges on format, tone, or a specific transformation, that input-output pair is the anchor that keeps the model from improvising.
### Sentiment analysis: show the format once
Say you want customer reviews classified as positive, negative, or neutral. One example teaches the whole task.
**Prompt:**
> You are a sentiment analysis expert. Classify the following customer review into one of three categories: "Positive", "Negative", or "Neutral".
>
> **Example:**
> **Review:** "The product arrived quickly, but the packaging was damaged. The item itself works perfectly."
> **Sentiment:** "Neutral"
>
> Now, classify the sentiment of this review:
>
> **Review to Classify:** "This software update is terrible! It broke half my features and is incredibly slow now."
### The example does the heavy lifting, so pick it well
- Choose it carefully: it sets the pattern for everything that follows.
- Make it representative. An edge case as your only example teaches the model the edge case.
- Include every element you want in the output.
- Add explicit instructions where the example alone is ambiguous.
- Don't overcomplicate it. The model generalizes the pattern.
### Code refactoring: the pattern is the prompt
Here's a one-shot prompt that refactors JavaScript from promise chains to async/await.
**Prompt:**
> You are an expert JavaScript developer. Refactor the following function to use `async/await` syntax while keeping the logic identical.
>
> **Example:**
> **Original Code:**
>
> ```javascript
> function fetchData(url) {
> return fetch(url)
> .then((response) => {
> if (!response.ok) {
> throw new Error("Network response was not ok");
> }
> return response.json();
> })
> .then((data) => {
> console.log("Data received:", data);
> return data;
> })
> .catch((error) => {
> console.error("Fetch error:", error);
> throw error;
> });
> }
> ```
>
> **Refactored Code:**
>
> ```javascript
> async function fetchData(url) {
> try {
> const response = await fetch(url);
> if (!response.ok) {
> throw new Error("Network response was not ok");
> }
> const data = await response.json();
> console.log("Data received:", data);
> return data;
> } catch (error) {
> console.error("Fetch error:", error);
> throw error;
> }
> }
> ```
>
> Now, refactor this function:
>
> **Function to Refactor:**
>
> ```javascript
> function getUser(id) {
> return database.findUser(id).then((user) => {
> return getPermissions(user.role).then((permissions) => {
> user.permissions = permissions;
> return user;
> });
> });
> }
> ```
## Data extraction: one example, parseable output every time
This is where one-shot earns its keep. Show the model the input text and the exact JSON you want back, and you turn unstructured text into something your code can parse without ceremony.
Consistency is the whole prize. When the output always has the same shape, it plugs straight into databases, analytics tools, or whatever pipeline you've got, with no regex graveyard between the model and your code.
**Prompt:**
> You are a data extraction specialist. Your task is to extract specific information from a user's message and format it as a JSON object.
>
> **EXAMPLE:**
> **Text:** "Hi, I'd like to book a flight for two adults from New York (JFK) to Los Angeles (LAX) on December 25th, 2025. I'd prefer a morning flight on Delta."
>
> **JSON Output:**
>
> ```json
> {
> "intent": "book_flight",
> "passengers": {
> "adults": 2,
> "children": 0
> },
> "origin": {
> "city": "New York",
> "airport_code": "JFK"
> },
> "destination": {
> "city": "Los Angeles",
> "airport_code": "LAX"
> },
> "date": "2025-12-25",
> "preferences": {
> "time_of_day": "morning",
> "airline": "Delta"
> }
> }
> ```
>
> ---
>
> **YOUR TASK:** Extract the relevant information from the following text and format it as a JSON object, following the example's structure.
>
> **Text to Process:** "Hey, can you find me a hotel in downtown Austin for 3 nights, checking in on March 10th, 2026? I need a room with a king-size bed and free Wi-Fi."
## Your model ignores the middle of your prompt
Context windows keep growing, and the marketing implies you can throw anything at them and the model will sort it out. The research says otherwise. ["Lost in the Middle: How Language Models Use Long Contexts"](https://arxiv.org/abs/2307.03172) found that models perform best when the critical information sits at the **beginning** or **end** of the context window.
The uncomfortable part of the study: when the important information was buried in the middle of a long context, performance didn't just dip. In some cases the model did worse than with no context at all. More context, worse answer.
Sit with that before celebrating the next million-token announcement. A bigger window makes it easier to drown the one instruction that matters in pages of filler. If you build on top of LLMs, especially RAG pipelines that inject retrieved documents straight into the prompt, this is the failure mode to design against, because the model will happily act on everything except the detail you cared about.
### A constraint buried mid-document gets silently dropped
Picture a task where you summarize a long document under one specific constraint: the summary must include a particular piece of information (a product code, a key date, someone's name) that might appear exactly once, in the middle of the text.
Put the constraint ("Include product code XYZ123 in the summary") in the middle of a long document and the model may skate right past it, handing you a summary that misses the one detail you needed.
To make it stick, place it at the beginning or end of your prompt, clearly separated from the document itself.
**Prompt:**
> **IMPORTANT CONSTRAINT:** Your summary MUST include the product code "PROD-789".
>
> Summarize the following document in 3-4 sentences, focusing on the key features and benefits.
>
> [Long Document Content Here, where "PROD-789" might be mentioned once in the middle]
>
> Alternatively, you could place the constraint at the very end:
>
> Summarize the following document in 3-4 sentences, focusing on the key features and benefits.
>
> [Long Document Content Here]
>
> **IMPORTANT CONSTRAINT:** Ensure the summary mentions product code "PROD-789".
### Where to put what
- Start fresh when you can: a new chat is a focused context.
- Front-load the critical instructions, data, or questions.
- New important information? Append it to the end. Don't splice it into the middle.
- The middle is for the supplementary stuff the model can afford to skim.
Next time an answer comes back vague, don't reach for a bigger model. Audit the prompt first: is there an example in it, and is the critical instruction at an edge or drowning in the middle? Those two checks fix most of the answers you were about to complain about.
**Related reading:** once your prompts behave, the next rung is not writing them at all: [stop prompting your agent, start writing loops](/en/blog/stop-prompting-write-loops/).
---
**P.S.** Got a prompt that refuses to behave no matter where you put the context? Show me on [Twitter/X](https://x.com/garbarok).
---
# ¿Cómo Mejorar las Respuestas de IA con Prompts de Ejemplo Único y Colocación de Contexto?
URL: https://www.oscargallegoruiz.com/blog/consejos-ingenieria-prompts-ai/
Lang: es
> Un buen ejemplo vale más que un párrafo de instrucciones: cómo el one-shot prompting y la colocación del contexto arreglan las respuestas vagas de la IA. →
La mayoría de las respuestas vagas de la IA no son un problema del modelo. Son un problema de la entrada.
Dos técnicas arreglan una parte sorprendente de ellas: el **one-shot prompting** (darle al modelo un único buen ejemplo) y la **colocación del contexto** (poner la información crítica donde el modelo de verdad mira). Sin frameworks, sin fine-tuning. Funcionan con cualquier LLM, hoy.
## Un buen ejemplo vale más que un párrafo de instrucciones
One-shot prompting significa exactamente lo que parece: incluyes un solo ejemplo de calidad en el prompt y dejas que el modelo generalice a partir de él.
Piensa en pair programming con un compañero. No le pasas una especificación de "cómo formateamos aquí". Le dices: mira cómo hicimos esto la última vez, ahora haz lo nuevo igual.
Es eficiente porque te ahorras enumerar casos extremos. Y es más fiable que un prompt zero-shot (sin ejemplo) porque el modelo recibe un patrón concreto que copiar en vez de una descripción que interpretar. Las instrucciones le dicen al modelo qué quieres; un ejemplo se lo *enseña*. Para cualquier cosa que dependa de formato, tono o una transformación concreta, ese par entrada-salida es el ancla que evita que el modelo improvise.
### Análisis de sentimiento: enseña el formato una vez
Supón que quieres clasificar reseñas de clientes como positivas, negativas o neutras. Un solo ejemplo enseña la tarea entera.
**Prompt:**
> Eres un experto en análisis de sentimiento. Clasifica la siguiente reseña de cliente en una de tres categorías: "Positiva", "Negativa" o "Neutra".
>
> **Ejemplo:**
> **Reseña:** "El producto llegó rápidamente, pero el embalaje estaba dañado. El artículo en sí funciona perfectamente."
> **Sentimiento:** "Neutra"
>
> Ahora, clasifica el sentimiento de esta reseña:
>
> **Reseña a Clasificar:** "¡Esta actualización de software es terrible! Rompió la mitad de mis funciones y ahora es increíblemente lenta."
### El ejemplo hace el trabajo pesado, así que elígelo bien
- Elígelo con cuidado: marca el patrón de todo lo que viene después.
- Que sea representativo. Un caso extremo como único ejemplo le enseña al modelo el caso extremo.
- Incluye todos los elementos que quieres en la salida.
- Añade instrucciones explícitas donde el ejemplo solo se quede ambiguo.
- No lo compliques. El modelo generaliza el patrón.
### Refactorización de código: el patrón es el prompt
Aquí tienes un prompt one-shot que refactoriza JavaScript de cadenas de promesas a async/await.
**Prompt:**
> Eres un desarrollador experto en JavaScript. Refactoriza la siguiente función para usar la sintaxis `async/await` manteniendo la lógica idéntica.
>
> **Ejemplo:**
> **Código Original:**
>
> ```javascript
> function fetchData(url) {
> return fetch(url)
> .then((response) => {
> if (!response.ok) {
> throw new Error("La respuesta de la red no fue correcta");
> }
> return response.json();
> })
> .then((data) => {
> console.log("Datos recibidos:", data);
> return data;
> })
> .catch((error) => {
> console.error("Error en fetch:", error);
> throw error;
> });
> }
> ```
>
> **Código Refactorizado:**
>
> ```javascript
> async function fetchData(url) {
> try {
> const response = await fetch(url);
> if (!response.ok) {
> throw new Error("La respuesta de la red no fue correcta");
> }
> const data = await response.json();
> console.log("Datos recibidos:", data);
> return data;
> } catch (error) {
> console.error("Error en fetch:", error);
> throw error;
> }
> }
> ```
>
> Ahora, refactoriza esta función:
>
> **Función a Refactorizar:**
>
> ```javascript
> function getUser(id) {
> return database.findUser(id).then((user) => {
> return getPermissions(user.role).then((permissions) => {
> user.permissions = permissions;
> return user;
> });
> });
> }
> ```
## Extracción de datos: un ejemplo, salida parseable siempre
Aquí es donde el one-shot se gana el sueldo. Enséñale al modelo el texto de entrada y el JSON exacto que quieres de vuelta, y conviertes texto sin estructura en algo que tu código puede parsear sin ceremonia.
La consistencia es el premio entero. Cuando la salida siempre tiene la misma forma, encaja directa en bases de datos, herramientas de análisis o el pipeline que tengas montado, sin un cementerio de regex entre el modelo y tu código.
**Prompt:**
> Eres un especialista en extracción de datos. Tu tarea es extraer información específica del mensaje de un usuario y formatearla como un objeto JSON.
>
> **EJEMPLO:**
> **Texto:** "Hola, me gustaría reservar un vuelo para dos adultos desde Nueva York (JFK) a Los Ángeles (LAX) el 25 de diciembre de 2025. Preferiría un vuelo por la mañana con Delta."
>
> **Salida JSON:**
>
> ```json
> {
> "intent": "reservar_vuelo",
> "pasajeros": {
> "adultos": 2,
> "niños": 0
> },
> "origen": {
> "ciudad": "Nueva York",
> "codigo_aeropuerto": "JFK"
> },
> "destino": {
> "ciudad": "Los Ángeles",
> "codigo_aeropuerto": "LAX"
> },
> "fecha": "2025-12-25",
> "preferencias": {
> "hora_del_dia": "mañana",
> "aerolinea": "Delta"
> }
> }
> ```
>
> ---
>
> **TU TAREA:** Extrae la información relevante del siguiente texto y formatéala como un objeto JSON, siguiendo la estructura del ejemplo.
>
> **Texto a Procesar:** "Hola, ¿puedes encontrarme un hotel en el centro de Austin para 3 noches, con check-in el 10 de marzo de 2026? Necesito una habitación con una cama king-size y Wi-Fi gratis."
## Tu modelo ignora el medio de tu prompt
Las ventanas de contexto no paran de crecer, y el marketing sugiere que puedes tirarles cualquier cosa y el modelo se aclarará. La investigación dice otra cosa. ["Lost in the Middle: How Language Models Use Long Contexts"](https://arxiv.org/abs/2307.03172) encontró que los modelos rinden mejor cuando la información crítica está al **principio** o al **final** de la ventana de contexto.
La parte incómoda del estudio: cuando la información importante estaba enterrada en medio de un contexto largo, el rendimiento no solo bajaba. En algunos casos el modelo rendía peor que sin ningún contexto. Más contexto, peor respuesta.
Piensa en eso antes de celebrar el próximo anuncio del millón de tokens. Una ventana más grande hace más fácil ahogar la única instrucción que importa entre páginas de relleno. Si construyes sobre LLMs, sobre todo pipelines RAG que inyectan documentos recuperados directamente en el prompt, este es el modo de fallo contra el que diseñar, porque el modelo actuará encantado sobre todo menos sobre el detalle que te importaba.
### Una restricción enterrada a mitad de documento se pierde en silencio
Imagina que tienes que resumir un documento largo con una restricción muy concreta: el resumen debe incluir un dato específico (un código de producto, una fecha clave, el nombre de alguien) que quizá aparece exactamente una vez, en mitad del texto.
Pon la restricción ("Incluir el código de producto XYZ123 en el resumen") en medio de un documento muy largo y el modelo puede pasarla de largo, entregándote un resumen sin el único detalle que necesitabas.
Para que la respete, colócala al principio o al final del prompt, claramente separada del documento.
**Prompt:**
> **RESTRICCIÓN IMPORTANTE:** Tu resumen DEBE incluir el código de producto "PROD-789".
>
> Resume el siguiente documento en 3-4 oraciones, centrándote en las características y beneficios clave.
>
> [Contenido del Documento Largo Aquí, donde "PROD-789" podría mencionarse una vez en el medio]
>
> Alternativamente, podrías colocar la restricción al final:
>
> Resume el siguiente documento en 3-4 oraciones, centrándote en las características y beneficios clave.
>
> [Contenido del Documento Largo Aquí]
>
> **RESTRICCIÓN IMPORTANTE:** Asegúrate de que el resumen mencione el código de producto "PROD-789".
### Dónde va cada cosa
- Empieza de cero cuando puedas: un chat nuevo es un contexto enfocado.
- Pon al principio las instrucciones, datos o preguntas críticas.
- ¿Llega información nueva e importante? Añádela al final. No la insertes en el medio.
- El medio es para lo suplementario, lo que el modelo puede permitirse hojear.
La próxima vez que una respuesta vuelva vaga, no busques un modelo más grande. Audita el prompt primero: ¿lleva un ejemplo, y la instrucción crítica está en un borde o ahogándose en el medio? Esas dos comprobaciones arreglan la mayoría de las respuestas de las que ibas a quejarte.
**Lectura relacionada:** cuando tus prompts se porten bien, el siguiente escalón es no escribirlos: [deja de promptear a tu agente, escribe loops](/blog/deja-de-promptear-escribe-loops/).
---
**P.D.** ¿Tienes un prompt que no obedece lo pongas donde lo pongas? Enséñamelo en [Twitter/X](https://x.com/garbarok).
---
# Astro Debugging: Fixed "Missing Schema Fields" in 5 Min
URL: https://www.oscargallegoruiz.com/en/blog/astro-content-config-location/
Lang: en
> Astro schema fields missing at runtime? You're probably editing src/content/config.ts instead of src/content.config.ts. Symptoms, cause, 4-step fix. →
## Why aren't my Astro schema fields updating?
If you've added fields to your Astro Content Collections schema and they aren't appearing, the most common cause is the configuration file's location or name. As of Astro 6, the legacy `src/content/config.ts` path is gone; Astro reads only `src/content.config.ts`. (In Astro 5 the old path still worked, which is why this trap bites people mid-migration.)
Before you burn an afternoon on it (I did), run this checklist:
1. **Location.** The config file lives at the root of `src/`, not inside `src/content/`. Correct: `src/content.config.ts`. Wrong: `src/content/config.ts`.
2. **Name.** It must be called `content.config.ts`, exactly. Any other variation gets ignored.
3. **No duplicates.** Search your project for a second configuration file Astro might be reading instead.
4. **Cache.** Delete the `.astro` directory and restart the dev server to force Astro to regenerate types from the correct file.
Have you ever defined a field in your content collection schema, only for it to vanish at runtime? You're not alone. I recently spent hours debugging schema fields that were inexplicably missing, despite being correctly defined.
> **TL;DR.** My new schema fields were missing because I was editing `src/content/config.ts`. Astro only recognizes `src/content.config.ts`. I moved my changes to the correctly named and located file and deleted the duplicate.
What follows is the full debugging trail: the symptoms, the dead ends, and the fix.
## The mystery of the disappearing schema fields
While adding a `relatedSlug` field to my blog's schema for multilingual support, I hit a wall. The field was defined in the schema and present in the Markdown frontmatter, but completely absent from the `post.data` object.
### The symptoms
My setup looked correct. The `relatedSlug` field was nowhere: not in the TypeScript types, not at runtime.
```typescript
// src/content/config.ts
import { z, defineCollection } from "astro:content";
const blogCollection = defineCollection({
schema: z.object({
title: z.string(),
// ... other fields
relatedSlug: z.string().optional(), // WRONG: this field was missing!
}),
});
export const collections = { blog: blogCollection };
```
- Defined in the schema: `relatedSlug` was clearly part of the Zod object.
- Present in the frontmatter: my `.md` files included `relatedSlug: "some-slug"`.
- Missing at runtime: `'relatedSlug' in post.data` returned `false`.
Two out of three. The wrong two.
### What didn't work (everything I tried first)
I suspected a bug in Astro or Zod, so I threw workarounds at it. None of them moved the needle:
1. **Swapping `.optional()` for `.default("")`**, hoping to force the field into existence. Still missing.
2. **Making it required.** Astro should have thrown an error for the missing field. It didn't. The field stayed absent.
3. **Renaming it.** `relatedSlug` became `translation` to rule out a naming conflict. The new field vanished too.
That third result was the real clue. **When even required fields are silently ignored, Astro isn't reading your config at all.**
## The root cause: I was editing the wrong file
After hours of debugging, the answer was embarrassingly simple.
The Astro documentation gives the content collections config strict naming and location requirements.
- Correct file: `src/content.config.ts`
- My file: `src/content/config.ts`
I had accidentally created a configuration file inside the `content` directory. As of Astro 6, that legacy `src/content/config.ts` path is gone, so Astro ignored it completely and kept reading an older version of `content.config.ts` sitting at the `src` root.
One slash. Hours of my life.
## The fix, in four steps
Once the root cause was identified, the fix was mechanical.
### Step 1: confirm which file Astro is actually using
The generated types in `.astro/` give you the answer.
```typescript
// .astro/content.d.ts
// This line reveals the source of truth:
export type ContentConfig = typeof import("../src/content.config.js");
```
### Step 2: consolidate and delete
I copied my latest schema definitions from the incorrect file (`src/content/config.ts`) into the correct one (`src/content.config.ts`), then deleted the duplicate.
```bash
# Delete the incorrect configuration file
rm src/content/config.ts
```
### Step 3: make the correct file the only truth
With the duplicate gone, I made sure `src/content.config.ts` had the final schema.
```typescript
// src/content.config.ts CORRECT
import { z, defineCollection } from "astro:content";
const blogCollection = defineCollection({
schema: z.object({
// ... all my fields
relatedSlug: z.string(), // CORRECT: now it works!
}),
});
export const collections = { blog: blogCollection };
```
### Step 4: clear the cache
To make sure Astro picked up the changes, clear the cache and restart the dev server.
```bash
# Clear the .astro cache directory
rm -rf .astro
# Restart the development server
npm run dev
```
After these steps, `relatedSlug` appeared in my types and at runtime. Like it had been there all along. Because it had.
## The checklist to run before you blame the framework
Next time fields go missing, check these before anything clever:
- Is your config file at `src/content.config.ts`?
- Is it named `content.config.ts` exactly?
- Is there only one `content.config.ts` in the whole project?
- Have you tried deleting the `.astro` directory?
- Does the file actually `export const collections`?
## Master the conventions before you suspect the tool
Here's the uncomfortable part. I spent those hours assuming the bug was in Astro or Zod, because blaming the tool feels better than checking a file path. The tool was fine. My directory tree wasn't.
What felt like a deep framework bug was a misconfiguration with a five-minute fix. When a framework silently ignores you, the silence usually means it never heard you in the first place. Check its conventions before you open an issue.
**Related reading:** this exact rename, `src/content/config.ts` to `src/content.config.ts`, is one of the breaking changes covered in [my Astro 5 to 6 migration guide](/en/blog/astro-6-migration-guide/), along with the rest of the traps that shipped with it.
---
**P.S.** What's the dumbest file-location bug that ever ate your afternoon? Misery loves company. Tell me on [Twitter/X](https://x.com/garbarok).
---
# Debug Astro: Arregla "Campos de Schema Ocultos" en 5 Min
URL: https://www.oscargallegoruiz.com/blog/astro-ubicacion-content-config/
Lang: es
> ¿Tus campos de schema en Astro no aparecen? Seguramente editas src/content/config.ts en vez de src/content.config.ts. Síntomas, causa y arreglo en 4 pasos. →
## ¿Por qué no se actualizan los campos de mi schema en Astro?
Si has añadido campos a tu schema de Astro Content Collections y no aparecen, la causa más común es la ubicación o el nombre del archivo de configuración. A partir de Astro 6, la ruta antigua `src/content/config.ts` desaparece; Astro lee solo `src/content.config.ts`. (En Astro 5 la ruta antigua todavía funcionaba, por eso esta trampa pilla a la gente a mitad de la migración.)
Antes de quemarte una tarde con esto (yo lo hice), repasa esta checklist:
1. **Ubicación.** El archivo de configuración vive en la raíz de `src/`, no dentro de `src/content/`. Correcto: `src/content.config.ts`. Incorrecto: `src/content/config.ts`.
2. **Nombre.** Debe llamarse `content.config.ts`, exactamente. Cualquier otra variación será ignorada.
3. **Sin duplicados.** Busca en tu proyecto otro archivo de configuración que Astro pueda estar leyendo en su lugar.
4. **Caché.** Elimina el directorio `.astro` y reinicia el servidor de desarrollo para forzar a Astro a regenerar los tipos desde el archivo correcto.
¿Alguna vez has definido un campo en tu schema solo para verlo desvanecerse en tiempo de ejecución? No estás solo. Hace poco pasé horas depurando campos de schema que desaparecían inexplicablemente, a pesar de estar definidos correctamente.
> **TL;DR.** Mis nuevos campos de schema desaparecían porque estaba editando `src/content/config.ts`. Astro solo reconoce `src/content.config.ts`. Moví mis cambios al archivo con el nombre y la ubicación correctos y eliminé el duplicado.
Lo que sigue es el rastro completo de la depuración: los síntomas, los callejones sin salida y el arreglo.
## El misterio de los campos del schema que desaparecen
Mientras añadía un campo `relatedSlug` al schema de mi blog para soporte multiidioma, me topé con un muro. El campo estaba definido en el schema y presente en el frontmatter del Markdown, pero completamente ausente en el objeto `post.data`.
### Los síntomas
Mi configuración parecía correcta. El campo `relatedSlug` no estaba en ningún lado: ni en los tipos de TypeScript ni en tiempo de ejecución.
```typescript
// src/content/config.ts
import { z, defineCollection } from "astro:content";
const blogCollection = defineCollection({
schema: z.object({
title: z.string(),
// ... otros campos
relatedSlug: z.string().optional(), // MAL: ¡este campo desaparecía!
}),
});
export const collections = { blog: blogCollection };
```
- Definido en el schema: `relatedSlug` era claramente parte del objeto de Zod.
- Presente en el frontmatter: mis archivos `.md` incluían `relatedSlug: "un-slug-cualquiera"`.
- Ausente en runtime: `'relatedSlug' in post.data` devolvía `false`.
Dos de tres. Justo los dos que no servían.
### Qué no funcionó (todo lo que probé antes)
Sospeché de un bug en Astro o Zod, así que empecé a tirar workarounds. Ninguno movió la aguja:
1. **Cambiar `.optional()` por `.default("")`**, esperando forzar la existencia del campo. Seguía ausente.
2. **Hacerlo requerido.** Astro debería haber lanzado un error por el campo faltante. No lo hizo. El campo seguía sin aparecer.
3. **Renombrarlo.** `relatedSlug` pasó a ser `translation` para descartar un conflicto de nombres. El campo nuevo también desapareció.
Ese tercer resultado era la pista de verdad. **Cuando hasta los campos requeridos se ignoran en silencio, Astro no está leyendo tu configuración en absoluto.**
## La causa raíz: estaba editando el archivo equivocado
Después de horas de depuración, la respuesta fue vergonzosamente simple.
La documentación de Astro impone requisitos estrictos de nombre y ubicación al archivo de configuración de las colecciones de contenido.
- Archivo correcto: `src/content.config.ts`
- Mi archivo: `src/content/config.ts`
Había creado accidentalmente un archivo de configuración dentro del directorio `content`. A partir de Astro 6, esa ruta antigua `src/content/config.ts` desaparece, así que Astro lo ignoraba por completo y seguía leyendo una versión más antigua de `content.config.ts` ubicada en la raíz de `src`.
Una barra. Horas de mi vida.
## El arreglo, en cuatro pasos
Una vez identificada la causa raíz, el arreglo fue mecánico.
### Paso 1: confirma qué archivo está usando Astro de verdad
Los tipos generados en `.astro/` te dan la respuesta.
```typescript
// .astro/content.d.ts
// Esta línea revela la fuente de la verdad:
export type ContentConfig = typeof import("../src/content.config.js");
```
### Paso 2: consolida y elimina
Copié mis últimas definiciones de schema del archivo incorrecto (`src/content/config.ts`) al correcto (`src/content.config.ts`) y luego eliminé el duplicado.
```bash
# Elimina el archivo de configuración incorrecto
rm src/content/config.ts
```
### Paso 3: haz del archivo correcto la única verdad
Con el duplicado eliminado, me aseguré de que `src/content.config.ts` tuviera el schema final.
```typescript
// src/content.config.ts BIEN
import { z, defineCollection } from "astro:content";
const blogCollection = defineCollection({
schema: z.object({
// ... todos mis campos
relatedSlug: z.string(), // BIEN: ¡ahora funciona!
}),
});
export const collections = { blog: blogCollection };
```
### Paso 4: limpia la caché
Para asegurarte de que Astro recoge los cambios, limpia la caché y reinicia el servidor de desarrollo.
```bash
# Limpia el directorio de caché .astro
rm -rf .astro
# Reinicia el servidor de desarrollo
npm run dev
```
Después de estos pasos, `relatedSlug` apareció en mis tipos y en tiempo de ejecución. Como si hubiera estado ahí todo el tiempo. Porque lo había estado.
## La checklist que repasar antes de culpar al framework
La próxima vez que se te pierdan campos, comprueba esto antes de intentar nada ingenioso:
- ¿Está tu archivo de configuración en `src/content.config.ts`?
- ¿Se llama `content.config.ts` exactamente?
- ¿Hay solo un `content.config.ts` en todo el proyecto?
- ¿Has probado a eliminar el directorio `.astro`?
- ¿El archivo realmente hace `export const collections`?
## Domina las convenciones antes de sospechar de la herramienta
Aquí va la parte incómoda. Pasé esas horas asumiendo que el bug estaba en Astro o en Zod, porque culpar a la herramienta sienta mejor que comprobar una ruta de archivo. La herramienta estaba bien. Mi árbol de directorios no.
Lo que parecía un bug profundo del framework era una configuración errónea con arreglo de cinco minutos. Cuando un framework te ignora en silencio, ese silencio suele significar que nunca te oyó. Revisa sus convenciones antes de abrir un issue.
**Lectura relacionada:** este renombrado exacto, `src/content/config.ts` a `src/content.config.ts`, es uno de los breaking changes de [mi guía de migración de Astro 5 a 6](/blog/astro-6-guia-migracion/), junto con el resto de trampas que vinieron con él.
---
**P.D.** ¿Cuál es el bug de ubicación de archivo más tonto que te ha comido una tarde? Las penas compartidas duelen menos. Cuéntamelo en [Twitter/X](https://x.com/garbarok).
---
# Astro 6 in 2026: 100 Core Web Vitals, 90% Less JS
URL: https://www.oscargallegoruiz.com/en/blog/introduction-astro-5/
Lang: en
> Astro 6 is here. Hands-on with Islands and the Content Layer API, plus the real Next.js to Astro migration that pulled most of the JS off my portfolio. →
> **Updated May 2026: now covers Astro 6.** I originally wrote this for Astro 5 in late 2025. I've since upgraded this site to **Astro 6** (stable since March 2026), and the headline pitch is unchanged: zero JS by default, Islands, and Core Web Vitals you can actually pass. The Content Layer API and `client:*` hydration directives below are exactly the same in v6. The visible deltas are mostly under the hood: Node `^22.12.0 || ^24.0.0` minimum, Zod v4, and the v5 legacy grace periods are over. If you want the upgrade-from-Astro-5 angle instead of an intro, see my [Astro 6 migration guide](/en/blog/astro-6-migration-guide/).
My portfolio used to ship a heavy JavaScript bundle to render what is mostly text. On Astro it ships a fraction of that, and on this site I now hit roughly 100 on Lighthouse.
Same content. Same design. This post is the why and the how.
## What Astro is, and why version 6 matters
Astro is a modern web framework designed for building fast, content-focused websites: blogs, portfolios, marketing sites. Its key feature is the "zero JavaScript by default" architecture, which ships only HTML and CSS to the browser and loads JavaScript only for the interactive components that need it.
The main new features in Astro 5 (all carried into 6) focus on performance and flexibility:
- **Content Layer API:** unifies content loading from multiple sources (local files, headless CMS) with build-time data validation and type-safety through its new *loader* system.
- **Improved Islands Architecture:** allows for more granular component hydration with directives like `client:visible`, drastically reducing the amount of JavaScript shipped to the client.
- **Faster builds:** a new caching system and parallel processing cut build times, noticeably so on incremental rebuilds.
- **Integrated asset optimization:** the `