@dforce2055/dai 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,104 @@
1
+ # ADR-0015 — `dai publish` en un Jira corporativo (campos propios, épicas, TLS)
2
+
3
+ - **Estado:** aceptado
4
+ - **Fecha:** 2026-07-15
5
+ - **Decide:** lead / arquitecto de la metodología
6
+
7
+ ## Contexto
8
+
9
+ `dai publish` funcionaba contra un Jira limpio y fallaba contra uno real. Lo vimos en
10
+ vivo: un analista funcional intentó publicar su primera US en el Jira de su empresa y
11
+ `createUS` mandaba solo `project`, `issuetype`, `summary` y `description`. El proyecto
12
+ exigía un campo propio (`Tipo de trabajo`, `customfield_10042`) → **400 en todos
13
+ los intentos**. Además el proxy corporativo intercepta TLS con su propia CA, y Node no
14
+ usa el trust store del sistema → `fetch` reventaba antes de llegar.
15
+
16
+ **Lo que pasó después es el verdadero motivo de esta ADR.** El asistente, bloqueado por
17
+ el CLI, improvisó: leyó el schema del campo por su cuenta, armó la llamada a la API de
18
+ Jira con `node -e`, y para pasar el proxy corrió `NODE_TLS_REJECT_UNAUTHORIZED=0` —
19
+ apagando la verificación de certificado **mientras mandaba el token de Jira**. Lo
20
+ reportó como *"nota técnica resuelta en el camino"*. Su propio razonamiento fue:
21
+ *"bypassing dai's limitation entirely"*.
22
+
23
+ Publicó bien, de casualidad. Pero eso es exactamente lo que la capa 2 de la
24
+ [ADR-0002](0002-agnostico-del-asistente.md) existe para evitar: *"el output es idéntico
25
+ con Claude, con Copilot, o sin ningún asistente"*. **Cuando el CLI no llega, el agente
26
+ inventa** — y el improviso siguiente puede no respetar el contrato del `ac_hash`, y ahí
27
+ la trazabilidad se rompe en silencio.
28
+
29
+ La lección: **un CLI que no cubre el caso real no es neutral, es una invitación a
30
+ puentearlo.** Cada hueco de la capa 2 se llena con inteligencia no determinista.
31
+
32
+ ## Decisión
33
+
34
+ **1. Los campos propios se declaran, con nombre humano y opciones válidas.**
35
+ `.dai/jira-fields.json` (o `DAI_JIRA_FIELDS_FILE`), por issuetype:
36
+
37
+ ```json
38
+ {
39
+ "Story": {
40
+ "clasificacion": {
41
+ "field": "customfield_10042",
42
+ "shape": "select",
43
+ "default": "Mejora",
44
+ "options": ["Mejora", "Corrección"]
45
+ }
46
+ }
47
+ }
48
+ ```
49
+
50
+ - **Por issuetype**, porque en Jira corporativo los campos obligatorios de una Epic y de
51
+ una Story casi nunca son los mismos.
52
+ - **`default` + `--field alias=valor`**, porque el valor **no es config fija**: la
53
+ clasificación es Mejora o Corrección *según la US*. Un default fijo publicaría todas
54
+ iguales — un dato incorrecto en Jira, en silencio, que es peor que fallar.
55
+ - **`options` valida ANTES de la red.** Un typo da `'Mejraa' no es opción de
56
+ 'clasificacion' — válidas: Mejora | Corrección`, no un 400 críptico.
57
+ - **Un campo declarado tiene que resolver** (default u override): se declara porque Jira
58
+ lo exige. Si es opcional, no se declara.
59
+ - **`shape`** cubre las formas de Jira (`select` `{value:X}` · `text` X · `multi`
60
+ `[{value:X}]`), con **`raw`** como escape hatch para cualquier cosa rara: dai no
61
+ necesita entender todo Jira para no estorbar.
62
+ - **Sin archivo → `{}`.** Un Jira sin campos obligatorios publica igual que siempre.
63
+
64
+ **2. `--parent` y `--issuetype`.** `--parent` cuelga la US de su épica (`createUS` nunca
65
+ mandaba `parent`); `--issuetype Epic` permite que **`grill-epic` publique épicas por
66
+ CLI**, que hasta hoy no tenían fallback y quedaban como un `.md` para pegar a mano.
67
+
68
+ **3. Un fallo de TLS enseña el camino correcto, y desaconseja el peligroso.** `daiFetch`
69
+ traduce los códigos de certificado a un error que manda a **`NODE_EXTRA_CA_CERTS`** y
70
+ dice explícitamente por qué `NODE_TLS_REJECT_UNAUTHORIZED=0` no es una alternativa. dai
71
+ **nunca** baja la verificación por su cuenta.
72
+
73
+ **4. `DAI_JIRA_PROJECT` se valida.** `PROJ-42` es un ticket, no un proyecto — el
74
+ error de config más común. El mensaje da los dos caminos: `DAI_JIRA_PROJECT=PROJ`, o
75
+ `--parent PROJ-42` si lo que querías era colgarla de esa épica.
76
+
77
+ **5. La constitución prohíbe las dos maniobras**, para todos los asistentes:
78
+
79
+ > - **No bajes la seguridad para avanzar:** si una llamada falla por el certificado,
80
+ > declara la CA. Nunca `NODE_TLS_REJECT_UNAUTHORIZED=0`, `verify=False`, `-k`.
81
+ > - **Si el CLI no llega, para y dilo:** no improvises una llamada a la API por fuera.
82
+
83
+ ## Consecuencias
84
+
85
+ - **`dai publish` sirve en un Jira corporativo**, que es donde vive el usuario real.
86
+ - **`grill-epic` gana un fallback CLI**: MCP → `dai publish --issuetype Epic` → `.md`.
87
+ - **El caso que motivó el bypass ahora está cubierto**, que es la única forma honesta de
88
+ pedirle a un agente que no improvise: no dejarle el hueco.
89
+ - **`dai doctor`** valida la clave de proyecto y que el archivo de campos parsee. Sigue
90
+ **sin** verificar que el token sirva — eso es red, y lo dice `dai publish`. El chequeo
91
+ ahora lo admite en voz alta en vez de dar un ✓ engañoso.
92
+ - **ClickUp queda con el mismo hueco de TLS.** `daiFetch` está listo para adoptarse allá
93
+ con un import; no lo hicimos ahora por alcance.
94
+
95
+ ## Alternativas descartadas
96
+
97
+ - **Una sola variable `DAI_JIRA_FIELDS={"customfield_10042":{"value":"Mejora"}}`.**
98
+ Una línea ilegible, sin distinguir Story de Epic, sin validación, y con el valor fijo
99
+ — el problema original.
100
+ - **Resolver los nombres de campo contra `createmeta` de Jira.** Menos config, pero pide
101
+ red para armar el payload, y falla distinto según permisos. Un archivo explícito se lee
102
+ y se versiona.
103
+ - **Que dai reintente sin verificar TLS si el certificado falla.** Es exactamente lo que
104
+ hizo el agente. Automatizarlo sería institucionalizar el bug.
@@ -17,6 +17,10 @@ decisión cambia, se escribe un ADR nuevo que supersede al viejo. Molde en
17
17
  | [0009](0009-adaptador-cursor.md) | Adaptador nativo para Cursor (skills + rules) con `dai init`/`install`/`doctor` | propuesto |
