¿Qué hace OpenSpec Merge?
Fusiona varias carpetas de capacidades relacionadas en openspec/specs/ en una única especificación de funcionalidad principal, mediante un flujo de trabajo en dos fases (etapa/aprobación). Nada en openspec/specs/<capacidad>/ se modifica hasta que un humano haya aprobado explícitamente la fusión.
Cuándo aplica
El flujo de trabajo de archivo de OpenSpec sincroniza los deltas en openspec/specs/<capacidad>/spec.md por cambio. Cuando cambios relacionados se archivan bajo diferentes nombres de capacidad (a menudo porque se construyeron por etapas, ej., user-show, user-detail, user-permissions), terminas con varias carpetas de especificaciones que describen funcionalmente una misma funcionalidad. Esta habilidad las fusiona en una sola, mediante un área de stage que requiere aprobación humana antes de que algo real sea reemplazado.
Las dos fases
- Fase A — Stage: lee las especificaciones fuente, escribe un borrador fusionado en
openspec/specs/.merged-specs/<funcionalidad>/spec.mdconApproved-by-human: no. Nada más cambia. - Fase B — Apply: se activa cuando el usuario ha cambiado el frontmatter a
Approved-by-human: yes. Reemplaza las carpetas fuente con el contenido aprobado y elimina el archivo de stage.
Siempre detecta qué fase aplica: si openspec/specs/.merged-specs/<funcionalidad>/ ya existe, primero verifica su campo Approved-by-human en lugar de volver a hacer stage desde cero.
Fase A — Stage
1. Identificar carpetas candidatas
Lista openspec/specs/* y busca carpetas que:
- Compartan un prefijo de nombre común o palabra de dominio (
user-show,user-detail,user-permissions) - Hagan referencia a la misma entidad/recurso en sus requisitos (mismo modelo, mismos endpoints de API, misma página UI)
- Fueron archivadas cerca en el tiempo (revisa las fechas en
openspec/changes/archive/)
Si el usuario nombró carpetas específicas explícitamente, usa esas en lugar de adivinar.
Si existe más de una agrupación plausible, detente y pregunta al usuario qué carpetas deben ir juntas antes de hacer stage de nada.
2. Leer cada spec.md candidato completo
Para cada carpeta, lee el spec.md completo, no solo los encabezados. Anota nombres de requisitos, escenarios, marcadores de deprecación y cualquier cosa que parezca modificar/sustituir un requisito en otra carpeta candidata.
3. Inferir el nombre de la capacidad destino
Derívalo del prefijo común o sustantivo de dominio compartido entre las carpetas candidatas (ej., user-show + user-detail + user-permissions → user, o user-management si suena más natural).
- Prefijo/dominio común claro → úsalo, no hace falta preguntar.
- Sin nombre compartido obvio (ej.,
checkout-flowyinvoice-exportrelacionados solo por un vago tema de "facturación") → pregunta al usuario que nombre la capacidad destino antes de continuar.
Indica el nombre inferido explícitamente en tu salida para que el usuario pueda sobrescribirlo.
4. Fusionar los requisitos
Reglas, en orden:
- Unión de requisitos AÑADIDOS: se mantiene cada requisito distinto de cada carpeta fuente.
- Requisitos conflictivos/duplicados (mismo nombre, o mismo comportamiento descrito dos veces): conserva la versión más completa/reciente, fusionando detalles no conflictivos en lugar de descartar silenciosamente.
- Requisitos ELIMINADOS/obsoletos: exclúyelos de la especificación fusionada.
- Nunca inventes requisitos. Marca ambigüedades o contradicciones en línea (ej.,
<!-- CONFLICTO: fuente A dice X, fuente B dice Y — necesita decisión humana -->) en lugar de elegir silenciosamente. - Preserva el texto de escenario original cuando sea posible; solo reescribe prosa al fusionar dos requisitos superpuestos en uno.
5. Escribir el archivo de stage
Escribe en:
openspec/specs/.merged-specs/<nombre-inferido>/spec.md
Con este frontmatter al inicio:
---
Approved-by-human: no
merged-from:
- user-show
- user-detail
- user-permissions
---
Seguido del contenido de la especificación fusionada.
6. Informar al usuario, brevemente
- Qué carpetas fuente se fusionaron y el nombre destino inferido
- Cualquier conflicto marcado en línea que necesite decisión
- Exactamente qué hacer a continuación: abrir
openspec/specs/.merged-specs/<nombre-inferido>/spec.md, revisarlo, editarlo si es necesario, y establecerApproved-by-human: yesen el frontmatter una vez satisfecho - Que nada en
openspec/specs/<capacidad>/ha sido tocado aún
Fase B — Apply
Activación: el usuario pide aplicar/finalizar una fusión, o notas que openspec/specs/.merged-specs/<funcionalidad>/spec.md tiene Approved-by-human: yes.
- Vuelve a leer el archivo de stage y confirma
Approved-by-human: yes. Si sigue siendono, detente e informa al usuario que necesita aprobación primero — no apliques. - Lee
merged-fromdel frontmatter para saber qué carpetas fuente reemplazar. - Elimina el frontmatter del contenido de stage (ambos campos), dejando un
spec.mdlimpio sin frontmatter. - Reemplaza las carpetas fuente con el resultado fusionado:
- Crea/sobrescribe
openspec/specs/<nombre-inferido>/spec.mdcon el contenido sin frontmatter. - Elimina las otras carpetas fuente listadas en
merged-fromque no sean el nombre destino.
- Crea/sobrescribe
- Elimina la carpeta de stage
openspec/specs/.merged-specs/<nombre-inferido>/. - Confirma al usuario qué fue reemplazado/eliminado, para que sea fácil verificar con git diff antes de confirmar.
Nunca ejecutes el paso 4 sin un Approved-by-human: yes explícito ya presente en el archivo — no pidas al usuario que apruebe verbalmente en el chat como sustituto; la aprobación debe ser el propio campo de frontmatter cambiado.
Ejemplo
Fase A — Entrada: openspec/specs/user-show/, openspec/specs/user-detail/, openspec/specs/user-permissions/ — todas describiendo diferentes aspectos de la misma funcionalidad de perfil de usuario.
Salida: openspec/specs/.merged-specs/user/spec.md:
---
Approved-by-human: no
merged-from:
- user-show
- user-detail
- user-permissions
---
# User
## Requisito: ...
...
Mensaje al usuario: fusionado desde user-show, user-detail, user-permissions en la capacidad inferida user (renombra la carpeta si prefieres user-management); no se encontraron conflictos; revisa openspec/specs/.merged-specs/user/spec.md y establece Approved-by-human: yes cuando estés listo.
Fase B — Una vez que el usuario establece Approved-by-human: yes y pide aplicar: se crea/sobrescribe openspec/specs/user/spec.md con el contenido fusionado sin frontmatter, se eliminan user-show/, user-detail/, user-permissions/, y se elimina openspec/specs/.merged-specs/user/.