El desarrollador que escribe "add user authentication" en Claude Code obtiene un resultado diferente cada vez. Tal vez JWT. Tal vez cookies de sesion. Tal vez un flujo OAuth2 completo con refresh tokens y PKCE. El agente no sabe lo que quieres porque no se lo has dicho. Le diste una direccion, no un destino.
Los desarrolladores que veo obteniendo resultados consistentes y entregables de Claude Code comparten un habito: escriben una especificacion antes de entregar trabajo al agente. No una novela. No un ticket de Jira con tres oraciones de contexto. Un documento concreto que define como se ve "terminado" antes de que alguien escriba una linea de codigo.
Esto no es sabiduria nueva. El desarrollo spec-first precede a la IA por decadas. Pero con agentes, el costo de saltarse la spec es mayor y el beneficio de escribir una es mas grande. Un desarrollador humano puede detenerse a mitad de la implementacion y preguntar "espera, te referias a autenticacion por contrasena o SSO?" Un agente elegira uno en silencio y seguira adelante. Para cuando te des cuenta, construyo lo incorrecto, y perdiste 20 minutos revisando codigo que necesita ser descartado.
Este articulo recorre el ciclo de vida guiado por specs que uso con Claude Code todos los dias: como escribir especificaciones contra las que los agentes pueden ejecutar, el checkpoint de plan-antes-del-codigo que atrapa malentendidos temprano, y un protocolo de verificacion mas riguroso que "compila."
Por que "solo construyelo" falla con agentes
Seamos especificos sobre el modo de fallo. Cuando le das a Claude Code una instruccion vaga, tres cosas salen mal:
Suposiciones silenciosas. El agente llena cada hueco en tu spec con sus propias suposiciones. A veces son razonables. A veces no. No sabras en que categoria estas hasta que leas el output. Con instrucciones vagas, terminas leyendo el output con mas cuidado del que te hubiera costado escribir una spec.
Resultados no reproducibles. Ejecuta el mismo prompt vago dos veces y obtendras dos implementaciones diferentes. No solo nombres de variables o formato diferentes. Decisiones arquitectonicas diferentes. Bibliotecas diferentes. Estrategias de manejo de errores diferentes. Si no puedes reproducir el output, no puedes construir un proceso confiable alrededor de el.
La revision se convierte en el cuello de botella. Cuando el agente toma todas las decisiones, tu tienes que verificar todas las decisiones. Un diff de 400 lineas donde entiendes cada eleccion toma 5 minutos de revision. Un diff de 400 lineas donde el agente eligio el esquema de base de datos, la forma de la API, los codigos de error y la logica de validacion toma 30 minutos porque estas reconstruyendo la spec a partir de la implementacion.
La solucion no son mejores prompts. Es adelantar las decisiones que importan a un documento contra el que el agente puede ejecutar.
El ciclo de vida guiado por especificaciones
El flujo de trabajo tiene cinco fases. Cada una tiene una condicion de entrada clara y una condicion de salida clara.
Fase 1: Lluvia de ideas. Exploras el espacio del problema. Cuales son las restricciones? Que enfoques existen? Que has intentado antes? Aqui es donde piensas en voz alta, ya sea solo o con Claude Code en modo conversacional. La condicion de salida es: tienes un enfoque preferido y entiendes las compensaciones.
Fase 2: Revision. Pones a prueba el enfoque. Que podria salir mal? Que casos limite existen? Esto conflictua con algo que ya esta en el codebase? Si trabajas con multiples agentes, aqui es donde un agente de arquitectura o una segunda opinion es valioso. La condicion de salida es: estas seguro de que el enfoque es solido.
Fase 3: Spec. Escribes lo que decidiste. Planteamiento del problema, enfoque propuesto, archivos a modificar, criterios de aceptacion verificables mecanicamente y un plan de pruebas. Este es el contrato. La condicion de salida es: alguien (humano o agente) podria leer esta spec y saber exactamente que construir y como verificarlo.
Fase 4: Implementacion. El agente ejecuta contra la spec. No contra una idea vaga. Contra un documento concreto con criterios testeables. La condicion de salida es: el agente dice que termino y ha publicado evidencia de verificacion.
Fase 5: Verificacion. Tu (o un agente de QA) confirmas que la implementacion coincide con la spec. No "se ve bien" sino "satisface cada criterio de aceptacion." La condicion de salida es: cada criterio esta verificado, y los que fallan regresan a la Fase 4.
La idea clave: las fases 1-3 son baratas. Toman 10-20 minutos para una funcionalidad de tamano medio. La fase 4 toma lo que dure la implementacion. La fase 5 toma 5-10 minutos. Saltarse las fases 1-3 no ahorra 10-20 minutos. Te cuesta el tiempo de revisar, depurar y rehacer trabajo que fue en la direccion equivocada.
Como se ve una buena spec para agentes
Aqui hay una plantilla de spec real. No una user story. No un documento de requisitos de producto. Un documento de trabajo que le dice a un agente exactamente que construir.
## Problem
The filter bar resets when switching workspaces. Users lose their
filter state and have to re-apply filters every time they switch.
## Approach
Persist filter state per-workspace in localStorage. Key the stored
state by workspace database path so filters don't bleed across
workspaces.
## Files to Modify
- lib/local-storage.ts: Add getWorkspaceFilters / setWorkspaceFilters
- components/filter-bar.tsx: Read initial state from localStorage,
write on every change
- hooks/use-workspace.ts: Trigger filter restore on workspace switch
## Acceptance Criteria
1. Select workspace A, set filters to status=open + type=bug
2. Switch to workspace B. Filters reset to defaults.
3. Switch back to workspace A. Filters restore to status=open + type=bug.
4. Close the browser tab, reopen. Filters for the active workspace
are still applied.
5. bd list --status=open --type=bug output matches the filtered table.
## Out of Scope
- Server-side filter persistence
- Filter presets / saved filter combinations
- URL-based filter state (query params)
## Test Plan
- Unit test: getWorkspaceFilters returns stored value for matching
workspace path
- Unit test: setWorkspaceFilters writes correct key format
- Manual test: steps 1-5 from acceptance criteria above
Observa lo que esta spec contiene y lo que no. No explica como funciona localStorage. Claude Code sabe eso. No justifica por que elegimos localStorage en vez de URL params. Eso paso en la fase de lluvia de ideas. Si lista cada archivo que el agente debe tocar, lo que significa que si el agente empieza a modificar archivos fuera de esta lista, eso es una senal de alerta. Incluye una seccion de fuera de alcance, que evita que el agente haga gold plating.
Los criterios de aceptacion son la parte mas importante. Cada uno es una accion concreta con un resultado observable. No "los filtros deberian persistir." Eso es ambiguo. "Cambia al workspace A, verifica que los filtros son status=open + type=bug" es testeable. Un agente puede ejecutar eso. Un revisor de QA puede verificarlo.
El patron plan-antes-del-codigo
Aqui hay un protocolo que atrapa la mayoria de los errores de implementacion antes de que se conviertan en codigo: exigirle al agente que publique su plan de implementacion antes de escribir algo.
En la practica, esto se ve como un comentario estructurado en la tarea. Antes de que el agente abra cualquier archivo, escribe exactamente lo que piensa hacer.
PLAN: Persist filter state per-workspace using localStorage.
1. Add workspace-scoped storage helpers to lib/local-storage.ts:
- getWorkspaceFilters(dbPath: string): FilterState | null
- setWorkspaceFilters(dbPath: string, filters: FilterState): void
- Key format: "beadbox:filters:{dbPath}"
2. Update components/filter-bar.tsx:
- On mount, read stored filters for current workspace
- On every filter change, write to localStorage
- Accept databasePath as prop (currently not passed)
3. Update hooks/use-workspace.ts:
- On workspace switch, emit event that filter-bar listens for
- Filter-bar reads new workspace's stored filters on event
4. Threading databasePath:
- filter-bar needs databasePath from the workspace context
- Will add it to the WorkspaceProvider context value
Files: lib/local-storage.ts, components/filter-bar.tsx,
hooks/use-workspace.ts, components/workspace-provider.tsx
Test: Unit tests for storage helpers, manual test of all 5
acceptance criteria.
Esto le toma al agente unos 30 segundos. A ti te toma unos 2 minutos leerlo. Y en esos 2 minutos, puedes detectar problemas que tomarian 20 minutos arreglar despues de la implementacion:
- Esta el agente tocando archivos fuera de la spec? (Agregar workspace-provider.tsx no estaba en la spec. Eso esta bien o es scope creep?)
- Tiene sentido el enfoque? (Usar un event emitter para cambios de workspace podria estar sobredimensionado. Un cambio de prop mas simple podria funcionar.)
- Faltan pasos? (Que pasa con limpiar entradas antiguas de localStorage cuando se elimina un workspace?)
El plan es un checkpoint. Si se ve bien, dile al agente que continue. Si se ve mal, corrige el plan. De cualquier forma, invertiste 2 minutos en vez de 20.