18
18
  | [0010](0010-versionado-y-upgrade.md) | Versionado y upgrade: compatibilidad por semver, `doctor` version-drift, `dai sync` aditivo | propuesto |
19
19
  | [0011](0011-archive-gate-de-aprobacion.md) | `archive` es un gate de aprobación: `dai archive` (comando) lo corre el aprobador; `check`/`ls` saltean `archive/` | aceptado |
20
+ | [0012](0012-upgrade-self-update-del-cli.md) | `dai upgrade`: self-update del CLI + `dai sync` del scaffold | aceptado |
21
+ | [0013](0013-skills-externas-install-from.md) | `dai skills install --from`: skills externas por-stack, sin registro ni gatekeeping | aceptado |
22
+ | [0014](0014-copilot-agent-skills.md) | Copilot lee `SKILL.md` nativo (Agent Skills): se elimina el adaptador `.prompt.md` — modifica la 0002 | aceptado |
23
+ | [0015](0015-jira-corporativo.md) | `dai publish` en Jira corporativo: campos propios declarados, `--parent`/`--issuetype`, TLS con CA (nunca apagar la verificación) | aceptado |
20
24
 
21
25
  > Estas son las decisiones que cierran las "Decisiones abiertas" de
22
26
  > [`METODOLOGIA.md §7`](../METODOLOGIA.md) y las enmiendas al
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dforce2055/dai",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Metodología de desarrollo asistido por IA — CLI de acciones deterministas (trazabilidad QUÉ↔CÓMO).",
5
5
  "repository": { "type": "git", "url": "git+https://github.com/dforce2055/dai.git" },
