Curso práctico de specs: skills y agentes en cada etapa
¿Tienes 10 minutos? Empieza por la ruta exprés: tu primer ciclo completo, con tu primera skill y tu primer agente. ¿Quieres llegar a experto? Sigue con las misiones: un caso guiado de punta a punta con Spec Kit y OpenSpec que incluye los temas avanzados, como el trabajo en paralelo, el drift, el legacy y la modernización. Poca teoría: haces, pegas el prompt y compruebas.
Comandos, archivos y salidas medidos el 2026-10-18 con Spec Kit 1.2.1 y OpenSpec 1.14.3. Lo de subagentes y hooks de Cursor sale de su documentación, consultada el 18-oct-2026.
10 min
Ruta exprés: tu primer ciclo completo
Cursor + OpenSpec · cinco pasos de copiar y pegar
Al terminar vas a tener un cambio propuesto, validado, implementado, revisado por un agente y archivado, más tu primera skill y tu primer agente. Eso no te hace experto, pero te pone el ciclo completo en la mano. Lo experto viene en las misiones.
Antes: Cursor abierto y Node 20.19 o más (node --version). Los comandos de terminal tardan segundos medido; lo que más tarda es que el agente escriba estimado.
Haz
npm install -g @fission-ai/openspec@1.14.3
mkdir -p ~/lab-expres && cd ~/lab-expres && git init -b main
openspec init --tools cursor --language es
git add -A && git commit -m "Base: OpenSpec"
cursor .
Debes vermedido
$ openspec init --tools cursor --language es
▌ OpenSpec structure created
✔ Setup complete for Cursor
OpenSpec Setup Complete
Created: Cursor
6 skills and 6 commands in .cursor/
Config: openspec/config.yaml (schema: spec-driven)
Getting started:
Start your first change: /opsx-propose "your idea"
Note: 6 more workflows are available (new, continue, ff, bulk-archive, verify, onboard).
Add them with `openspec config profile`.
Learn more: https://github.com/Fission-AI/OpenSpec
Feedback: https://github.com/Fission-AI/OpenSpec/issues
Restart your IDE to refresh commands.
Haz(en la terminal, dentro de ~/lab-expres; es un solo bloque)
mkdir -p .cursor/skills/revisar-spec
cat > .cursor/skills/revisar-spec/SKILL.md <<'FIN_DEL_ARCHIVO'
---
name: revisar-spec
description: Revisa una spec de Spec Kit o de OpenSpec sin editarla y señala requisitos que no se pueden probar, palabras ambiguas, requisitos sin escenario, tecnología que se coló y criterios de éxito sin número. Usar después de especificar y antes de planear, o cuando pidan revisar una spec.
---
# Revisar una spec
Sólo lees. No edites ningún archivo.
1. Ubica la spec: la ruta que te den; si no, `.specify/feature.json` (Spec Kit) o el cambio activo de `openspec list` (OpenSpec).
2. Revisa cada requisito:
- ¿Se puede probar con un escenario concreto? Si no, es un hallazgo.
- ¿Usa palabras sin número («rápido», «fácil», «adecuado», «robusto», «intuitivo»)?
- ¿Tiene al menos un escenario? En OpenSpec, ¿lleva SHALL o MUST y escenarios con cuatro `#`?
- ¿Menciona clases, tablas, librerías o frameworks? Eso va en el plan o en el diseño.
3. Revisa los criterios de éxito: cada uno con número y sin tecnología.
4. Entrega una tabla `ubicación | problema | propuesta`, de lo más grave a lo menos grave.
5. Termina con una línea: «Lista para planear» o «Necesita cambios (N hallazgos)».
FIN_DEL_ARCHIVO
mkdir -p .claude/agents
cat > .claude/agents/revisor-conformidad.md <<'FIN_DEL_ARCHIVO'
---
name: revisor-conformidad
description: Revisa, sólo leyendo, si el cambio de la rama cumple su spec requisito por requisito (implementado, con prueba que cita su ID, criterio cumplido), qué se coló fuera de la spec y si alguna prueba se apagó, se aflojó o se borró. Usar antes de abrir el PR o con /conformidad. No edita nada.
tools: Read, Grep, Glob, Bash
readonly: true
---
# Revisor de conformidad
No escribiste este código: lo revisas contra su spec. Sólo lees. Bash es sólo para `git` y `rg`.
## Cómo revisas
1. Lista los requisitos de la spec: los `FR-###` de Spec Kit, o los `### Requirement:` de OpenSpec con sus escenarios.
2. Lee el diff: `git diff --stat <base>...HEAD`, `git diff <base>...HEAD` y lo que no tiene commit.
3. Por cada requisito: ¿el diff lo implementa? (cita `archivo:línea`). ¿Qué prueba lo cita en su nombre? ¿Se cumple su criterio?
4. Al revés: ¿qué cambios del diff no rastrean a ningún requisito? Repórtalos aunque sean un refactor válido.
5. Busca pruebas apagadas, aflojadas o borradas: `@Disabled`, `@Ignore`, `.skip`, aserciones borradas o comentadas, un valor concreto que pasó a `any()`.
6. Revisa que el diff no rompa una regla de `AGENTS.md`, de la constitución o de `openspec/config.yaml`.
7. Por cada firma pública que cambió, busca con `rg` quién la llama fuera del diff.
## Reglas
- Todo hallazgo lleva `archivo:línea`. Si no lo puedes citar, no lo afirmes.
- Máximo 3 bloqueantes, en orden de gravedad. No comentes estilo ni rediseñes.
- Si te falta la spec o la base, dilo y para.
## Salida
```
## Conformidad: NO LISTO | LISTO CON PENDIENTES | LISTO PARA PR
| Requisito | ¿Implementado? | Prueba | ¿Criterio cumplido? |
|---|---|---|---|
Fuera de la spec: …
Pruebas apagadas, aflojadas o borradas: …
Reglas rotas: …
### Bloqueantes (máximo 3)
1. `archivo:línea` — qué pasa, por qué importa y cómo se arregla.
```
FIN_DEL_ARCHIVO
Debes ver
Dos archivos: la skill revisar-spec, que revisa una spec, y el agente revisor-conformidad, de sólo lectura, que revisa el código contra la spec. El bloque está probado: crea los archivos idénticos a los de la misión 5. Abre un chat nuevo para que Cursor los vea.
Pega(en el chat de Cursor)
/opsx-propose bloquear-marcas: Gobierno de Datos puede bloquear una marca, y el alta de productos de una marca bloqueada se rechaza con el código MARCA_BLOQUEADA. Fuera de alcance: bajar lo ya publicado. Un comportamiento por requisito, cada uno con un escenario feliz y uno de error.
Usa el subagente revisor-conformidad para revisar este cambio contra openspec/changes/bloquear-marcas, con base main.
Debes ver
Un veredicto (LISTO PARA PR, LISTO CON PENDIENTES o NO LISTO) con una fila por requisito. Si dice NO LISTO, pide que se arregle y repite la revisión.
Pega
/opsx-archive bloquear-marcas
Compruebamedido(el nombre de la capacidad lo elige el agente; el tuyo puede ser otro)
$ openspec list --specs
Specs:
bloqueo-de-marcas requirements 2
Lo lograste. Recorriste cinco etapas del mapa: especificar, revisar con una skill, implementar, pasar la conformidad con un agente y archivar. Para llegar a experto te falta esto, y aquí se practica:
La base del repo: reglas, contexto y mapa de specs → misión 1.
Spec Kit para servicios nuevos: constitución, clarify, plan, checklists y analyze → misiones 2 a 5.
Varios cambios a la vez con worktrees e integración por riesgo → misión 7.
Legacy sin spec y modernización por módulos → misiones 9 y 10.
Cómo funciona
Vas a construir un servicio de catálogo de marcas en un repo de práctica. Nace con Spec Kit, recibe cambios con OpenSpec y lo cuidan agentes de revisión. Al final rescatas un módulo viejo sin documentar y lo modernizas. Después de la ruta exprés vienen las misiones 0 a 10, de 10 a 30 minutos cada una.
Cada tarea tiene una casilla, y tu avance se guarda en este navegador. Dentro de cada tarea vas a ver:
Haz
Lo que haces tú, en la terminal o en el chat.
Pega
El prompt exacto, con botón de copiar.
Debes ver
Lo que tiene que aparecer: archivos, salidas o un informe.
Comprueba
Un comando que confirma que salió bien antes de seguir.
Los recuadros Taller son donde escribes tus propias skills, agentes y hooks. La teoría va plegada en «¿Por qué?»: ábrela si la necesitas.
Lo mínimo de teoría
Spec
Qué debe hacer el sistema y por qué, sin decir cómo. Se escribe antes que el código y manda sobre él.
Requisito y escenario
Una regla que se puede probar (FR-002 o ### Requirement:) y un ejemplo concreto que la prueba. Cada escenario se vuelve una prueba.
Cambio y delta (OpenSpec)
Un cambio propone qué se agrega, modifica o quita en la spec viva del sistema. Al archivarlo, la spec viva se actualiza.
Skill
Una carpeta con SKILL.md: un procedimiento que el agente sigue en tu misma conversación, cuando aplica o cuando escribes /nombre.
Agente (subagente)
Otro agente con su propio contexto, limpio. Sólo le devuelve al principal su mensaje final. Sirve para revisar sin sesgo, investigar mucho o trabajar en paralelo.
Hook
Un script que se dispara en un evento (antes de un comando, antes de editar) y puede bloquearlo. Es el candado que no depende de la buena voluntad del agente.
Cómo leer las etiquetas
Medido lo corrimos y es la salida real. Simulado lo escribimos como lo haría el agente, sobre las plantillas reales; los ejemplos de OpenSpec además pasaron su validador estricto. Citado lo dice la documentación oficial o la regla de un equipo. Inferido es una deducción nuestra.
El mapa: qué skill, agente o hook en cada etapa
Ésta es la tabla que vas a usar todo el curso. Cada fila es una etapa del trabajo con specs; cada misión te dice en qué filas estás. Filtra por flujo:
Etapa
Qué haces
Skill o comando
Agente (contexto aparte)
Candado
Misión
Base del repo
Reglas, contexto, constitución, mapa de specs y config.yaml, una vez y en su propio PR
Los tres niveles de SDD: ¿qué pasa con la spec al terminar?
Nivel
Qué pasa con la spec
Herramienta
En este curso
Spec-first
Una spec por feature. Sirve para construirla, se cierra y queda como un capítulo del libro; lo nuevo va en otra spec
Spec Kit: por eso numera las specs y crea una rama por spec
Misiones 1 a 5
Spec-anchored
Una spec viva por capacidad, que cada cambio modifica: es el contrato de la aplicación. Su gran reto es el drift
OpenSpec
Misiones 6 a 8
Spec-as-source
Una spec por archivo de código. Sólo se tocan las specs, y una herramienta genera el código a partir de ellas
Herramientas todavía en desarrollo
Sólo se explica
El curso de SDD que sigue el equipo recomienda spec-first como el más mantenible en entornos profesionales, porque mantener una sola spec viva en el tiempo exige mucho cuidado; los otros dos siguen siendo válidos curso de SDD, sección 5. Aquí se usan los dos primeros según la vida del servicio: spec-first mientras nace y spec-anchored cuando ya vive.
La regla para decidir: ¿skill, agente, regla o hook?
Si necesitas…
Usa
En el curso
Que algo pase siempre, aunque el agente no quiera
Hook
no-saltar-pruebas
Contexto que aplica a todo el repo, en cada turno
Regla: AGENTS.md, la constitución o config.yaml
Stack fijo y no negociables
Un procedimiento corto y repetible que el agente use cuando aplique
Skill
revisar-spec
Lo mismo, pero sólo cuando tú lo pidas
Skill con disable-model-invocation: true
/conformidad
Ojos frescos, revisar el trabajo de otro, una investigación larga o trabajo en paralelo
Agente, de sólo lectura si revisa
revisor-conformidad, auditor-drift
La documentación de Cursor da la misma regla: un subagente sirve para aislar una investigación larga, correr trabajo en paralelo o verificar de forma independiente; si la tarea es simple, como «generar un changelog», usa una skill cursor.com/docs/subagents.
Misión 0
Arma tu laboratorio
10 minutos · un repo de práctica con las dos herramientas
Node debe ser 20.19 o más. Con Node 18, OpenSpec ni arranca: responde SyntaxError: Unexpected token 'with'medido. Si te falta uv, instálalo con su instalador oficial (docs.astral.sh/uv).
specify 1.2.1 y 1.14.3medido. Si specify no se encuentra, corre uv tool update-shell y abre otra terminal.
Haz
mkdir -p ~/lab-specs && cd ~/lab-specs && git init
specify init --here --force --integration cursor-agent --script sh
openspec init --tools cursor --language es
En Cursor se invocan /speckit-… y /opsx-….
mkdir -p ~/lab-specs && cd ~/lab-specs && git init
specify init --here --force --integration claude --script sh
openspec init --tools claude --language es
En Claude Code se invocan /speckit-… y /opsx:….
mkdir -p ~/lab-specs && cd ~/lab-specs && git init
specify init --here --force --integration codex --script sh
openspec init --tools codex --language es
En Codex las skills de Spec Kit se invocan con $speckit-…. El init de OpenSpec para Codex no lo medimos.
mkdir -p ~/lab-specs && cd ~/lab-specs && git init
specify init --here --force --integration copilot --script sh
openspec init --tools github-copilot --language es
Con Copilot todo queda en .github/: skills en .github/skills/ y los comandos de OpenSpec como prompt files en .github/prompts/. Se invocan /speckit-… y /opsx-…. Así quedó con el perfil completo de OpenSpec medido:
Existen .specify/ y openspec/. Spec Kit pide --force porque la carpeta ya tiene .git: sin él, en modo no interactivo se niega medido.
El perfil por defecto trae 6 flujos; el curso usa también new, continue, ff, verify y bulk-archive. Es configuración global de tu máquina, y openspec update regenera los archivos del repo.
Haz
openspec config set profile custom
openspec config set workflows '["propose","explore","new","continue","apply","update","ff","sync","archive","bulk-archive","verify","onboard"]'
openspec update
Debes ver
$ openspec update
Updating 2 tool(s): claude (1.14.3 → 1.14.3), cursor (1.14.3 → 1.14.3)
✔ Updated Claude Code
✔ Updated Cursor
✓ Updated: Claude Code, Cursor (v1.14.3)
Tools: Claude Code, Cursor
Restart your IDE to refresh commands.
Comprueba
ls .cursor/skills | wc -l # 10 de Spec Kit + 12 de OpenSpec = 22
git add -A && git commit -m "Laboratorio: Spec Kit y OpenSpec"
Reinicia el IDE o abre un chat nuevo para que aparezcan los comandos.
Aquí no hace falta ni skill ni agente: son reglas. Las lee cualquier agente, en cada turno.
Haz
Crea AGENTS.md en la raíz y, para Claude Code, un CLAUDE.md que sólo diga @AGENTS.md. Así hay una sola copia de las reglas. En este workspace, Cursor aplica los dos archivos como reglas del proyecto observado.
# AGENTS.md — reglas del repo para cualquier agente
## Stack (fijo; no se renegocia en una propuesta)
- Java 21, Spring Boot 3.3 WebFlux y MongoDB. Pruebas: JUnit 5 y Testcontainers.
## No negociables
- La spec primero: nada de código sin una spec o un cambio aprobado. Servicio que nace → Spec Kit (`specs/`); servicio que ya vive → OpenSpec (`openspec/`).
- Cada requisito tiene una prueba que lo cita en su nombre (`FR-002: …`, o el nombre del escenario en OpenSpec).
- Prohibido saltarse o apagar pruebas para llegar a verde. Lo bloquea un hook.
- Sin secretos en el código, en los logs ni en las pruebas.
## Cómo trabajas aquí
- Si falta información para un paso, para y pregunta; no adivines.
- Un cambio = una rama. No toques código fuera del alcance del cambio.
- Si a mitad de camino algo de la spec está mal, corrige el artefacto (spec, design o tasks), no el código por fuera.
- Antes del PR: corre todas las pruebas y pide la revisión de conformidad (`/conformidad`).
## Dónde está cada cosa
- Contexto del negocio: `contexto-proyecto.md`. Mapa de specs del equipo: `specs/README.md`.
- Reglas de OpenSpec: `openspec/config.yaml`. Constitución de Spec Kit: `.specify/memory/constitution.md`.
Taller: tus reglas
Cambia el stack por el tuyo y deja máximo diez líneas de «no negociables». Cada línea se paga en cada turno, y una regla que nadie puede verificar («código limpio») no sirve.
Haz
Uno solo para todo el repo. Las specs lo heredan; no se recrea por feature.
# Contexto del proyecto
**Qué es:** el servicio de catálogo de marcas. Gobierno de Datos administra las marcas; los sistemas que dan de alta productos consultan si una marca se puede usar.
**Quién lo usa:** Gobierno de Datos (administra), Compras (consulta) y los vendedores, que dan de alta productos desde otro sistema.
**Términos:** marca activa, inactiva o bloqueada. «Alta» es crear un producto.
**Qué NO hace:** no guarda productos ni precios, y no tiene pantalla propia.
**Quién decide:** las reglas de negocio, Gobierno de Datos; la arquitectura, el arquitecto del equipo.
Pega
/speckit-constitution Proyecto: servicio de catálogo de marcas.
Principios:
1. La spec manda: no se programa nada sin spec aprobada.
2. Pruebas primero (no negociable): cada FR tiene una prueba que lo cita en su nombre.
3. Contratos antes que implementación: OpenAPI en contracts/.
4. Errores RFC 7807 con un código de negocio estable.
5. Lo más simple que cumpla; toda complejidad extra se justifica en el plan.
Restricciones: Java 21, Spring Boot 3.3, MongoDB, inyección por constructor, ningún secreto en el repo.
Escribe el contenido en español y deja los encabezados de la plantilla como están.
Debes ver
.specify/memory/constitution.md sin marcadores entre corchetes, con versión 1.0.0 y un «Sync Impact Report» arriba simulado. Ábrelo en el explorador de la misión 3, etapa 2.
Haz
specs/README.md es el único lugar donde el equipo ve qué está especificado, quién es dueño de cada concepto y qué se decidió no hacer.
# Mapa de Specs
Índice versionado del equipo: qué se especificó, en qué estado va y quién es dueño de cada concepto.
Se actualiza al abrir un feature (`prevista` o `en curso`) y al cerrarlo (`publicada`).
| # | Nombre | Qué aporta | Estado | Dueño | Depende de | Rama |
|---|---|---|---|---|---|---|
| 001 | catalogo-de-marcas | Alta, consulta, desactivación e historial de marcas | prevista | dev A | — | — |
> Estados: `prevista` · `en curso` · `publicada` · `sustituye a NNN`.
## Conceptos con dueño
Cada concepto lo define una sola spec; las demás la citan. Si dos lo definen distinto, corre la revisión cruzada.
- (todavía ninguno)
## Fuera de alcance acumulado
- (todavía nada)
Haz
Reemplaza openspec/config.yaml. context va en todos los artefactos que genera OpenSpec; rules, sólo en el artefacto de su sección. Fija ahí el stack: sin él, cada design.md puede proponer uno distinto.
schema: spec-driven
# context se inyecta en TODOS los artefactos que genera OpenSpec: que sea corto.
context: |
Catálogo de marcas: administra las marcas que se pueden usar al dar de alta productos.
Language: es
All artifacts must be written in es.
Keep OpenSpec structural headings and SHALL/MUST keywords in English.
Stack técnico (fijado; no se renegocia en propuestas):
- Java 21 + Spring Boot 3.3 WebFlux; MongoDB.
- Pruebas: JUnit 5 + Testcontainers. Cada escenario tiene una prueba que se llama como el escenario.
Principios innegociables:
1. La spec es la fuente de verdad: lo que openspec/specs/ no describe es un defecto, aunque funcione.
2. Lo más simple que cumpla.
3. Una marca nunca se borra: se desactiva o se bloquea.
# rules sólo se inyecta al generar ese artefacto.
rules:
proposal:
- Incluye siempre qué NO cambia.
- Registra cada decisión de negocio con su fecha y quién la tomó.
specs:
- Si la capacidad ya existe en openspec/specs/, modifícala (MODIFIED); no la dupliques con ADDED.
- Reutiliza los términos de las specs vivas; no inventes sinónimos.
design:
- Ninguna dependencia nueva sin justificación escrita (ADR en estado Proposed).
Tu context y las rules de specs dentro de las instrucciones que recibe el agente medido:
$ openspec instructions specs --change prueba-reglas
(…)
<project_context>
<!-- This is background information for you. Do NOT include this in your output. -->
Catálogo de marcas: administra las marcas que se pueden usar al dar de alta productos.
Language: es
All artifacts must be written in es.
Keep OpenSpec structural headings and SHALL/MUST keywords in English.
Stack técnico (fijado; no se renegocia en propuestas):
- Java 21 + Spring Boot 3.3 WebFlux; MongoDB.
- Pruebas: JUnit 5 + Testcontainers. Cada escenario tiene una prueba que se llama como el escenario.
Principios innegociables:
1. La spec es la fuente de verdad: lo que openspec/specs/ no describe es un defecto, aunque funcione.
2. Lo más simple que cumpla.
3. Una marca nunca se borra: se desactiva o se bloquea.
</project_context>
<rules>
<!-- These are constraints for you to follow. Do NOT include this in your output. -->
- Si la capacidad ya existe en openspec/specs/, modifícala (MODIFIED); no la dupliques con ADDED.
- Reutiliza los términos de las specs vivas; no inventes sinónimos.
</rules>
(…)
Haz
git switch -c base-del-repo
git add -A && git commit -m "Base del repo: reglas, contexto, constitución, mapa de specs y config de OpenSpec"
¿Por qué en su propio PR?
Si dos devs arman la base a la vez dentro de sus features, quedan dos constituciones o dos AGENTS.md que no se fusionan bien. La base va primero y en secuencia; los features arrancan cuando se integra regla del kit de un equipo.
Misión 2
Especifica con Spec Kit y estrena tu primera skill
25 minutos · el qué y el porqué, y una skill que lo revisa
Usas: las skills /speckit-specify y /speckit-clarify, la extensión git de Spec Kit si la quieres, y escribes tu skill revisar-spec.
Spec Kit se amplía con extensiones: paquetes que agregan comandos y hooks que corren antes o después de cada comando. La extensión git crea la rama de la feature antes de especificar y puede hacer commit antes y después de cada fase.
El autocommit viene apagado. Se enciende en .specify/extensions/git/git-config.yml: pon auto_commit.default en true y el enabled de cada comando que quieras. Ahí también se ajusta el nombre de la rama a la convención del equipo con branch_template o branch_prefixmedido el archivo. Un ejemplo simulado:
branch_template: "feature/{number}-{slug}" # el último tramo debe empezar con {number}-
auto_commit:
default: true
before_plan:
enabled: true
Los hooks de Spec Kit no son candados. Son instrucciones que el agente lee en cada comando, y el curso de SDD muestra que a veces no se ejecutan curso de SDD, sección 4. Lo que no puede fallar va en un hook del agente (misión 4) o en el CI.
Si no la quieres, por ejemplo porque tu equipo ya tiene su convención de ramas, apágala y crea tú la rama en la tarea siguiente medido:
$ specify extension disable git
✓ Extension 'Git Branching Workflow' disabled
Commands will no longer be available. Hooks will not execute.
To re-enable: specify extension enable git
Haz
git switch -c 001-catalogo-de-marcas
Spec Kit no crea la rama: eso lo hace su extensión de git, que no instalamos. La carpeta de la spec y la rama son independientes medido de la skill.
Pega(en un chat nuevo)
/speckit-specify Catálogo de marcas.
Quién lo usa: Gobierno de Datos administra las marcas; otros sistemas consultan si una marca se puede usar.
Qué necesita: dar de alta, editar, desactivar (sin borrar) y consultar marcas. El nombre no se repite aunque cambien mayúsculas o espacios.
Por qué: hoy hay marcas duplicadas y productos con marcas retiradas.
Criterios de aceptación (los escribo yo):
- Dar de alta "Zeta" cuando ya existe "zeta" se rechaza con MARCA_DUPLICADA.
- Una marca desactivada sigue existiendo y la consulta dice que está inactiva.
Fuera de alcance: la pantalla y la carga inicial de marcas.
Reglas: no menciones tecnología. Lo que no esté claro márcalo [NEEDS CLARIFICATION] en vez de suponerlo. Escribe en español y deja los encabezados de la plantilla.
Los criterios los escribes tú. El curso de SDD pide escribir a mano la primera versión de la spec, con criterios de aceptación que se puedan verificar; la IA la mejora, no la inventa curso de SDD, sección 3. Si no tienes tiempo para la spec entera, al menos escribe tú los criterios, como en el prompt.
Debes ver
specs/001-catalogo-de-marcas/spec.md, checklists/requirements.md y .specify/feature.json. Si quedan dudas, como máximo tres preguntas con opciones A, B y C medido de la skill.
Comprueba
ls specs/001-*/ && cat .specify/feature.json && git branch --show-current
grep -c "FR-0" specs/001-*/spec.md # cada requisito con su ID
Taller: tu primera skill
Etapa: entre especificar y planear. Por qué skill y no agente: es corta, repetible y la quieres dentro de tu conversación mientras corriges la spec.
Guárdala en .cursor/skills/revisar-spec/SKILL.md (Claude Code: .claude/skills/; Codex: .agents/skills/, que Cursor también lee).
---
name: revisar-spec
description: Revisa una spec de Spec Kit o de OpenSpec sin editarla y señala requisitos que no se pueden probar, palabras ambiguas, requisitos sin escenario, tecnología que se coló y criterios de éxito sin número. Usar después de especificar y antes de planear, o cuando pidan revisar una spec.
---
# Revisar una spec
Sólo lees. No edites ningún archivo.
1. Ubica la spec: la ruta que te den; si no, `.specify/feature.json` (Spec Kit) o el cambio activo de `openspec list` (OpenSpec).
2. Revisa cada requisito:
- ¿Se puede probar con un escenario concreto? Si no, es un hallazgo.
- ¿Usa palabras sin número («rápido», «fácil», «adecuado», «robusto», «intuitivo»)?
- ¿Tiene al menos un escenario? En OpenSpec, ¿lleva SHALL o MUST y escenarios con cuatro `#`?
- ¿Menciona clases, tablas, librerías o frameworks? Eso va en el plan o en el diseño.
3. Revisa los criterios de éxito: cada uno con número y sin tecnología.
4. Entrega una tabla `ubicación | problema | propuesta`, de lo más grave a lo menos grave.
5. Termina con una línea: «Lista para planear» o «Necesita cambios (N hallazgos)».
name es el comando y debe ser igual a la carpeta: minúsculas y guiones, 64 caracteres como máximo.
description dice qué hace y cuándo usarla. Es lo único que el agente lee para decidir si la carga sola.
No lleva disable-model-invocation: queremos que el agente la use cuando le pidas «revisa la spec».
Queda un [NEEDS CLARIFICATION]: no dice cuánto tiempo se guarda el historial
Resolverlo en /speckit-clarify
FR-003
«Sistema autorizado» no dice cuáles ni cómo se autentican
Definir la lista o el criterio
SC-001
«En menos de 1 minuto» no dice cómo se mide
Medirlo en la prueba de aceptación
Necesita cambios (3 hallazgos)
Si falla
Si /revisar-spec no aparece, revisa que name sea igual a la carpeta y abre otro chat: en Cursor, la lista de skills se fija al empezar el chat foro oficial de Cursor.
Pega
/speckit-clarify Enfócate en reglas de negocio y casos límite: duplicados, concurrencia e historial. No preguntes de tecnología. Si no sé una respuesta, déjala como pregunta abierta, no como requisito.
Debes ver
Como máximo cinco preguntas, de una en una. Cada respuesta queda en ## Clarifications y cambia el requisito que toca: FR-006 se resuelve y aparece FR-007 simulado.
Comprueba
grep -n "### Session" specs/001-*/spec.md
grep -c "NEEDS CLARIFICATION" specs/001-*/spec.md # debe ser 0
git add -A && git commit -m "Spec 001: catálogo de marcas"
Reto: ¿qué tiene de malo este requisito?
- **FR-008**: El sistema MUST guardar las marcas en MongoDB con un índice único y responder rápido.
Respuesta: tres cosas. Mete tecnología (MongoDB, índice), que va en el plan. «Rápido» no se puede probar: necesita un número, como el SC-002. Y mezcla dos comportamientos en un requisito. Debería decir: «El sistema MUST rechazar un nombre de marca repetido» (y el rendimiento va como criterio de éxito con número).
Misión 3
Planea, divide y analiza
20 minutos · el cómo, las tareas y la revisión cruzada de artefactos
Usas:/speckit-plan, /speckit-tasks y /speckit-analyze. Un chat nuevo por paso: el estado vive en los archivos.
Haz
Mira specs/README.md. Si otro dev tiene una spec en curso, corre antes la revisión cruzada (misión 7): los choques se arreglan en la spec, no en el merge. En el laboratorio estás solo: sigue.
Pega
/speckit-plan Stack: Java 21, Spring Boot 3.3 WebFlux y MongoDB; pruebas con JUnit 5 y Testcontainers.
Contrato OpenAPI en contracts/. Nada de caché ni mensajería, salvo que un criterio de éxito lo exija.
Si algo viola la constitución, detente y dime qué principio y por qué.
Al final, propón qué decisiones transversales de este plan deben pasar a AGENTS.md.
Debes ver
plan.md, research.md, data-model.md, contracts/ y quickstart.md, con la «Constitution Check» en ✅ simulado.
Comprueba
ls specs/001-*/ specs/001-*/contracts/
grep -A8 "Constitution Check" specs/001-*/plan.md
Una checklist no prueba el código: prueba si los requisitos de un tema están completos, claros y son medibles. Haz una por cada dominio delicado y resuelve las casillas pendientes antes de las tareascurso de SDD, sección 3.
Pega
/speckit-checklist seguridad: roles, autenticación entre sistemas y qué pasa cuando se niega un permiso
Debes ver
checklists/seguridad.md, con casillas CHK001, CHK002… y entre corchetes qué revisan: [Gap], [Ambiguity] o [Consistency]simulado. Cada casilla sin marcar es un hueco de la spec: corrígelo con /speckit-clarify o editando la spec, y vuelve a correr la checklist. Ábrela en el explorador de esta misión, etapa 6.
Pega
/speckit-tasks Pruebas primero en cada historia (la constitución lo exige). Cada prueba lleva en su nombre el FR que cubre, por ejemplo "FR-002: rechaza nombre repetido". Tareas de medio día como máximo.
Comprueba
grep -c "^- \[ \] T" specs/001-*/tasks.md # cuántas tareas
for fr in $(grep -oE "FR-[0-9]{3}" specs/001-*/spec.md | sort -u); do
grep -q "$fr" specs/001-*/tasks.md || echo "$fr no aparece en ninguna tarea"
done
Pega
/speckit-analyze Dame primero los CRITICAL y HIGH, cada uno con el arreglo que propones. No edites nada hasta que yo apruebe.
Debes ver
Un informe en el chat, sin archivos nuevos: analyze sólo lee medido de la skill. Un ejemplo simulado:
ID
Category
Severity
Location(s)
Summary
Recommendation
C1
Coverage
HIGH
spec.md FR-005 · tasks.md
FR-005 (quién y cuándo) sólo tiene tarea en el alta
Agregarlo a T015
A1
Ambiguity
MEDIUM
spec.md FR-003
«Sistema autorizado» no está definido
Aclararlo
🛑 Cero CRITICAL antes de implementar. Aprueba los arreglos y vuelve a correr analyze.
Avanza el explorador hasta la etapa en la que vas. Lo de specify init y las plantillas es medido; lo que escribe el agente es simulado. Verde = nuevo en esa etapa; ámbar = cambió.
git add -A && git commit -m "Spec 001: plan, tareas y análisis"
Misión 4
Implementa con candados
25 minutos · un hook, las pruebas primero y nada sin rastro
Usas: tu hook no-saltar-pruebas, /speckit-implement y /speckit-converge.
Taller: tu primer hook
Etapa: implementar. Por qué hook: una regla en AGENTS.md el agente la puede olvidar; un hook corre siempre, y si sale con código 2, la acción no ocurre.
Regístralo en .cursor/hooks.json y guarda el script en .cursor/hooks/:
#!/usr/bin/env bash
# Bloquea los comandos que se saltan pruebas o verificaciones.
# Cursor lo llama en beforeShellExecution y le manda {"command": …} por stdin.
# Claude Code lo llama en PreToolUse (matcher Bash) y le manda {"tool_input": {"command": …}}.
# Código de salida 2 = bloquear en los dos.
leido="$(python3 -c 'import sys, json
d = json.load(sys.stdin)
if "command" in d:
print("cursor\t" + d["command"])
else:
print("claude\t" + d.get("tool_input", {}).get("command", ""))' 2>/dev/null)"
origen="${leido%%$'\t'*}"
comando="${leido#*$'\t'}"
saltos='-DskipTests|maven\.test\.skip=true|maven\.test\.failure\.ignore=true|jacoco\.skip=true|--no-verify'
saltos_gradle='gradlew?( [^|;&]*)? (-x|--exclude-task)[ =]?[^ ]*(test|check|jacoco)'
if printf '%s' "$comando" | grep -Eq -e "$saltos" -e "$saltos_gradle"; then
if [ "$origen" = "cursor" ]; then
echo '{"permission": "deny", "user_message": "Bloqueado: no se permite saltarse pruebas ni verificaciones.", "agent_message": "Corre la suite completa; en este repo está prohibido saltarse pruebas."}'
fi
echo "Bloqueado: no se permite saltarse pruebas ni verificaciones. Corre la suite completa." >&2
exit 2
fi
[ "$origen" = "cursor" ] && echo '{"permission": "allow"}'
exit 0
chmod +x .cursor/hooks/no-saltar-pruebas.sh
En Claude Code el mismo script va como hook PreToolUse con "matcher": "Bash" en .claude/settings.json o ~/.claude/settings.json. Cursor también aplica esos hooks de Claude Code cursor.com/docs/reference/third-party-hooks. Si ya los tienes ahí, no los registres dos veces.
Comprueba
Que deja pasar lo normal, en los dos formatos de entrada medido:
$ echo '{"command":"./gradlew test","cwd":"/repo"}' | .cursor/hooks/no-saltar-pruebas.sh; echo "código de salida: $?"
{"permission": "allow"}
código de salida: 0
$ echo '{"tool_name":"Bash","tool_input":{"command":"./gradlew test"}}' | .cursor/hooks/no-saltar-pruebas.sh; echo "código de salida: $?"
código de salida: 0
Y que bloquea: pídele al agente «corre la build saltándote las pruebas». El comando no debe ejecutarse y debes ver el mensaje del hook. Si no pasa nada, revisa el canal de salida «Hooks» de Cursor.
Lo que pasó al preparar este curso
El caso «bloquea» de este script no lo pudimos correr aquí. El hook del equipo, registrado sólo en ~/.claude/settings.json, bloqueó un comando del propio agente de Cursor que llevaba esos textos como datos de prueba medido. Eso enseña dos cosas: Cursor sí aplica los hooks de Claude Code, y el candado mira el texto del comando, no la intención. Diseña tus patrones con cuidado para que no frenen lo que no deben.
Pega
/speckit-implement Sólo las fases 1 a 3 (el producto mínimo). Escribe cada prueba primero y confirma que falla antes de programar. Al terminar cada fase, corre las pruebas y detente para que revise.
Debes ver
Las tareas T001 a T011 marcadas con [X], y pruebas que citan su requisito en el nombre simulado:
package mx.ejemplo.marcas.integracion;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
class AltaMarcaTest extends PruebaConMongo {
@Test
@DisplayName("FR-002: rechaza ' ZETA ' cuando ya existe 'Zeta'")
void rechazaNombreRepetidoSinImportarMayusculasNiEspacios() {
darDeAlta("Zeta").expectStatus().isCreated();
darDeAlta(" ZETA ")
.expectStatus().isEqualTo(409)
.expectBody().jsonPath("$.code").isEqualTo("MARCA_DUPLICADA");
}
@Test
@DisplayName("FR-001: un usuario de Compras no puede dar de alta marcas")
void soloGobiernoDeDatosDaDeAlta() {
darDeAltaComo("compras", "Zeta").expectStatus().isForbidden();
}
}
Si falla
Si se detiene a preguntar por checklists, hay casillas sin marcar en checklists/: resuélvelas o contesta que sigues a propósito.
Haz(desde la raíz del repo)
spec=specs/001-catalogo-de-marcas/spec.md
for fr in $(grep -oE "FR-[0-9]{3}" "$spec" | sort -u); do
if grep -rqE "\"$fr[^0-9]" src/test; then echo "✅ $fr tiene prueba"; else echo "❌ $fr sin prueba"; fi
done
Debes ver
Con sólo el producto mínimo, faltan pruebas medido sobre el ejemplo:
$ spec=specs/001-catalogo-de-marcas/spec.md
for fr in $(grep -oE "FR-[0-9]{3}" "$spec" | sort -u); do
if grep -rqE "\"$fr[^0-9]" src/test; then echo "✅ $fr tiene prueba"; else echo "❌ $fr sin prueba"; fi
done
✅ FR-001 tiene prueba
✅ FR-002 tiene prueba
❌ FR-003 sin prueba
❌ FR-004 sin prueba
❌ FR-005 sin prueba
❌ FR-006 sin prueba
❌ FR-007 sin prueba
Implementa las fases 4 a 6 (/speckit-implement Fases 4 a 6) y repite hasta que todo salga ✅.
Pega
/speckit-converge
Debes ver
Al final de tasks.md, una «Phase 7: Convergence» con lo que falta, cada tarea rastreable a su requisito. Converge sólo agrega: no toca spec, plan ni código medido de la skill. Ejemplo simulado:
## Phase 7: Convergence
- [ ] T018 [US3] Registrar la reactivación en el historial (FR-007): hoy aplicacion/ReactivacionDeMarca.java cambia `activa` pero no escribe en `marcas_historial`
- [ ] T019 [P] [US1] Agregar la prueba "FR-002: dos altas simultáneas de 'Zeta' dejan una sola marca" (Edge Cases)
Comprueba
# después de /speckit-implement "Sólo la fase Convergence":
./gradlew test && git add -A && git commit -m "Spec 001: implementación"
Usas: tu agente revisor-conformidad y tu skill /conformidad, que lo lanza.
Taller: tu primer agente
Etapa: antes del PR. Por qué agente y no skill: quien implementó no se revisa a sí mismo. El subagente empieza con contexto limpio, sin tu conversación ni tus suposiciones, y sólo te devuelve el veredicto cursor.com/docs/subagents.
Guárdalo en .claude/agents/revisor-conformidad.md. Lo leen Claude Code y Cursor; si sólo usas Cursor, también vale .cursor/agents/, que gana si hay dos con el mismo nombre cursor.com/docs/subagents.
---
name: revisor-conformidad
description: Revisa, sólo leyendo, si el cambio de la rama cumple su spec requisito por requisito (implementado, con prueba que cita su ID, criterio cumplido), qué se coló fuera de la spec y si alguna prueba se apagó, se aflojó o se borró. Usar antes de abrir el PR o con /conformidad. No edita nada.
tools: Read, Grep, Glob, Bash
readonly: true
---
# Revisor de conformidad
No escribiste este código: lo revisas contra su spec. Sólo lees. Bash es sólo para `git` y `rg`.
## Cómo revisas
1. Lista los requisitos de la spec: los `FR-###` de Spec Kit, o los `### Requirement:` de OpenSpec con sus escenarios.
2. Lee el diff: `git diff --stat <base>...HEAD`, `git diff <base>...HEAD` y lo que no tiene commit.
3. Por cada requisito: ¿el diff lo implementa? (cita `archivo:línea`). ¿Qué prueba lo cita en su nombre? ¿Se cumple su criterio?
4. Al revés: ¿qué cambios del diff no rastrean a ningún requisito? Repórtalos aunque sean un refactor válido.
5. Busca pruebas apagadas, aflojadas o borradas: `@Disabled`, `@Ignore`, `.skip`, aserciones borradas o comentadas, un valor concreto que pasó a `any()`.
6. Revisa que el diff no rompa una regla de `AGENTS.md`, de la constitución o de `openspec/config.yaml`.
7. Por cada firma pública que cambió, busca con `rg` quién la llama fuera del diff.
## Reglas
- Todo hallazgo lleva `archivo:línea`. Si no lo puedes citar, no lo afirmes.
- Máximo 3 bloqueantes, en orden de gravedad. No comentes estilo ni rediseñes.
- Si te falta la spec o la base, dilo y para.
## Salida
```
## Conformidad: NO LISTO | LISTO CON PENDIENTES | LISTO PARA PR
| Requisito | ¿Implementado? | Prueba | ¿Criterio cumplido? |
|---|---|---|---|
Fuera de la spec: …
Pruebas apagadas, aflojadas o borradas: …
Reglas rotas: …
### Bloqueantes (máximo 3)
1. `archivo:línea` — qué pasa, por qué importa y cómo se arregla.
```
description dice cuándo delegarle. El agente principal la lee para decidir; también lo puedes pedir por nombre.
Sólo lectura, en los dos agentes. En Claude Code, tools sin Edit ni Write. En Cursor, readonly: true: Cursor no documenta tools, y sus subagentes heredan todas las herramientas del principal cursor.com/docs/subagents.
El cuerpo es su prompt: cómo revisa, sus reglas y una salida con formato fijo y veredicto.
Taller: una skill manual
Con disable-model-invocation: true la skill sólo corre cuando escribes /conformidad: no queremos que el agente lance una revisión cara por su cuenta cursor.com/docs/skills.
---
name: conformidad
description: Lanza al subagente revisor-conformidad para revisar, sólo leyendo, si el cambio de la rama cumple su spec requisito por requisito. Usar antes de abrir el PR o cuando pregunten «¿ya cumple la spec?».
disable-model-invocation: true
---
# /conformidad
1. Ubica la spec del cambio: la ruta que te den; si no, `.specify/feature.json` (Spec Kit) o el cambio activo de `openspec list` (OpenSpec). Si hay más de una candidata, pregunta cuál.
2. Ubica la rama base: la que te den; si no, `origin/main`.
3. Lanza el subagente `revisor-conformidad` con la ruta de la spec y la base. No revises tú: quien implementó no se revisa a sí mismo.
4. Muestra el veredicto tal cual. Si sale NO LISTO, ofrece arreglarlo, pero no edites nada hasta que te lo pidan.
Pega(en un chat nuevo)
/conformidad specs/001-catalogo-de-marcas main
Debes versimulado
## Conformidad: LISTO CON PENDIENTES
Spec: specs/001-catalogo-de-marcas · Base: main · Alcance: 14 archivos, 6 de prueba
| Requisito | ¿Implementado? | Prueba | ¿Criterio cumplido? |
|---|---|---|---|
| FR-001 | sí, `web/Seguridad.java:22` | `AltaMarcaTest.java:18` | sí |
| FR-002 | sí, `dominio/Marca.java:19` | `AltaMarcaTest.java:9` | sí |
| FR-003 | sí, `web/RutasMarcas.java:41` | `DisponibilidadTest.java:12` | sí |
| … | … | … | … |
Fuera de la spec: `web/RutasMarcas.java:60` agrega GET /marcas (listado), que ningún FR pide.
Pruebas apagadas, aflojadas o borradas: ninguna
Reglas rotas: sin hallazgos
### Bloqueantes (máximo 3)
Ninguno. Pendiente: explica el listado en el PR o quítalo.
Comprueba
Que el veredicto cita archivo:línea en cada fila. Si dice NO LISTO, corrige y repite; no edites el agente para que «apruebe».
Mientras el servicio nace, los cambios siguen en Spec Kit. La regla, del curso y del kit del equipo curso de SDD, sección 4:
La spec cumplió su objetivo y llega algo nuevo: esa spec se cierra y lo nuevo va en otra (/speckit-specify, número siguiente). En el mapa de specs puede decir sustituye a NNN.
El resultado no fue el esperado: se itera la misma spec, en una sesión nueva y con el modelo más potente que tengas.
Pega(para iterar)
/speckit-specify Reescribe la spec existente @specs/001-catalogo-de-marcas/spec.md; no crees una spec nueva. Los criterios nuevos son: <…>.
Si el cambio es de fondo, borra de esa spec plan.md, tasks.md, research.md, data-model.md, quickstart.md y contracts/, y repite plan → tasks → analyze → implement. Si es menor, pide al plan que reutilice lo existente y cambie sólo lo necesario.
Haz
git push -u origin 001-catalogo-de-marcas
gh pr create --title "Spec 001: catálogo de marcas" --body-file pr.md # pr.md = qué, por qué, cómo verificar + la tabla de /conformidad
🛑 El merge lo deciden el CI en verde, el análisis de seguridad y una revisión humana. Antes, repasa la Definition of Done:
Pruebas verdes de verdad, sin saltarse ninguna.
Cada requisito con al menos una prueba que cita su ID.
Ninguna prueba apagada, aflojada o borrada, y lo que quedó fuera de la spec, explicado en el PR.
specs/README.md con la spec 001 como publicada.
Con el merge, el servicio ya vive. De aquí en adelante, cada mejora es un cambio de OpenSpec.
Misión 6
Gradúate a OpenSpec: tu primer cambio
25 minutos · explorar, proponer, aplicar, verificar y archivar
Cambias de nivel: de spec-first a spec-anchored. Ya no escribes una spec por feature: modificas la spec viva del sistema. Usas:/opsx-explore, /opsx-new + /opsx-continue, /opsx-apply, /opsx-verify y /opsx-archive. El cambio: Gobierno de Datos puede bloquear una marca, y el alta de productos de esa marca se rechaza.
Haz
git switch main && git pull && git switch -c bloquear-marcas
openspec list && openspec list --specs
¿Ya hay un cambio abierto con la misma intención? Actualízalo en vez de abrir otro. ¿Dependes de uno abierto? Ése se archiva primero regla del kit de un equipo.
Pega
/opsx-explore Quiero que una marca pueda bloquearse para que nadie dé de alta productos de esa marca. Revisa con `openspec list --specs` qué capacidades existen, dime cuáles toca, qué preguntas hay y dos o tres formas de resolverlo con sus pros y contras. No crees archivos.
Debes ver
Análisis y preguntas, sin archivos. Explore nunca escribe código, y sólo crea artefactos de un cambio si se lo confirmas medido de la skill.
Pega
/opsx-new bloquear-marcas
Y luego, una vez por artefacto (propuesta, delta, diseño y tareas), revisando cada uno antes de seguir:
/opsx-continue bloquear-marcas
Si el alcance ya está claro desde el principio, /opsx-propose hace los cuatro de un jalón; /opsx-ff crea los que falten de corrido. OpenSpec no tiene clarify: pide «lista las ambigüedades que requieran decisión de negocio» y contéstalas una por una.
Debes ver
Por debajo, la skill crea el cambio y pide su estado medido:
Al terminar, los cuatro artefactos. El delta es una capacidad nueva, así que lleva ## Purpose y ## ADDED Requirementssimulado, pasó el validador estricto:
# Spec Delta
## Purpose
Decidir qué marcas no se pueden usar al dar de alta productos, quién puede bloquearlas y qué pasa con las altas de esas marcas.
## ADDED Requirements
### Requirement: Bloquear y desbloquear una marca
El sistema SHALL permitir que sólo un usuario con rol Gobierno de Datos bloquee o desbloquee una marca, y SHALL guardar quién lo hizo y cuándo.
#### Scenario: Gobierno de Datos bloquea una marca
- **WHEN** un usuario con rol Gobierno de Datos bloquea la marca "ACME"
- **THEN** la marca queda bloqueada con su usuario y la fecha y hora del bloqueo
#### Scenario: Otro rol intenta bloquear
- **WHEN** un usuario con rol Compras intenta bloquear la marca "ACME"
- **THEN** la operación se rechaza con el código SIN_PERMISO y la marca no cambia
### Requirement: Rechazar altas de productos de marcas bloqueadas
El sistema MUST rechazar el alta de un producto cuya marca esté bloqueada, con el código MARCA_BLOQUEADA.
#### Scenario: Alta de un producto de marca bloqueada
- **WHEN** un vendedor da de alta un producto de la marca bloqueada "ACME"
- **THEN** el alta se rechaza con el código MARCA_BLOQUEADA y no se crea el producto
#### Scenario: Alta de un producto de marca no bloqueada
- **WHEN** un vendedor da de alta un producto de la marca "Zeta", que no está bloqueada
- **THEN** el alta sigue con las validaciones de siempre
/opsx-apply bloquear-marcas Empieza por el grupo 1. Por cada tarea: escribe la prueba de su escenario con el nombre del escenario, hazla pasar, márcala [x] y dime con qué comando se verifica. Detente al terminar cada grupo.
Debes ver
Una prueba por escenario, con el nombre del requisito y del escenario simulado:
package mx.ejemplo.marcas.web;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
/** Una prueba por escenario de openspec/changes/bloquear-marcas/specs/bloqueo-de-marcas/spec.md */
class BloqueoDeMarcaTest extends PruebaConMongo {
@Test
@DisplayName("Bloquear y desbloquear una marca · Gobierno de Datos bloquea una marca")
void gobiernoDeDatosBloquea() {
bloquearComo("gobierno-de-datos", "ACME").expectStatus().isOk();
assertThat(marca("ACME").bloqueada()).isTrue();
assertThat(marca("ACME").bloqueadaPor()).isEqualTo("gobierno-de-datos");
}
@Test
@DisplayName("Bloquear y desbloquear una marca · Otro rol intenta bloquear")
void otroRolNoPuedeBloquear() {
bloquearComo("compras", "ACME")
.expectStatus().isForbidden()
.expectBody().jsonPath("$.code").isEqualTo("SIN_PERMISO");
}
@Test
@DisplayName("Rechazar altas de productos de marcas bloqueadas · Alta de un producto de marca bloqueada")
void rechazaAltaDeMarcaBloqueada() {
bloquearComo("gobierno-de-datos", "ACME");
altaDeProducto("ACME")
.expectStatus().isEqualTo(422)
.expectBody().jsonPath("$.code").isEqualTo("MARCA_BLOQUEADA");
}
}
La regla anti-drift. Si a mitad de camino descubres que la spec o el diseño están mal, no edites el código por fuera: corrige el artefacto y deja que /opsx-continue regenere lo que depende de él. Retocar el código fuera del flujo es la forma más común de que spec y código se separen regla del kit de un equipo.
Pega
/opsx-verify bloquear-marcas
Debes ver
Un informe en tres ejes: completitud (tareas y cobertura de la spec), corrección (requisitos y escenarios) y coherencia (apego al diseño). Cada hallazgo es CRITICAL, WARNING o SUGGESTION medido de la skill. Un CRITICAL se arregla antes de archivar. En un WARNING decides tú: o el código se ajusta al diseño, o el diseño se actualiza a la decisión real.
$ openspec list --specs
Specs:
bloqueo-de-marcas requirements 2
Ahora existe openspec/specs/bloqueo-de-marcas/spec.md, generada por OpenSpec. Recórrela en el explorador, etapa 4. Después, /conformidad y el PR, como en la misión 5.
Misión 7
Varios cambios en paralelo, con worktrees
25 minutos · qué no se paraleliza, specs que chocan e integración por orden de riesgo
Usas: git worktrees, un agente por worktree y tu agente revision-cruzada. El caso: el dev B (o un segundo agente) hace motivo-al-bloquear, en el que el bloqueo exige un motivo, mientras el dev A hace desbloqueo-temporal. Los dos tocan el mismo requisito.
La base se acuerda junta y en secuencia: la constitución (o config.yaml), el dominio básico, el esquema de datos y las convenciones. Si dos personas la escriben a la vez, pueden fijar principios contradictorios que después no se consolidan curso de SDD, sección 6. En este laboratorio ya quedó en la misión 1, así que puedes seguir.
Un worktree es otra carpeta del mismo repo con su propia rama. Así dos agentes trabajan a la vez sin pisarse archivos.
$ git worktree add ../lab-specs-motivo -b motivo-al-bloquear
Preparing worktree (new branch 'motivo-al-bloquear')
HEAD is now at <commit> Base del repo
$ git worktree add ../lab-specs-desbloqueo -b desbloqueo-temporal
Preparing worktree (new branch 'desbloqueo-temporal')
HEAD is now at <commit> Base del repo
$ git worktree list
~/lab-specs <commit> [main]
~/lab-specs-desbloqueo <commit> [desbloqueo-temporal]
~/lab-specs-motivo <commit> [motivo-al-bloquear]
Abre cada carpeta en su propia ventana de Cursor. En cada una, su dev o su agente corre /opsx-propose de su cambio. Las tareas y la implementación también van en paralelo, cada una en su worktree. Haz commit en cada worktree antes de integrar.
Taller: un agente que lee otras ramas
Etapa: antes de planear o aplicar, sólo si hay specs en paralelo. Por qué agente: lee mucho (varias ramas y specs) y conviene que no llene tu contexto. Además debe ser de sólo lectura: lee con git show, sin cambiar de rama.
---
name: revision-cruzada
description: Compara, sólo leyendo, las specs que se escriben en paralelo en distintas ramas y encuentra conceptos definidos dos veces, reglas que se contradicen y escrituras sobre los mismos datos; propone una spec dueña por concepto. Usar antes de planear o de aplicar cuando hay otras specs en curso en el repo.
tools: Read, Grep, Glob, Bash
readonly: true
---
# Revisión cruzada
Sólo lees: no cambias de rama, no entras a otros worktrees y no editas specs.
1. Ramas: las que te den; si no, las filas `en curso` de `specs/README.md`, más `git branch -r`.
2. Lee cada spec desde su rama sin hacer checkout: `git show <rama>:<ruta>`. Si una spec no tiene commit, di de qué rama falta y para.
3. Busca:
- conceptos definidos en más de una spec, aunque usen otras palabras (estados, permisos, umbrales);
- reglas que una spec fija y otra contradice o reinventa;
- escrituras sobre las mismas colecciones, tópicos o estados;
- dependencias: una spec que necesita algo que otra todavía no publica.
4. Cita cada choque textual, con rama y archivo. Propón la spec dueña de cada concepto; no resuelvas tú.
## Salida
```
## Revisión cruzada: SIN CHOQUES | CHOQUES MENORES | CHOQUES A RESOLVER
| ID | Severidad | Specs | Qué chocan | Cita (rama:archivo) | Dueño propuesto |
|---|---|---|---|---|---|
Orden de implementación que sale de las dependencias: …
```
Pega
Usa el subagente revision-cruzada para comparar las ramas motivo-al-bloquear y desbloqueo-temporal.
Debes versimulado
## Revisión cruzada: CHOQUES A RESOLVER
| ID | Severidad | Specs | Qué chocan | Cita (rama:archivo) | Dueño propuesto |
|---|---|---|---|---|---|
| C-1 | alta | motivo-al-bloquear, desbloqueo-temporal | Las dos modifican «Bloquear y desbloquear una marca» con textos distintos | motivo-al-bloquear:openspec/changes/motivo-al-bloquear/specs/bloqueo-de-marcas/spec.md «…y, al bloquear, el motivo…» / desbloqueo-temporal:…/spec.md «…o la desbloquee hasta una fecha…» | bloqueo-de-marcas (spec viva) |
Orden de implementación: primero motivo-al-bloquear (se archiva); después desbloqueo-temporal rehace su MODIFIED sobre la spec viva ya actualizada.
Haz
Anota en specs/README.md, sección «Conceptos con dueño», que «marca bloqueada» la define la capacidad bloqueo-de-marcas. Nadie edita la spec de otro worktree: cada dev ajusta la suya en su rama, con /opsx-continue.
Reto: ¿qué está mal en este delta del dev A?
## ADDED Requirements
### Requirement: Bloquear y desbloquear una marca
El sistema SHALL permitir bloquear una marca o desbloquearla hasta una fecha.
Respuesta: el requisito ya existe en la spec viva, así que debe ir en ## MODIFIED Requirements, copiando el bloque completo con todos sus escenarios. Un ADDED sobre algo que ya existe deja dos specs describiendo lo mismo: drift desde el primer día. Además, le falta al menos un escenario.
Debes ver
El MODIFIED del dev B copia el bloque entero (texto y tres escenarios) y lo edita simulado, pasó el validador estricto:
# Spec Delta
## MODIFIED Requirements
### Requirement: Bloquear y desbloquear una marca
El sistema SHALL permitir que sólo un usuario con rol Gobierno de Datos bloquee o desbloquee una marca, y SHALL guardar quién lo hizo, cuándo y, al bloquear, el motivo (de 10 a 300 caracteres).
#### Scenario: Gobierno de Datos bloquea una marca
- **WHEN** un usuario con rol Gobierno de Datos bloquea la marca "ACME" con el motivo "Imitaciones reportadas por Legal"
- **THEN** la marca queda bloqueada con su usuario, la fecha y hora del bloqueo y el motivo
#### Scenario: Bloqueo sin motivo
- **WHEN** un usuario con rol Gobierno de Datos intenta bloquear la marca "ACME" sin motivo
- **THEN** la operación se rechaza con el código MOTIVO_REQUERIDO y la marca no cambia
#### Scenario: Otro rol intenta bloquear
- **WHEN** un usuario con rol Compras intenta bloquear la marca "ACME"
- **THEN** la operación se rechaza con el código SIN_PERMISO y la marca no cambia
Compruebamedido
$ openspec show motivo-al-bloquear --diff
# Proposal
## Why
Auditoría pidió saber por qué se bloqueó cada marca. Hoy el bloqueo guarda quién y cuándo, pero no el motivo.
## What Changes
- Bloquear una marca exige un motivo de 10 a 300 caracteres.
- Desbloquear no pide motivo.
## Capabilities
### New Capabilities
- (ninguna)
### Modified Capabilities
- `bloqueo-de-marcas`: el requisito "Bloquear y desbloquear una marca" exige el motivo.
## Impact
- **API:** `PATCH /marcas/{id}/bloqueo` recibe `motivo`; sin él responde `MOTIVO_REQUERIDO`.
- **Datos:** campo `motivoBloqueo` en la marca.
Specifications Changed (diffs)
bloqueo-de-marcas
MODIFIED: Bloquear y desbloquear una marca
@@ -1,10 +1,14 @@
### Requirement: Bloquear y desbloquear una marca
-El sistema SHALL permitir que sólo un usuario con rol Gobierno de Datos bloquee o desbloquee una marca, y SHALL guardar quién lo hizo y cuándo.
+El sistema SHALL permitir que sólo un usuario con rol Gobierno de Datos bloquee o desbloquee una marca, y SHALL guardar quién lo hizo, cuándo y, al bloquear, el motivo (de 10 a 300 caracteres).
#### Scenario: Gobierno de Datos bloquea una marca
-- **WHEN** un usuario con rol Gobierno de Datos bloquea la marca "ACME"
-- **THEN** la marca queda bloqueada con su usuario y la fecha y hora del bloqueo
+- **WHEN** un usuario con rol Gobierno de Datos bloquea la marca "ACME" con el motivo "Imitaciones reportadas por Legal"
+- **THEN** la marca queda bloqueada con su usuario, la fecha y hora del bloqueo y el motivo
+#### Scenario: Bloqueo sin motivo
+- **WHEN** un usuario con rol Gobierno de Datos intenta bloquear la marca "ACME" sin motivo
+- **THEN** la operación se rechaza con el código MOTIVO_REQUERIDO y la marca no cambia
+
#### Scenario: Otro rol intenta bloquear
- **WHEN** un usuario con rol Compras intenta bloquear la marca "ACME"
- **THEN** la operación se rechaza con el código SIN_PERMISO y la marca no cambia
Si falla
Si tu MODIFIED omite escenarios, la versión 1.14.3 lo detiene en la validación y al archivar, sin tocar archivos medido:
$ openspec validate texto-de-bloqueo --strict
Change 'texto-de-bloqueo' has issues
✗ [ERROR] bloqueo-de-marcas/spec.md: MODIFIED "Bloquear y desbloquear una marca" omits scenario(s) the current spec still has: "Bloqueo sin motivo", "Otro rol intenta bloquear". The modified block has 1 scenario; the current spec has 3 scenarios. It adds none. Copy the omitted scenarios into the MODIFIED block (a MODIFIED requirement replaces the whole block, so archive refuses to drop them).
Next steps:
- Ensure change has deltas in specs/: use headers ## ADDED/MODIFIED/REMOVED/RENAMED Requirements
- Each requirement MUST include at least one #### Scenario: block
- Debug parsed deltas: openspec show texto-de-bloqueo --json --deltas-only
$ echo $?
1
No se integra por orden de llegada: primero lo que menos puede romper (algo de sólo lectura, como un reporte) y al final lo que escribe en la base de datos curso de SDD, sección 6. Aquí, motivo-al-bloquear primero, porque desbloqueo-temporal depende de él.
Pega(en un chat nuevo, en la carpeta principal, en main)
Estás en main. Integra la rama motivo-al-bloquear, que tiene su propio worktree: haz el merge. Si da conflictos, analiza cada uno y propón la solución completa antes de aplicarla. Si entra limpio, corre todas las pruebas; si fallan, analiza por qué y propón cómo resolverlo. No borres worktrees ni ramas todavía.
Repite con la siguiente rama. Para resolver conflictos conviene el modelo más potente que tengas curso de SDD, sección 6. Si choca .specify/feature.json, el puntero de Spec Kit a la spec activa, quédate con la versión de main.
Si el squad cerró varios cambios que tocan la misma spec, usa /opsx-bulk-archive: detecta los conflictos y los fusiona en orden de creación, pidiendo confirmación regla del kit de un equipo.
Usas: tu agente auditor-drift. Aunque cada cambio pase por verify, el drift entra por fuera: un hotfix directo al código, un cambio que alguien retocó sin OpenSpec, dos specs que describen lo mismo.
Haz
En el laboratorio, edita a mano el código del bloqueo para que Compras también pueda desbloquear, sin tocar ninguna spec, y haz commit con el mensaje «hotfix desbloqueo».
Taller: un agente para tareas largas
Por qué agente: recorre todas las specs vivas, el código y el git reciente; eso llenaría tu chat. En Cursor puedes agregarle is_background: true para que corra en segundo plano y no te bloquee cursor.com/docs/subagents.
---
name: auditor-drift
description: Audita, sólo leyendo, si las specs vivas de openspec/specs/ y el código siguen diciendo lo mismo, en las dos direcciones, y entrega un informe de drift con evidencia. Usar cada semana o antes de cerrar un sprint, en una sesión nueva.
tools: Read, Grep, Glob, Bash
readonly: true
---
# Auditor de drift
Sólo auditas e informas: no editas specs, código ni pruebas, y no creas cambios de OpenSpec.
1. **Código → spec:** por cada requisito y escenario de `openspec/specs/`, ¿el código lo sigue haciendo así? Fíjate en estados, validaciones, límites y mensajes.
2. **Spec → código:** busca comportamiento observable (endpoints, validaciones, mensajes publicados) que ninguna spec menciona o que la contradice. Empieza por lo que cambió en git en los últimos 30 días.
3. **Además:** escenarios sin prueba, cambios activos ya implementados y sin archivar, y dos capacidades que describen lo mismo.
## Reglas
- Cada hallazgo lleva evidencia: `archivo:línea` o el commit.
- Ante la duda entre «cumple» y «drift», márcalo como drift de severidad baja y explica la duda.
- Severidad alta si toca dinero, contratos o datos que consumen otros sistemas; media si lo nota el usuario; baja si es interno.
## Salida
```
## Drift: SINCRONIZADO | DRIFT LEVE | DRIFT GRAVE
| ID | Tipo | Severidad | Capacidad y requisito | Evidencia | Qué pasa |
|---|---|---|---|---|---|
Por hallazgo, una salida que decide una persona:
(a) regularizar la spec · (b) corregir el código · (c) escalar a negocio
```
Pega(en un chat nuevo)
Usa el subagente auditor-drift con los últimos 7 días de git.
Debes versimulado
## Drift: DRIFT GRAVE
| ID | Tipo | Severidad | Capacidad y requisito | Evidencia | Qué pasa |
|---|---|---|---|---|---|
| D-1 | Código → spec | alta | bloqueo-de-marcas · «Bloquear y desbloquear una marca» | web/BloqueoHandler.java:41 (commit «hotfix desbloqueo») | El código deja desbloquear a Compras; la spec dice que sólo Gobierno de Datos |
| D-2 | Pruebas | media | bloqueo-de-marcas · escenario «Bloqueo sin motivo» | BloqueoDeMarcaTest.java | El escenario no tiene prueba |
Por hallazgo, una salida que decide una persona:
D-1: (b) corregir el código, porque el hotfix contradice una regla acordada.
D-2: agregar la prueba.
Haz
(a) Regularizar la spec, si lo que hace el código es lo deseado: /opsx-propose "regulariza: Compras puede desbloquear". Como el comportamiento ya existe, sólo faltan las pruebas.
(b) Corregir el código, si la spec es lo deseado: un cambio normal (misión 6).
(c) Escalar a negocio, si no está claro cuál de los dos es el correcto.
El primero falla si un delta o una spec viva está mal formada; el segundo, si alguien archivó con tareas pendientes. Los comandos están medidos en local; el pipeline no lo corrimos. Ojo: openspec archive -y archiva aunque falten tareas, sólo avisa medido:
El caso: un módulo viejo de facturación cobra la baja a mitad de mes por dos caminos distintos, y nadie sabe cuál es el bueno. Primero se observa, luego se clasifica y se pregunta, después se congela con pruebas y al final se escribe la spec de lo que hay. Cambiar el comportamiento es otro trabajo: la misión 10curso de SDD, sección 7, y kit de un equipo.
Haz
git tag foto-base # el punto contra el que se compara todo
Pega
Arranca la aplicación sin modificar ningún archivo; sólo instala las dependencias que hagan falta. Después dime cómo recorrerla a mano: pantallas, endpoints y procesos programados.
Recórrela tú como usuario. El README se lee con desconfianza: dice lo que alguien creyó, no lo que hay. Luego, la constitución de la fase, que aquí son prohibiciones, no aspiraciones:
Pega
/speckit-constitution Fase: documentar y proteger, no mejorar. Principios:
1. El comportamiento actual es sagrado: ningún cambio observable sin una decisión de negocio por escrito, aunque parezca un error.
2. Toda afirmación lleva evidencia (archivo y líneas, dato real o testimonio con nombre y fecha); lo que no la tiene es una pregunta.
3. Los hallazgos no se corrigen: se registran.
4. Cero dependencias nuevas y cero refactors; las pruebas usan el framework que ya existe.
Taller: escríbelo tú
Diseña .claude/agents/investigador-legacy.md: lee código sin tocarlo, cita archivo:línea en cada afirmación y marca como PENDIENTE lo que tenga un solo testigo. Pista: readonly: true, tools sin Edit ni Write, y una salida con cuatro documentos.
Ver una solución
---
name: investigador-legacy
description: Investiga, sólo leyendo, código legacy sin documentar y reconstruye qué hace hoy, con evidencia archivo:línea en cada afirmación. Usar al empezar un reverse-spec o cuando nadie sabe qué hace un módulo.
tools: Read, Grep, Glob, Bash
readonly: true
---
# Investigador de legacy
No tocas nada: lees, citas y registras. El README miente un poco; el código es la fuente, pero poco confiable.
Entrega cuatro documentos en specs/000-reconocimiento/:
1. mapa-sistema.md: cada módulo con su responsabilidad en una frase de negocio, dependencias y criticidad. Cierra con las zonas oscuras.
2. flujo-<entidad>.md: el ciclo de vida de la entidad principal por TODOS los caminos que la cambian. Señala dónde dos caminos hacen lo mismo con código distinto.
3. registro-riesgos.md: lo que puede romperse hoy, de mayor a menor, todavía sin soluciones.
4. memoria-historica.md: incidentes, decisiones con nombre y avisos de "no tocar" que dejan los comentarios y el git.
Reglas: cada afirmación con archivo:línea; con un solo testigo, PENDIENTE y la pregunta exacta que lo destrabaría.
Pega
Usa el subagente investigador-legacy sobre el módulo de facturación.
Debes ver
Los cuatro documentos, y en flujo-baja.md el hallazgo clave: dos cálculos de la misma baja simulado:
BigDecimal cargoPorDias(BigDecimal mensual, int diasUsados) { // camino A
return mensual.divide(BigDecimal.valueOf(30), 2, HALF_UP).multiply(BigDecimal.valueOf(diasUsados));
}
BigDecimal cargoProporcional(BigDecimal mensual, int diasUsados, int diasDelMes) { // camino B
return mensual.multiply(BigDecimal.valueOf(diasUsados)).divide(BigDecimal.valueOf(diasDelMes), 2, HALF_UP);
}
Con una mensualidad de 60.00 y una baja del 16 al 30 de julio (15 días de un mes de 31), el camino A cobra 30.00 y el B, 29.03calculado.
Cada comportamiento se clasifica como INTENCIONAL, ACCIDENTAL o DUDOSO. Un concepto implementado dos veces con resultados distintos es una contradicción: se documenta con un ejemplo donde divergen, y no se decide cuál es el bueno. Nada se da por confirmado con un solo testigo: hacen falta 2 de 3 entre código, datos y negocio.
Debes versimulado
## A-01 · Dos cálculos distintos del cargo por baja a mitad de mes
- Testigos: CÓDIGO Facturacion.java:41 y :58 · DATOS (pendiente: dos facturas reales de julio) · NEGOCIO (pendiente)
- Clasificación: PENDIENTE
- Depende de esto: las facturas ya emitidas con cualquiera de los dos cálculos
- Tratamiento: especificar tal cual hasta que negocio decida; la corrección no es retroactiva
- Pregunta: "Hoy una baja del 16 al 30 de julio se cobra de dos formas: 30.00 o 29.03. ¿Cuál es la correcta? (A / B)"
🛑 La pregunta se puede contestar sin ambigüedad, trae un ejemplo con números y no sugiere la respuesta. La IA no la contesta por el negocio: si no hay con quién hablar, el paso queda bloqueado.
Pega
Escribe pruebas de caracterización del cargo por baja: el valor esperado es el que produce el código actual, aunque parezca un error. Si una prueba falla, corrige la prueba, nunca el código. Nombre de la prueba de la anomalía: "CONGELA comportamiento actual: A-01 · …". Usa el framework de pruebas que ya existe.
Debes versimulado
@Test
@DisplayName("CONGELA comportamiento actual: A-01 · baja del 16 al 30 de julio: 30.00 por días y 29.03 proporcional")
void congelaLosDosCalculosDeLaBaja() {
assertThat(facturacion.cargoPorDias(new BigDecimal("60.00"), 15)).isEqualByComparingTo("30.00");
assertThat(facturacion.cargoProporcional(new BigDecimal("60.00"), 15, 31)).isEqualByComparingTo("29.03");
}
Súmale un golden master del flujo principal: de 8 a 12 casos fijos cuya salida completa se guarda y se compara campo a campo en cada corrida. Sólo se regenera con una decisión de negocio documentada.
Sólo con los tres candados: la partición en specs aprobada, cero PENDIENTES en el registro y la red de caracterización en verde.
Pega
/speckit-specify Spec de ingeniería inversa: documenta el comportamiento EXISTENTE del cargo por baja. No es una feature nueva: es la especificación de lo que el sistema ya hace, para que sirva de contrato. Las anomalías no se corrigen ni se omiten: se especifican tal como funcionan hoy, con su ID del registro (A-01). Cada criterio de aceptación cita la prueba de caracterización que lo verifica, y cada decisión de negocio cita el acta.
Si hay que presentarlo a quien decide, el entregable es un specs/SPEC-PACK.mdcurso de SDD, sección 7:
Pega
Arma specs/SPEC-PACK.md, la entrada al paquete: un resumen ejecutivo sin tecnicismos (qué se hizo, qué se encontró con ejemplos en dinero, qué protección se instaló y qué decisiones quedan pendientes), los riesgos priorizados, un índice comentado de los documentos y qué quedó fuera de la red de pruebas.
🛑 Y la decisión, sólo con los tres candados cerrados: las specs aprobadas, cero PENDIENTES y la red en verde. Hay tres opciones: documentarlo y dejarlo vivo, modernizarlo (misión 10) o marcarlo obsoleto. Decide quien tiene la autoridad, no el agente.
Misión 10
Moderniza por módulos (strangler fig)
30 minutos · cambiar la implementación sin que nadie lo note
La idea: modernizar no es mejorar el código. Es cambiar la implementación por módulos, incluso con otra tecnología, sin que cambie el comportamiento: el éxito es que nadie lo note. Las correcciones aprobadas llegan después, como specs delta curso de SDD, sección 8, y kit de un equipo.
Pega
/speckit-constitution Enmienda la constitución: termina la fase de documentación y empieza la de modernización. Principios:
1. El comportamiento es sagrado por defecto: sólo cambia con una decisión registrada en registro-de-anomalias.md, que cite quién la tomó y cuándo.
2. Las pruebas de caracterización son el árbitro: un test en rojo sin decisión que lo ampare se resuelve revirtiendo el código, no ajustando el test.
3. Estrangular antes que reescribir: un módulo a la vez, cada uno con su spec, su extracción y su prueba de equivalencia.
4. Dependencias nuevas sólo con justificación en la spec y un ADR aprobado por una persona.
5. Cero retroactividad: lo ya emitido no se toca.
Comprueba
Que la constitución tiene versión nueva y fecha de enmienda, y que sigue diciendo que el comportamiento no cambia sin una decisión.
Pega
Compara los módulos candidatos a modernizar con tres criterios, en este orden: valor (qué cambios o decisiones pendientes bloquea), red (cuántas pruebas de caracterización lo cubren; sin red no se estrangula) y acoplamiento (cuántos consumidores tiene y si toca base de datos, red o reloj). Deja en specs/000-reconocimiento/consumidores-<módulo>.md la lista completa de quién lo usa, con archivo:línea. No elijas tú: recomienda.
🛑 Decides tú o el arquitecto, con la recomendación delante. Si ningún candidato tiene red suficiente, vuelve a la misión 9 y amplíala primero.
Pega
/speckit-specify Spec de sustitución del módulo de facturación. Las specs del comportamiento actual son el contrato inmutable. Nueva implementación con las mismas funciones y firmas; cero cambios de comportamiento, anomalías incluidas. Criterios de aceptación: (a) la suite de caracterización completa pasa contra el módulo nuevo; (b) el golden master pasa sin regenerarse; (c) una prueba comparativa corre el módulo viejo y el nuevo sobre muchos casos con semilla fija y exige igualdad campo a campo. La entrada vieja queda como fachada que delega en el nuevo; los consumidores no se tocan. Fuera de alcance: los consumidores, las correcciones de anomalías y cualquier otro módulo.
Después, el ciclo de siempre: clarify, plan, tasks, analyze e implement (misiones 2 a 4). Si el plan propone tocar consumidores o corregir algo «de paso», devuélvelo: está fuera de alcance.
Haz
Corre los tres anillos: la suite completa, el golden master sin regenerar y la prueba comparativa. Lee la salida real.
🛑 Los tres en verde antes de seguir. Si un anillo falla, se corrige el módulo nuevo, nunca la prueba ni el master. Si va a producción con tráfico real, vienen después la paridad en QA, el feature flag y el plan de rollback kit de un equipo. Luego, de vuelta a la tarea 2 con el siguiente módulo.
Con el módulo ya modernizado y la decisión del negocio en mano (D-01: «el correcto es el proporcional»):
Pega
/speckit-specify Spec DELTA sobre la spec del cargo por baja: ejecuta la decisión D-01 y cierra la anomalía A-01. Di qué requisitos revoca y cuáles conserva; el comportamiento nuevo con un ejemplo antes y después; cero retroactividad (aplica desde el despliegue). Fuera de alcance: las otras anomalías, cada una en su delta. Criterio: la prueba "CONGELA comportamiento actual: A-01" se sustituye por la del comportamiento nuevo, citando A-01 y D-01.
Si el negocio todavía no ha decidido, no hay delta: la anomalía sigue congelada.
Una funcionalidad nueva se especifica desde la arquitectura que ya hay, no desde la que te gustaría tener. Meter otro stack aparte deja dos arquitecturas y el doble de lugares donde fallar: un segundo legacy. Si la arquitectura actual no la soporta, primero se moderniza el módulo que hace falta (tareas 2 a 4) curso de SDD, sección 8.
Comprueba
Que el plan no mete tecnología que el repo no usa, salvo con un ADR aprobado. Cuando termine la modernización, enmienda otra vez la constitución para dejarla como la de un servicio normal.
Taller: tu kit de skills, agentes y hooks
Así queda tu kit al terminar el curso, misión por misión. Todo es simulado salvo donde se indica.
El kit mínimo, por etapa
Pieza
Tipo
Etapa
Cuándo corre
Escribe
AGENTS.md, constitución, config.yaml
Reglas
Todas
Siempre
—
revisar-spec
Skill
Especificar → planear
Cuando pides revisar una spec
No
no-saltar-pruebas
Hook
Implementar
Antes de cada comando de shell
—
conformidad
Skill manual
Antes del PR
Sólo con /conformidad
No (lanza al agente)
revisor-conformidad
Agente
Antes del PR
Lo lanza /conformidad
No
revision-cruzada
Agente
Antes de planear o aplicar
Si hay specs en paralelo
No
auditor-drift
Agente
Mantenimiento
Cada semana, en sesión nueva o en segundo plano
No
investigador-legacy
Agente
Legacy
Al empezar un reverse-spec
Sólo sus documentos de reconocimiento
Fíjate en el patrón: los agentes revisan y no escriben código, y las skills hacen trabajo corto dentro de tu conversación. Lo que no puede fallar va en un hook.
Plantillas para copiar
---
name: <nombre-en-minusculas> # igual a la carpeta; 64 caracteres como máximo
description: <Qué hace, en tercera persona>. Usar cuando <frases con que la pediría alguien del equipo>.
disable-model-invocation: true # quítalo si quieres que el agente la use por su cuenta
---
# <Título>
<Una línea: qué haces y qué NO haces (por ejemplo, "sólo lees").>
1. <Paso concreto, con el comando o el archivo exacto.>
2. <Paso.>
3. <Qué entregas y con qué formato.>
Si falta algo para decidir, dilo y para; no lo supongas.
En Cursor, el cuerpo conviene que quede por debajo de unos 5 000 tokens, y description en 1 024 caracteres o menos cursor.com.
---
name: <nombre-en-minusculas>
description: <Qué revisa o investiga y cuándo delegarle>. Usar cuando <situación>.
tools: Read, Grep, Glob, Bash # Claude Code: sin Edit ni Write = no edita
readonly: true # Cursor: sólo lectura
# model: inherit # Cursor: el modelo del agente principal (por defecto)
# is_background: true # Cursor: corre en segundo plano
---
# <Rol>
No hiciste este trabajo: lo revisas. Sólo lees.
## Cómo trabajas
1. <Qué lee primero.>
2. <Qué compara.>
## Reglas
- Todo hallazgo lleva archivo:línea; si no lo puedes citar, no lo afirmes.
- Máximo 3 bloqueantes. Si te falta algo, dilo y para.
## Salida (tal cual)
## <Veredicto>: <OPCIÓN 1> | <OPCIÓN 2> | <OPCIÓN 3>
| … | … |
El subagente empieza con contexto limpio, así que el agente principal debe pasarle en el prompt lo que necesita: la ruta de la spec, la rama base o los días a revisar cursor.com/docs/subagents.
Cursor cursor.com/docs: skills, subagents, hooks y third-party-hooks. Rutas de skills y prompts de Claude, Codex y Copilot medidas con lo que instalan Spec Kit y OpenSpec. Lo de Copilot sin hooks kit de un equipo.
No instales de más. Como Cursor también lee .claude/, .agents/ y .codex/, si instalas las mismas skills para dos agentes es probable que en Cursor las veas dos veces inferido de la documentación. Con agentes repetidos, gana el de .cursor/agents/cursor.com/docs/subagents.
Buenas prácticas que se notan
Un propósito por pieza. Si la description necesita «y también…», son dos skills.
La description decide todo: qué hace y cuándo usarla, en tercera persona, con las frases que usaría alguien del equipo.
Quien revisa no escribe: agentes de revisión siempre con readonly: true y tools sin Edit ni Write.
Salida con formato fijo y veredicto (LISTO, NO LISTO…): así se compara de una corrida a otra y se pega en el PR.
Evidencia o nada: cada hallazgo con archivo:línea; lo que no se puede citar no se afirma.
Máximo tres bloqueantes. Si todo es bloqueante, nada lo es.
Fail-fast: si falta un dato, la pieza para y lo pide. Nunca lo adivina.
Prueba cada pieza con un caso que debe pasar y otro que no, antes de dársela al equipo.
Antipatrones
Antipatrón
Qué pasa
En su lugar
Un agente para algo simple («genera el changelog»)
Gastas un contexto entero en una tarea de una línea
Una skill
Un agente revisor que puede editar
«Arregla» para aprobar, y la revisión deja de ser independiente
readonly: true y tools sin Edit ni Write
Una regla crítica sólo en AGENTS.md
El agente la olvida en un chat largo
Un hook
Una description vaga («ayuda con specs»)
El agente nunca la carga, o la carga siempre
Qué hace y cuándo, con frases concretas
Una skill gigante que hace todo el flujo
Cara en tokens y difícil de corregir
Una skill por etapa
Un hook con un patrón demasiado amplio
Bloquea comandos legítimos y el equipo lo apaga
Patrones precisos, probados con casos que pasan y casos que no
Ejercicio final: diseña el kit de tu equipo
El escenario: seis devs, tres servicios en producción y uno nuevo. Quieren specs en español, que nadie se salte pruebas, una revisión antes de cada PR, una auditoría semanal y entender un módulo viejo antes de reemplazarlo. Usan Cursor y Claude Code.
Tu turno: decide qué piezas, de qué tipo, en qué etapa y dónde guardarlas.
Ver una solución
Reglas:AGENTS.md con el stack y los no negociables, más CLAUDE.md con @AGENTS.md. openspec/config.yaml en los tres servicios vivos, con --language es y las rules del equipo. Constitución sólo en el servicio nuevo.
Hookno-saltar-pruebas en .claude/settings.json. Así lo aplican Claude Code y Cursor sin registrarlo dos veces. Además, la suite completa en CI.
Skills en .claude/skills/, que leen los dos: revisar-spec (automática) y conformidad (manual).
Agentes en .claude/agents/, todos de sólo lectura: revisor-conformidad, revision-cruzada (son seis devs: habrá specs en paralelo), auditor-drift e investigador-legacy.
Flujos: Spec Kit para el servicio nuevo; OpenSpec para los vivos. El módulo viejo pasa por reverse-spec y, si se moderniza, por strangler fig.
CI:openspec validate --all --strict y --archived.
Temas avanzados: dónde se practica cada uno
Cada tema avanzado del curso de SDD que sigue el equipo (secciones 4 a 8), con la misión y la tarea donde lo practicas aquí. Los fundamentos (secciones 2 y 3: instalación, constitución, una buena spec, clarify, plan, tasks, analyze, implement, iterar y checklists) están en la ruta exprés y en las misiones 0 a 5.
Sección del curso
Tema
Dónde se practica
4 · Flujo profesional con git
Git en SDD y el ciclo profesional: una rama por spec, commit por fase, PR
Lo que no se practica aquí: modelos locales, entorno gráfico y los modos de aprobación automática de cada agente, que dependen de tu herramienta. Spec-as-source tampoco: sólo se explica.
Biblioteca de prompts
Cambia lo que va entre < y >. Están con los nombres de Cursor; en Claude Code, OpenSpec usa /opsx:…, y en Codex, Spec Kit usa $speckit-….
Ningún prompt coincide con la búsqueda.
Especificar desde notas de un tallerSpec Kit · specify
Cuándo: ya hubo sesiones con negocio y no quieres que la IA invente.
/speckit-specify <nombre>. Fuente única: estas notas del taller (<fecha>): <pegar notas o ruta>.
Cada FR termina con su origen entre paréntesis. Lo que las notas no decidan va como [NEEDS CLARIFICATION]; no lo completes con supuestos. Si dos notas se contradicen, escribe la contradicción y no elijas. Al final agrega "## Trazabilidad" con la tabla | FR | Origen | Evidencia |.
Reescribir una spec que ya existeSpec Kit · specify
Cuándo: el resultado no fue el esperado y hay que iterar la misma spec (mientras el servicio nace).
/speckit-specify Reescribe la spec existente @specs/<NNN-nombre>/spec.md; no crees una spec nueva. Los criterios nuevos son: <…>.
Si el cambio es de fondo, borra de esa spec plan, tareas, research, data-model, quickstart y contracts, y repite plan → tasks → analyze → implement.
Implementar por fasesSpec Kit · implement
/speckit-implement Sólo la fase <N>. Por cada tarea: escribe la prueba, confirma que falla, programa, confirma que pasa y marca [X]. Al terminar la fase, corre toda la suite y detente para que revise.
Proponer un comportamiento nuevoOpenSpec · propose
/opsx-propose <nombre-en-kebab>: <qué y por qué en tres líneas>. Fuera de alcance: <…>.
Un comportamiento por requisito, cada uno con un escenario feliz y uno de error. design.md sólo si hay decisiones técnicas. Cada tarea dice cómo se verifica.
Cambiar un requisito que ya existeOpenSpec · propose
/opsx-propose <nombre>: cambia el requisito "<título exacto>" de la capacidad <ruta en openspec/specs> para que <…>. Usa MODIFIED copiando primero el bloque completo actual (texto y todos sus escenarios) y luego edítalo.
Listar ambigüedades (OpenSpec no tiene clarify)OpenSpec · propose
Lista las ambigüedades de la propuesta <cambio> que requieran decisión de negocio. Pregúntamelas una por una y registra cada respuesta en proposal.md con su fecha. Lo que decide otra persona queda como duda; no lo adivines.
Corregir un artefacto a mitad de caminoOpenSpec · continue
En el cambio <cambio>, el delta dice <…> pero lo correcto es <…>. Corrige el artefacto y regenera con /opsx-continue lo que dependa de él. No edites el código por fuera.
Regularizar un driftOpenSpec · propose
/opsx-propose regulariza-<tema>: el código ya hace <…> (evidencia: <archivo:línea>) y es lo deseado. Escribe el delta para que la spec viva lo describa. No implementes nada salvo las pruebas que falten.
Revisión de conformidadAgente
/conformidad <ruta de la spec o del cambio> <rama base>
Sin la skill: «Usa el subagente revisor-conformidad con la spec <ruta> y la base <rama>.»
Revisión cruzada de specs en paraleloAgente
Usa el subagente revision-cruzada para comparar las ramas <rama-1> y <rama-2>. Si no te doy ramas, toma las filas "en curso" de specs/README.md.
Auditoría de drift semanalAgente
Usa el subagente auditor-drift con los últimos <N> días de git. No edites nada; dame el informe y, por hallazgo, la salida que recomiendas.
Integrar una rama por orden de riesgoParalelo
Cuándo: varios cambios hechos en worktrees; se integra primero lo que menos puede romper.
Estás en main. Integra la rama <rama>, que tiene su propio worktree: haz el merge. Si da conflictos, analiza cada uno y propón la solución completa antes de aplicarla. Si entra limpio, corre todas las pruebas; si fallan, analiza por qué y propón cómo resolverlo. No borres worktrees ni ramas todavía.
Limpiar al terminar de integrarParalelo
Ya integré las ramas <ramas>. Detén lo que esté corriendo en sus worktrees, borra esos worktrees y sus ramas, cierra sus specs y marca cada una como publicada en specs/README.md. Muéstrame git worktree list y git status al final.
Requisitos sin pruebaRevisión
Lista los requisitos de <spec> (FR-### o "### Requirement:" con sus escenarios) y busca en <carpeta de pruebas> qué prueba cita cada uno en su nombre. Tabla: requisito | prueba | archivo. Marca los que no tienen prueba y enséñame el comando de búsqueda que usaste.
Crear una skillSkills
Crea una skill en .cursor/skills/<nombre>/SKILL.md que <qué hace>, para la etapa <etapa>. name igual a la carpeta y en minúsculas; description en tercera persona, con qué hace y cuándo usarla; <con o sin> disable-model-invocation; menos de 150 líneas. Después dame un caso de prueba que debe funcionar y uno que no.
Crear un agente de sólo lecturaSkills
Crea un subagente en .claude/agents/<nombre>.md que <qué revisa>, para la etapa <etapa>. Sólo lectura en los dos agentes: tools: Read, Grep, Glob, Bash y readonly: true. Que cite archivo:línea en cada hallazgo, entregue máximo 3 bloqueantes y una salida con formato fijo y veredicto.
Crear un hookHooks
Crea un hook de proyecto en .cursor/hooks.json que <qué bloquea o revisa> en el evento <evento>. El script va en .cursor/hooks/, lee el JSON de stdin y sale con 2 para bloquear. Pruébalo con una entrada que debe pasar y otra que debe bloquearse antes de darlo por bueno.
Convertir un comando en skillSkills
Convierte el comando <ruta del .md> en una skill personal en ~/.cursor/skills/<nombre>/SKILL.md, con disable-model-invocation: true, sin cambiar sus pasos. Dime qué partes dependían de otra herramienta.
Reconocimiento por capasLegacy
Investiga <módulo> sólo leyendo y entrega en specs/000-reconocimiento/: mapa-sistema.md, flujo-<entidad>.md, registro-riesgos.md y memoria-historica.md. Cada afirmación con archivo:línea. Lo que tenga un solo testigo, PENDIENTE con la pregunta exacta que lo destrabaría.
Preguntas decidibles para el negocioLegacy
Con los PENDIENTES de registro-de-anomalias.md, redacta preguntas para negocio: contexto mínimo, lenguaje no técnico, un ejemplo con números reales, respuesta sí/no o a elegir, sin sugerir la respuesta, ordenadas por impacto económico y dirigidas a una persona.
Elegir el siguiente módulo a modernizarModernización
Compara los módulos candidatos a modernizar por valor (qué cambios pendientes bloquea), red (cuántas pruebas de caracterización lo cubren) y acoplamiento (consumidores y si toca base de datos, red o reloj). Deja la lista de consumidores de cada uno con archivo:línea. Recomienda; no elijas tú.
Funcionalidad nueva sin «feature isla»Modernización
/speckit-specify <funcionalidad>. Especifícala desde la arquitectura que ya tiene el repo (ver AGENTS.md); no propongas otro stack ni un servicio aparte. Si la arquitectura actual no la soporta, dime qué módulo habría que modernizar primero.
Pruebas de caracterizaciónLegacy
Escribe pruebas de caracterización de <módulo>: el valor esperado es el que produce el código actual. Si una prueba falla, corrige la prueba, nunca el código. Una prueba por anomalía con nombre "CONGELA comportamiento actual: A-xx · …"; toda frontera en tres puntos (debajo, el valor y encima). Usa el framework de pruebas que ya existe.
Formato de OpenSpec y trampas
Qué quieres
Encabezado
Regla
Agregar comportamiento
## ADDED Requirements
Si la capacidad es nueva, el delta empieza con ## Purpose (una o dos oraciones, 50 caracteres o más)
Cambiar comportamiento
## MODIFIED Requirements
Copia el bloque completo de la spec viva y edítalo; el título debe coincidir
Quitar comportamiento
## REMOVED Requirements
Lleva **Reason** y **Migration**
Sólo renombrar
## RENAMED Requirements
Formato FROM: / TO:
Cada requisito: ### Requirement: <nombre> y un texto con SHALL o MUST, en mayúsculas y como palabra completa.
Cada escenario: #### Scenario: con exactamente cuatro#, y las líneas - **WHEN** … / - **THEN** …. Al menos uno por requisito.
Descripción de un requisito nuevo: 500 caracteres o menos; si no, --strict falla.
Un cambio sin cambio de comportamiento (refactor, documentación) pone skip_specs: true en su .openspec.yaml; no inventa un requisito.
En español: el contenido va en español; los encabezados y SHALL/MUST, en inglés. El init con --language es lo deja escrito en config.yaml.
Todo medido de openspec instructions specs y del validador.
Trampas medidas
Escribir «DEBE» en lugar de SHALL o MUST
$ openspec validate debe-en-espanol
Change 'debe-en-espanol' is valid
⚠ [WARNING] prueba-de-idioma/spec.md: ADDED "Rechazar altas de productos de marcas bloqueadas" should contain SHALL or MUST (RFC 2119 best practice for English specs)
$ openspec validate debe-en-espanol --strict
Change 'debe-en-espanol' has issues
⚠ [WARNING] prueba-de-idioma/spec.md: ADDED "Rechazar altas de productos de marcas bloqueadas" should contain SHALL or MUST (RFC 2119 best practice for English specs)
Next steps:
- Ensure change has deltas in specs/: use headers ## ADDED/MODIFIED/REMOVED/RENAMED Requirements
- Each requirement MUST include at least one #### Scenario: block
- Debug parsed deltas: openspec show debe-en-espanol --json --deltas-only
$ echo $?
1
Archivar con tareas pendientes usando -y
$ openspec archive bloquear-marcas -y
Task status: 0/5 tasks
Warning: 5 incomplete task(s) found. Continuing due to --yes flag.
Specs to update:
bloqueo-de-marcas: create
Applying changes to openspec/specs/bloqueo-de-marcas/spec.md:
+ 2 added
Totals: + 2, ~ 0, - 0, → 0
Specs updated successfully.
Change 'bloquear-marcas' archived as '2026-10-18-bloquear-marcas'.
Un MODIFIED que omite escenarios
$ openspec archive texto-de-bloqueo -y
Task status: ✓ Complete
Specs to update:
bloqueo-de-marcas: update
bloqueo-de-marcas MODIFIED failed for header "### Requirement: Bloquear y desbloquear una marca" - current spec contains scenario(s) not present in the modified block: "Bloqueo sin motivo", "Otro rol intenta bloquear". The modified block has 1 scenario; the current spec has 3 scenarios. It adds none. Refresh the change spec before archiving to avoid dropping scenarios.
Aborted. No files were changed.
$ echo $?
1
Problemas comunes
Un hook bloqueó un comando que no se saltaba nada
El hook mira el texto del comando: si tu comando contiene el patrón, aunque sea como dato, lo bloquea. Ajusta el patrón para que sea preciso. Si el hook es del equipo, no lo rodees; dilo.
Los hooks de Spec Kit no se ejecutaron (no creó la rama o no hizo commit)
Los hooks de .specify/extensions.yml son instrucciones que el agente debe seguir, y a veces se las salta. Revisa specify extension list y pídele que corra el hook. Si algo no puede fallar, ponlo en un hook del agente (misión 4) o en el CI.
Al integrar ramas, choca .specify/feature.json
Es el puntero de Spec Kit a la spec activa, y cada rama lo cambia. Quédate con la versión de la rama principal.
Mi agente no aparece o el principal no lo usa
Revisa la carpeta (.cursor/agents/ o .claude/agents/) y que description diga cuándo usarlo. Pídelo por nombre: «Usa el subagente <nombre>…» o /<nombre>. Abre un chat nuevo después de crearlo.
Mi agente revisor editó archivos
En Cursor le falta readonly: true: tools no está documentado ahí y los subagentes heredan todas las herramientas. En Claude Code, quítale Edit y Write de tools.
Mi hook no se dispara
Revisa "version": 1 en hooks.json, que el script tenga chmod +x y la ruta relativa a la raíz del proyecto. Mira el canal de salida «Hooks» de Cursor. En los de Claude Code, cada entrada debe traer la clave matcherforo oficial de Cursor.
SyntaxError: Unexpected token 'with' al correr openspec
Tu Node es anterior a 20.19. Actualízalo y abre otra terminal; con nvm, cambia también la versión predeterminada.
Veo cada skill dos veces en Cursor
Instalaste las mismas skills para dos agentes. Cursor lee también .claude/skills/ y .agents/skills/. Deja una: specify integration uninstall <agente>.
openspec validate --strict pide SHALL o MUST
Escribiste «DEBE». Usa SHALL o MUST; el resto puede ir en español.
«Ensure change has deltas in specs/»
Falta el delta o los encabezados no son exactos (## ADDED Requirements, #### Scenario: con cuatro #). Depura con openspec show <cambio> --json --deltas-only.
/speckit-plan trabaja sobre otra feature
Las skills leen la feature activa de .specify/feature.json. Ábrelo o pásale la ruta de la spec.
No aparecen los comandos después de instalar
Reinicia el IDE (OpenSpec lo pide al terminar) o abre un chat nuevo, y confirma que abriste el agente en la carpeta donde corriste init.
Chuleta de comandos
specify init --here --force --integration <agente> --script sh
Instalar en el repo actual
specify integration list | install | status | upgrade | switch | uninstall
Curso de SDD que sigue el equipo, secciones 2 a 8: lo que la página marca como «curso de SDD» sale de sus lecciones, y la tabla de temas avanzados dice dónde se practica cada una.
Cómo se midió. Un script corre las dos herramientas de verdad en una carpeta temporal y guarda sus archivos y salidas. Mide la inicialización para Cursor, Claude, Codex y Copilot, el ciclo de dos cambios de OpenSpec, la extensión git de Spec Kit y sus hooks, los worktrees, las reglas de config.yaml llegando al agente, los casos permitidos del hook y la revisión requisito → prueba. El bloque que crea la skill y el agente de la ruta exprés se ejecuta y se compara con los originales cada vez que se genera la página. Las rutas de la máquina se reemplazaron por ~/mi-proyecto. Las misiones, los flujos de reverse-spec y modernización, y los agentes de revisión se basan en el kit de un equipo que trabaja así. Aquí van en versiones genéricas.