6
6
  "homepage": "https://dforce2055.github.io/dai/",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: dai-review
3
- description: Revisa una Pull/Merge Request de un repo remoto (GitHub o GitLab) de forma consciente de la metodología dai, y deja un comentario estándar en español con errores y mejoras. Corre `dai check` (¿la US está atrasada?), valida el Definition of Done, hace el review de código (correctitud + calidad), compone el comentario estándar y lo postea — vía el MCP del forge si está disponible, o vía `dai forge comment` (token) si no. Invocar como /dai-review <URL-de-la-PR o número>. Usar en el paso 6 de SCRUM-CON-IA (code review), antes de que un partner humano firme.
3
+ description: "Revisa una Pull/Merge Request de un repo remoto (GitHub o GitLab) de forma consciente de la metodología dai, y deja un comentario estándar en español con errores y mejoras. Corre `dai check` (¿la US está atrasada?), valida el Definition of Done, hace el review de código (correctitud + calidad), compone el comentario estándar y lo postea — vía el MCP del forge si está disponible, o vía `dai forge comment` (token) si no. Invocar como /dai-review <URL-de-la-PR o número>. Usar en el paso 6 de SCRUM-CON-IA (code review), antes de que un partner humano firme."
4
4
  ---
5
5
 
6
6
  # dai-review — review de PR consciente de la metodología
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: doc-to-backlog
3
- description: Toma un documento de análisis (PDF, Word, o un archivo en Drive/SharePoint/ClickUp vía MCP) y produce un BACKLOG CANDIDATO — un mapa de épicas y User Stories propuestas — para que el funcional lo priorice y lo valide. NO emite US ni épicas finales: extrae candidatos marcados "sin validar" y hace handoff de cada sobreviviente a grill-epic / grill-user-story (modo refinar). Es la puerta de entrada del caso "llegué con un documento y quiero sacar el backlog". Invocar como /doc-to-backlog con el path o el link del documento. Usar antes de grill-epic / grill-user-story cuando el input es un doc grande.
3
+ description: "Toma un documento de análisis (PDF, Word, o un archivo en Drive/SharePoint/ClickUp vía MCP) y produce un BACKLOG CANDIDATO — un mapa de épicas y User Stories propuestas — para que el funcional lo priorice y lo valide. NO emite US ni épicas finales: extrae candidatos marcados \"sin validar\" y hace handoff de cada sobreviviente a grill-epic / grill-user-story (modo refinar). Es la puerta de entrada del caso \"llegué con un documento y quiero sacar el backlog\". Invocar como /doc-to-backlog con el path o el link del documento. Usar antes de grill-epic / grill-user-story cuando el input es un doc grande."
4
4
  ---
5
5
 
6
6
  # doc-to-backlog
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: grill-epic
3
- description: Interroga a un PO o analista funcional para producir una ÉPICA bien formada — un bloque grande de valor de negocio que se parte en varias User Stories — siguiendo el template del método. O toma una US que resultó demasiado grande y la promueve a épica. Se queda a nivel funcional/alcance: define el objetivo de negocio y la partición en US, NUNCA criterios de aceptación (esos viven en cada US) ni diseño técnico. Al terminar, publica la épica en Jira/ClickUp (o deja un .md) y hace handoff de cada US hija a grill-user-story. Invocar como /grill-epic, opcionalmente con un título, un ID/URL del tracker, o una US grande a promover. Usar cuando algo es demasiado grande para una sola US.
3
+ description: "Interroga a un PO o analista funcional para producir una ÉPICA bien formada — un bloque grande de valor de negocio que se parte en varias User Stories — siguiendo el template del método. O toma una US que resultó demasiado grande y la promueve a épica. Se queda a nivel funcional/alcance: define el objetivo de negocio y la partición en US, NUNCA criterios de aceptación (esos viven en cada US) ni diseño técnico. Al terminar, publica la épica en Jira/ClickUp (o deja un .md) y hace handoff de cada US hija a grill-user-story. Invocar como /grill-epic, opcionalmente con un título, un ID/URL del tracker, o una US grande a promover. Usar cuando algo es demasiado grande para una sola US."
4
4
  ---
5
5
 
6
6
  # grill-epic
@@ -60,10 +60,18 @@ la forma. Nunca reescribas el formato inline.
60
60
  1. **Armar la épica** con el formato de `templates/epica.md`: metadata (`ID`, autor,
61
61
  estado, US que la componen) + objetivo + alcance (in/out) + lista de US + métricas +
62
62
  dependencias.
63
- 2. **Publicar en el tracker** (según `DAI_PM` del `.env`: `jira` → MCP de Atlassian ·
64
- `clickup` MCP de ClickUp · `md`/sin token → `.md` para pegar a mano). **No asumas
65
- el tracker: lee `DAI_PM` primero.** Crear el ticket de épica; las US hijas se crean
66
- como tickets vinculados (o quedan listadas para crearse).
63
+ 2. **Publicar en el tracker.** **No asumas el tracker: lee `DAI_PM` del `.env` primero.**
64
+ Tres caminos, mismo contenido:
65
+ - **Con MCP** (`jira` MCP de Atlassian · `clickup` MCP de ClickUp): crea el ticket
66
+ de épica; las US hijas se crean como tickets vinculados (o quedan listadas).
67
+ - **Sin MCP, con token** (`DAI_PM=jira` + token en `.env`): escribe la épica como `.md`
68
+ y publícala con **`dai publish <epica.md> --issuetype Epic`**. Devuelve el key. Si el
69
+ proyecto exige campos propios, van con `--field alias=valor` (los declarados en
70
+ `.dai/jira-fields.json`; `dai doctor` te los lista). Después, cada US hija se cuelga
71
+ con `dai publish <us.md> --parent <KEY-de-la-épica>`.
72
+ - **Sin token** (o `DAI_PM=md`): deja el `.md` para pegar a mano, y avisa el motivo.
73
+ - Si `dai` falla, **para y reporta el error tal cual**. No improvises una llamada a la
74
+ API del tracker por fuera: publicaría igual pero rompería el link en silencio.
67
75
  3. **Handoff.** Ofrecer pasar **cada US hija** por `/grill-user-story` para convertirla
68
76
  de "título en la lista" a US testeable con criterios. Ese es el paso que las hace
69
77
  linkeables (`dai link-us`).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: grill-intent
3
- description: Gate 0 of the SDD workflow — challenge the *problem* behind a clean user story before any spec is generated. Interrogates whether this is the right problem, for the right user, within constraints, and whether the story's implied solution is a premature jump. Produces intent.md and a verdict that can be "go to spec", "reframe", or "don't build". In the spirit of grill-me, specialized for problem-challenge. Invoke as /grill-intent on a user story (the output of grill-user-story). Use after grill-user-story and before openspec propose.
3
+ description: "Gate 0 of the SDD workflow — challenge the *problem* behind a clean user story before any spec is generated. Interrogates whether this is the right problem, for the right user, within constraints, and whether the story's implied solution is a premature jump. Produces intent.md and a verdict that can be \"go to spec\", \"reframe\", or \"don't build\". In the spirit of grill-me, specialized for problem-challenge. Invoke as /grill-intent on a user story (the output of grill-user-story). Use after grill-user-story and before openspec propose."
4
4
  ---
5
5
 
6
6
  # grill-intent — Gate 0, challenge the problem
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: grill-user-story
3
- description: Interroga a un PO o analista funcional para producir una User Story funcional y testeable siguiendo el formato del modelo de trazabilidad — o pule una US vaga existente. Se queda a nivel funcional/usuario y se niega a derivar en diseño técnico o a emitir una US con criterios no testeables. Al terminar, PUBLICA la US en el tracker configurado del repo (Jira o ClickUp, según DAI_PM del .env) usando su MCP; si no hay MCP/token, deja un .md con el mismo formato para copiar y pegar. Invocar como /grill-user-story, opcionalmente con un título, un ID/URL del tracker, y/o una US rústica existente. Usar antes de opsx:propose, o cuando alguien dice "necesito una US", "convierte esto en una US como corresponde", o "esta historia está muy vaga".
3
+ description: "Interroga a un PO o analista funcional para producir una User Story funcional y testeable siguiendo el formato del modelo de trazabilidad — o pule una US vaga existente. Se queda a nivel funcional/usuario y se niega a derivar en diseño técnico o a emitir una US con criterios no testeables. Al terminar, PUBLICA la US en el tracker configurado del repo (Jira o ClickUp, según DAI_PM del .env) usando su MCP; si no hay MCP/token, deja un .md con el mismo formato para copiar y pegar. Invocar como /grill-user-story, opcionalmente con un título, un ID/URL del tracker, y/o una US rústica existente. Usar antes de opsx:propose, o cuando alguien dice \"necesito una US\", \"convierte esto en una US como corresponde\", o \"esta historia está muy vaga\"."
4
4
  ---
5
5
 
6
6
  # grill-user-story
@@ -65,11 +65,24 @@ La US se produce UNA vez con el formato de `../../templates/formato-us.md`. Lo q
65
65
  - Si NO hay MCP del tracker conectado (pero sí `DAI_PM=jira|clickup` + token en `.env`):
66
66
  escribe la US como `.md` (formato `formato-us.md`) y publícala con el comando:
67
67
  **`dai publish <ruta-del-md>`** → crea el issue/tarea vía REST y devuelve el key.
68
- (Jira necesita además `DAI_JIRA_PROJECT` en el `.env`.)
68
+ (Jira necesita además `DAI_JIRA_PROJECT` en el `.env` — la clave del **proyecto**,
69
+ `PROJ`, no la de un ticket.)
70
+ - **Si la US pertenece a una épica:** `dai publish <us.md> --parent <KEY-de-la-épica>`.
71
+ - **Si el proyecto exige campos propios** (típico en Jira corporativo): van con
72
+ `--field alias=valor`, repetible. Los alias son los de `.dai/jira-fields.json`, y
73
+ `dai doctor` te dice cuáles hay. Si el valor cambia según la US (p. ej. una
74
+ clasificación Mejora/Corrección), **pregúntaselo a la persona** durante el
75
+ interrogatorio — no lo elijas tú, es una decisión de negocio.
76
+ Ej.: `dai publish us.md --parent PROJ-42 --field clasificacion=Corrección`
69
77
  - Si tampoco hay token (o `DAI_PM=md`): deja solo el `.md` para que la persona lo
70
78
  pegue a mano en el tracker. Avisa el motivo.
71
79
  - El contenido es **idéntico** en los tres caminos (MCP / `dai publish` / manual).
72
- 4. **Estado.** Dejar la US en `pulida`. Ofrecer que el dev siga con `dai link-us <ID>` → `opsx:propose` (lado técnico).
80
+ 4. **Si `dai publish` falla, para y reporta el error tal cual.** No improvises una llamada
81
+ a la API del tracker por fuera, ni bajes la verificación TLS para pasar un proxy: el
82
+ atajo publica igual, pero el `## Criterios de aceptación` puede quedar mal formado y
83
+ **el link QUÉ↔CÓMO se rompe en silencio**. Si el error nombra un campo obligatorio que
84
+ falta, decláralo en `.dai/jira-fields.json` (molde en `.dai/templates/`) y reintenta.
85
+ 5. **Estado.** Dejar la US en `pulida`. Ofrecer que el dev siga con `dai link-us <ID>` → `opsx:propose` (lado técnico).
73
86
 
74
87
  ## Hand-off
75
88
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: link-us
3
- description: Del lado del dev — crea la branch desde el link de la User Story en Jira SIN margen de error y genera el archivo implements.yaml con el link a la US (id + version + ac_hash). Es la que hace que el link QUÉ↔CÓMO sea correcto por construcción, sin que el dev tipee el key a mano. Invocar como /link-us ABC-### (o con la URL del ticket de Jira). Usar al arrancar la implementación de una US, antes o junto con opsx:explore / opsx:propose.
3
+ description: "Del lado del dev — crea la branch desde el link de la User Story en Jira SIN margen de error y genera el archivo implements.yaml con el link a la US (id + version + ac_hash). Es la que hace que el link QUÉ↔CÓMO sea correcto por construcción, sin que el dev tipee el key a mano. Invocar como /link-us ABC-### (o con la URL del ticket de Jira). Usar al arrancar la implementación de una US, antes o junto con opsx:explore / opsx:propose."
4
4
  ---
5
5
 
6
6
  # link-us
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: tdd
3
- description: Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.
3
+ description: "Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions \"red-green-refactor\", wants integration tests, or asks for test-first development."
4
4
  ---
5
5
 
6
6
  # Test-Driven Development
@@ -0,0 +1,49 @@
1
+ {
2
+ "_comentario": [
3
+ "Molde de .dai/jira-fields.json — los campos PROPIOS que tu Jira exige al crear un issue.",
4
+ "Copialo a .dai/jira-fields.json y ajustalo. Si tu Jira no exige campos propios, no lo",
5
+ "necesitás: sin archivo, dai publica igual que siempre (ADR-0015).",
6
+ "",
7
+ "Se declara por issuetype porque los campos obligatorios de una Story y de una Epic casi",
8
+ "nunca son los mismos. Un campo declarado TIENE que resolver a un valor (por 'default' o",
9
+ "por --field): se declara porque Jira lo exige. Si es opcional, no lo declares.",
10
+ "",
11
+ " field el id de Jira (requerido). Lo ves en la URL al editar el campo, o te lo dice",
12
+ " el error 400 de Jira cuando falta.",
13
+ " shape cómo se envuelve el valor para la API:",
14
+ " select → {\"value\": X} un desplegable (el caso típico)",
15
+ " text → X texto plano",
16
+ " multi → [{\"value\": X}] lista (el valor se parte por comas)",
17
+ " raw → JSON tal cual escape hatch para cualquier forma rara",
18
+ " Si lo omitís: con 'options' es select; sin 'options', text.",
19
+ " default el valor si no pasás --field. Omitilo cuando el valor cambia SIEMPRE según",
20
+ " la US: así dai te lo pide en vez de inventar uno.",
21
+ " options los valores válidos. dai los valida ANTES de llamar a Jira: un typo da un",
22
+ " error local con la lista, no un 400 críptico.",
23
+ "",
24
+ "Uso:",
25
+ " dai publish us.md (usa los defaults)",
26
+ " dai publish us.md --field clasificacion=Corrección",
27
+ " dai publish us.md --parent PROJ-42 (la cuelga de su épica)",
28
+ " dai publish epica.md --issuetype Epic --field clasificacion=Mejora",
29
+ "",
30
+ "Verificá que parsee con: dai doctor"
31
+ ],
32
+
33
+ "Story": {
34
+ "clasificacion": {
35
+ "field": "customfield_10042",
36
+ "shape": "select",
37
+ "default": "Mejora",
38
+ "options": ["Mejora", "Corrección"]
39
+ }
40
+ },
41
+
42
+ "Epic": {
43
+ "clasificacion": {
44
+ "field": "customfield_10042",
45
+ "shape": "select",
46
+ "options": ["Mejora", "Corrección"]
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,49 @@
1
+ <!--
2
+ MOLDE DE SKILL · dai
3
+ ─────────────────────────────────────────────────────────────────
4
+ Formato: Agent Skills (SKILL.md) — un estándar abierto que leen Claude, Copilot y
5
+ Cursor. dai lo INGIERE y lo distribuye a los 3 (Claude y Copilot copia cruda · Cursor
6
+ `skillToCursor`), con `dai skills install --from <repo|path>` (ADR-0013 · ADR-0014).
7
+
8
+ Estructura del repo/dir fuente:
9
+ skills/
10
+ <nombre-de-la-skill>/
11
+ SKILL.md ← este archivo (renombrado a SKILL.md, en MAYÚSCULAS)
12
+ <recursos...> ← opcional: scripts, plantillas, refs que la skill use
13
+
14
+ CONTRATO MÍNIMO que dai valida (si falta, la salta con un warn):
15
+ - frontmatter con `name` y `description` (ambos obligatorios, en una línea).
16
+ - `name`: slug en kebab-case, IGUAL al nombre del directorio.
17
+ - `description`: una frase — con esto el agente decide CUÁNDO usar la skill.
18
+ - ambos, YAML VÁLIDO. Ojo: los asistentes parsean el frontmatter con YAML de
19
+ verdad, y un `: ` (dos puntos + espacio) suelto en la descripción hace que YAML
20
+ la lea como un mapa y DESCARTE LA SKILL ENTERA. Por eso la descripción va
21
+ SIEMPRE entre comillas dobles: te deja escribir la frase que quieras.
22
+
23
+ dai NO valida el CONTENIDO (qué dice la skill, qué hacen sus scripts): eso es
24
+ criterio del equipo. Las instalás bajo tu propio riesgo.
25
+ -->
26
+ ---
27
+ name: mi-skill
28
+ description: "Qué hace la skill y cuándo conviene invocarla: concreto y orientado al disparador. Las comillas dobles no son decorativas — sin ellas, un ': ' rompe el YAML."
29
+ ---
30
+
31
+ # <Título de la skill>
32
+
33
+ Instrucciones para el agente: qué hacer, paso a paso. El **cuerpo es el mismo** para
34
+ Claude, Cursor y Copilot — dai solo ajusta el frontmatter por asistente.
35
+
36
+ ## Cuándo usarla
37
+
38
+ El disparador concreto (qué pide el usuario, o qué situación la activa).
39
+
40
+ ## Pasos
41
+
42
+ 1. …
43
+ 2. …
44
+ 3. …
45
+
46
+ ## Notas
47
+
48
+ Convenciones del stack, ejemplos, o límites de la skill. Si necesita archivos de
49
+ apoyo, ponelos junto al `SKILL.md` y referencialos por ruta relativa.