Qué es una skill, su frontmatter y cómo se redacta están en Skills y agentes. Aquí, la estructura completa de una skill: qué carpetas y ficheros puede tener, qué secciones lleva el SKILL.md según el tipo. Cómo se prueba está en Evaluación de skills.
Más información:
SKILL.md, ficheros de apoyo y carga por niveles.$ARGUMENTS.Cada skill es una carpeta dentro de la carpeta de skills del proyecto. La carpeta en concreto depende de la herramienta:
.opencode/skills/..claude/skills/.
OpenCode también lee .claude/skills/, así que con esa carpeta una misma skill vale para las dos.
Hay dos tipos de skills:
/.Lo que hace una skill que hace cosas es, en el fondo, el trabajo de un agente. Pero crear un skill que actúa de agente, no como agente tiene las siguientes ventajas:
.claude/agents/, así que sus plantillas, scripts o ejemplos no pueden ir junto a él. Una skill es una carpeta y lleva dentro todo lo que usa (ver la estructura).agent- delante del nombre; una skill, directamente:
@agent-crear-servicio R-12 /do-crear-servicio R-12
Normalmente no hace falta convertirla en agente: lo que aporta un agente es empezar con el contexto vacío, y eso ya se consigue lanzando la skill en una sesión limpia, con /clear antes. Si aun así quieres que se ejecute como un agente, en Claude Code basta con context: fork en el frontmatter:
--- name: do-crear-servicio description: Crea un servicio de Pedidos con su test a partir de un requisito de specs/. context: fork ---
context: fork en los skills como ha hecho claude code.
El nombre de la skill (su carpeta y su name) empieza por un prefijo que dice de qué tipo es:
k-, de knowledge, conocimiento en inglés: las que saben cosas. Describen las convenciones del proyecto y las cargan otras skills y los agentes: k-servicios, k-tests.do-, «hacer» en inglés: las que hacen cosas. Ejecutan un proceso y las lanzas tú: do-crear-servicio, do-revisar-pr.
Detrás del prefijo, en kebab-case, el tema en las k- y un verbo en las do-.
Ventajas del prefijo:
/. Una skill llamada init o context se confunde con /init o /context; /do-revisar-pr no coincide con ningún comando./do- sale todo lo que se puede lanzar: el autocompletado enseña solo las skills que hacen cosas, sin las de conocimiento, que no se lanzan a mano.
Una skill no suele ser un único SKILL.md: lleva una serie de ficheros auxiliares que la organizan y que el LLM solo carga cuando los necesita, en vez de cargar la skill entera. Solo el SKILL.md es obligatorio; cada carpeta aparece únicamente si la skill tiene ese tipo de contenido.
| Carpeta o fichero | Contiene | Ejemplo |
|---|---|---|
SKILL.md | Instrucciones e índice | |
<tema>.md | Son ficheros extra que deberían estar en SKILL.md pero que los sacamos fuera para que el agente no tenga que leer todo si no lo necesita | transacciones.md |
agents/ | El rol completo de un subagente que lanza la skill: uno por fichero. | verificador.md |
templates/ | Plantillas literales con huecos. Es para cuando el skill debe generar algún tipo de fichero para que tenga una guia de como debe ser. | service-impl.md |
examples/ | Ejemplo de como queda lo que tiene que generar. Un buen ejemplo siempre ayuda mucho al agente a hacer su trabajo. Mejor un buen ejemplo que una buena descripción | pedido-service.md |
references/ | Documentación de referencia. Podría ser la documentación oficial de Spring que ponemos aqui | spring-transactional.md |
scripts/ | Script en bash o python , etc que ejecuta el skill para hacer su tarea. Si algo se puede hacer con un script en vez de usar más tokens, es mejor crear un script. | sin-transaccion.py |
assets/ | Esquemas, XSD, imágenes, etc | errores.schema.json |
evals/ | Dentro hay carpetas con los test unitarios para probar el skill (cómo se hacen) | update-sin-filtrar/ |
Las que suele tener cada tipo de skill:
| Carpeta | Skill de conocimiento (k-) | Skill que hace (do-) |
|---|---|---|
SKILL.md | ✓ | ✓ |
<tema>.md | ✓ | |
agents/ | ✓ | |
templates/ | ✓ | ✓ |
examples/ | ✓ | |
references/ | ✓ | |
scripts/ | ✓ | ✓ |
assets/ | ✓ | ✓ |
evals/ | ✓ | ✓ |
La de conocimiento guarda lo que se sabe: temas, ejemplos y documentación. La que hace guarda lo que se ejecuta: subagentes, plantillas de lo que genera y scripts. Si una do- necesita las reglas, carga la k-; no las copia.
Para explicar la estructura de carpetas de un skill , lo vamos a hacer con un ejemplo de un skill que "sabe" como son los servicios en Spring Understanding @Service in Spring Boot: A Complete Guide with Examples
.claude/skills/k-servicios/
├── SKILL.md
├── transacciones.md
├── templates/
│ └── service-impl.md
├── examples/
│ └── pedido-service.md
├── references/
│ └── spring-transactional.md
├── scripts/
│ └── sin-transaccion.py
└── assets/
└── errores.schema.json
La skill que crea un servicio a partir de un requisito de specs/. Las reglas de los servicios no están aquí: las carga de k-servicios.
.claude/skills/do-crear-servicio/
├── SKILL.md
├── agents/
│ └── verificador.md
├── templates/
│ └── service-test.md
└── scripts/
└── sin-test.py
En el fichero SKILLS.md está toda la explicación/descripción de lo que debe saber o hacer el skill, sin embargo no es adecuado tener ficheros demasiado largos. Por ese motivo están los ficheros <tema>.md que son simplemete secciones del fichero SKILLS.md y que se referencian desde SKILLS.md.
El motivo de hace esto es para ahorrar contexto. A veces un skill trata de varios temas relacionados. Por ejemplo, si vamos a cear un CRUD, podríamos tener un skill que sepa hacer CRUDs y en ese caso hablaría sobre controladores, servicios y repositorios. Cuando la IA está programando el controlador no necesita saber como se hace un servicio o un repositorio.
La description del frontmatter (cómo es) y la frase que va justo después del H1 se parecen, pero el modelo las lee en momentos distintos:
description | Frase de entrada | |
|---|---|---|
| Cuándo la lee | Siempre: está en contexto junto con las de todas las skills | Solo cuando la skill ya está cargada |
| Para qué | Decidir si carga la skill | Saber qué es y cómo actuar |
| Qué dice | Qué es y cuándo usarla, con las palabras que escribiría el usuario | En las k-, qué cubre y quién la usa. En las do-, el rol y qué transforma en qué |
--- name: do-crear-servicio description: Crea un servicio de Pedidos con su test a partir de un requisito de specs/. Usar cuando se pida crear, añadir o generar un servicio o una clase *Service. --- # do-crear-servicio Eres un desarrollador del servidor: conviertes un requisito de `specs/` en un `*Service` con su test.
La frase de entrada es imprescindible cuando la skill se ejecuta sin pasar por la description:
context: fork: el cuerpo del SKILL.md es el prompt del subagente. Si no fija el rol, el subagente no lo tiene./do-crear-servicio: se carga directamente, sin que la description haya servido para elegirla.description, sobra. Si da el rol o dice quién la usa, se queda.
La tabla índice del SKILL.md (cómo es) va justo después de la frase de entrada, antes de cualquier otra sección, y tiene todos los ficheros:
evals/ y assets/ van como una sola fila de carpeta: nadie los lee como instrucciones.
✅ En la Fase 2, copia `templates/service-impl.md` y rellena los huecos. ❌ Ver también `templates/service-impl.md`. (no dice cuándo)
.md de más de 100 líneas lleva su propio ## Índice en las primeras 40 líneas. El modelo a veces lee solo el principio de un fichero largo: si el índice está abajo, no sabe qué hay.
--- name: k-servicios description: Convenciones de los servicios de Pedidos (transacciones, validación, errores de negocio). Usar al escribir, revisar o probar una clase *Service. --- # k-servicios Reglas de las clases `*Service` del servidor. La cargan `do-crear-servicio` y `do-revisar-pr`. ## Índice | Fichero | Qué contiene | |-----------------------------|----------------------------------------| | `transacciones.md` | Qué métodos son transaccionales y cómo | | `templates/service-impl.md` | Esqueleto de un servicio nuevo | ## 1. Conceptos clave <vocabulario del dominio: agregado, error de negocio...> ## 2. Convenciones del proyecto <solo lo propio del proyecto, no lo del framework> ## 3. Patrones recomendados <plantillas literales, o punteros a templates/> ## 4. Ejemplos ✅/❌ <casos correctos e incorrectos, cada ❌ con su porqué> ## 5. Anti-patrones <lo que no se hace nunca y por qué>
name. Y nada por debajo de ####: si hace falta un quinto nivel, la estructura está mal.Sigue la estructura de los comandos de Spec Kit:
--- name: do-crear-servicio description: Crea un servicio de Pedidos con su test a partir de un requisito de specs/. Usar cuando se pida crear, añadir o generar un servicio o una clase *Service. --- # do-crear-servicio Eres un desarrollador del servidor: conviertes un requisito de `specs/` en un `*Service` con su test. ## Índice | Fichero | Qué contiene | |-----------------------------|-----------------------------------------| | `templates/service-test.md` | Esqueleto del test del servicio | | `agents/verificador.md` | Rol del subagente que comprueba el test | | `scripts/sin-test.py` | Lista los requisitos sin test | | `evals/` | Casos de prueba de la skill | ## Formato de entrada ```text $ARGUMENTS ``` You **MUST** consider the user input before proceeding (if not empty). Se espera el identificador del requisito (`R-12`) y, opcionalmente, el nombre del servicio. ## Outline 1. **Leer** el requisito (Fase 1). 2. **Escribir** el servicio y su test (Fase 2). 3. **Comprobar** que el requisito tiene test y pasa (Fase 3). **STOP conditions**: - No hay ningún requisito con ese identificador → **ERROR** y detente. - El servicio ya existe → **STOP** y pregunta antes de sobrescribirlo. ## 1. Fase 1 — Leer el requisito 1. Busca el identificador en `specs/`. 2. Carga la skill `k-servicios`. ## 2. Fase 2 — Escribir el servicio 1. Escribe el servicio con la plantilla de `k-servicios`. 2. Copia `templates/service-test.md` y rellena los huecos, con el identificador del requisito en el nombre del test. ## 3. Fase 3 — Comprobar 1. Ejecuta `python3 .claude/skills/do-crear-servicio/scripts/sin-test.py specs/ src/test/java`. 2. Lanza un subagente con model: haiku que lea `agents/verificador.md` y pásale `requisito` y `ruta_test`. 3. Ejecuta `./mvnw -pl servidor test`. **LIMIT**: máximo 3 vueltas de corrección; si sigue fallando, avisa con lo que queda. ## Quick Guidelines - Un servicio por agregado. - Ningún requisito sin su test. - Si el requisito es ambiguo, pregunta: no lo interpretes.
Las secciones, en este orden:
## Formato de entrada: un bloque text con $ARGUMENTS, que Claude Code sustituye por lo que escribes detrás de /do-crear-servicio. La línea en inglés es la de Spec Kit, tal cual, y la siguiente dice qué argumentos espera.## Outline: las fases numeradas, un verbo cada una, y al final las STOP conditions: cuándo aborta (ERROR) y cuándo para a preguntar (STOP).## Quick Guidelines: lo esencial en 10 puntos como máximo, al final del cuerpo.El cuerpo va en español, pero las palabras que marcan una orden van en inglés y en negrita: el modelo les da más peso que a «debes» o «es importante».
| Palabra | Para qué |
|---|---|
MUST / MUST NOT | Obligación o prohibición absoluta |
CRITICAL | Lo que el modelo suele hacer mal aunque se le diga |
STOP | Para y pregunta al usuario |
ERROR | Aborta con un mensaje |
LIMIT | Un número máximo: preguntas, vueltas, ficheros |
Solo en lo que de verdad no puede fallar. El resto, en imperativo y en segunda persona: «lee», «valida», no «podrías leer».
Una skill que escribe un fichero termina esa fase con un checklist que el modelo repasa antes de dar el fichero por bueno, y un LIMIT de vueltas para no quedarse corrigiendo sin fin:
### Checklist del servicio - [ ] ¿Cada método público valida su entrada? - [ ] ¿Cada requisito de `specs/` tiene un test con su identificador? **MUST NOT** dar el servicio por terminado con algún punto sin cumplir. **LIMIT**: máximo 3 vueltas de corrección; si sigue fallando, avisa con lo que queda.
Si una fase delega en un subagente (comprobar, revisar, juzgar), su rol va en un fichero de agents/, y el SKILL.md dice cuándo lanzarlo y qué le pasa:
✅ Lanza un subagente con model: haiku que lea `agents/verificador.md` y pásale `requisito` y `ruta_test`. ❌ Lanza un subagente que lea `agents/verificador.md`. (no dice qué le pasa ni con qué modelo)
Todos los ficheros de agents/ tienen las mismas secciones, en este orden:
# Verificador Comprueba que un requisito tiene su test y que el test prueba lo que pide el requisito. ## Rol Revisas el trabajo de otro sin haberlo visto hacer. No le das la razón por haberlo intentado. ## Entradas Te llegan en el prompt: - `requisito`: identificador del requisito en `specs/` (`R-12`). - `ruta_test`: el fichero de test que hay que comprobar. ## Proceso 1. Lee el requisito en `specs/`. 2. Lee el test y busca el identificador en su nombre. 3. Comprueba que cada condición del requisito tiene su aserción. ## Criterios - OK cuando: el test cita el requisito y comprueba todas sus condiciones. - Fallo cuando: falta el identificador o alguna condición no tiene aserción. - En la duda: fallo. ## Salida La primera línea es exactamente `PASS R-12` o `FAIL R-12`; debajo, una línea por condición sin probar. ✅ `FAIL R-12` / `Sin aserción: el pedido enviado no se puede cancelar.` ❌ `Parece que el test está bastante bien.` (el que lo lanza no puede comparar eso) ## Pautas - **MUST NOT** modificar el test: solo dice qué falta.
SKILL.md, así que no lo cita («ver SKILL.md §2»). Todo lo que usa le llega en ## Entradas.PASS/FAIL) que la skill compara tal cual, no un texto libre.model: haiku. El que juzga o diseña se queda con el modelo principal.fork. El fork hereda toda la conversación: el verificador ve razonar al que escribió el código y le da la razón. Además ignora el model.
Una skill de procedimiento no lanza la siguiente cuando decides tú cuándo se sigue: termina diciendo la orden exacta y para.
✅ Servicio creado. Siguiente paso: `/do-revisar-pr`. **STOP**. ❌ Servicio creado. Ahora lanzo do-revisar-pr. (te quita la revisión de lo generado)
Lo que escribes detrás de /do-… llega entero en $ARGUMENTS, el bloque de ## Formato de entrada (ver la estructura). Si es un solo valor (R-12), basta con lo que ya hay. Pero muchas skills reciben varias piezas, como la /test de Despliegue y proyecto:
/do-test unit create PedidoService /do-test api create Pedido: alta válida, sin cliente, cliente que no existe /do-test e2e repair
En ese caso, el ## Formato de entrada describe el formato pieza a pieza: qué valores admite, si es obligatoria y qué se hace si falta. Las palabras fijas van primero y el texto libre siempre al final, porque es lo único que puede llevar espacios:
--- name: do-test description: Crea o repara los tests unitarios, de arquitectura, de API o E2E. Usar cuando se pida escribir tests, generarlos o arreglar los que fallan. argument-hint: <unit|arch|api|e2e> <create|repair> [clase, reglas o escenarios] --- # do-test Eres el responsable de los tests: los creas a partir del código o de los escenarios y reparas los que fallan. ## Formato de entrada ```text $ARGUMENTS ``` You **MUST** consider the user input before proceeding (if not empty). El formato es `<tipo> <verbo> [resto]`: - `tipo`: `unit`, `arch`, `api` o `e2e`. Obligatorio. - `verbo`: `create` o `repair`. Obligatorio. - `resto`: todo lo que va detrás del verbo, tal cual. - `unit create`: una clase o un paquete. Si no hay, las clases de `domain` sin tests. - `arch create`: las reglas de arquitectura, en castellano. - `api create` y `e2e create`: los escenarios. Obligatorio. - `repair`: no lleva. **STOP conditions**: - Falta el tipo o el verbo, o no es uno de los valores → **ERROR** con la forma de uso y detente. - `api create` o `e2e create` sin escenarios → **STOP** y pide los escenarios.
argument-hint: lo que enseña el autocompletado al escribir /do-test. Así no hay que recordar el orden de las piezas.resto: se explica para cada combinación, porque significa una cosa distinta según el verbo.$0, $1… para coger cada pieza. Claude Code los parte por espacios, así que el texto libre (Pedido: alta válida, sin cliente) llega troceado. Y si falta un argumento, el $2 llega al modelo escrito tal cual. Coge siempre $ARGUMENTS entero y deja que lo parta el modelo con el formato que le has dado.
$ARGUMENTS se sustituye en todo el fichero, no solo en Formato de entrada. Si una skill tiene que hablar del placeholder, como k-skill, no puede escribirlo junto: lo cuenta partido («$ seguido de ARGUMENTS»). Escrito tal cual, al cargarla aparece en su lugar lo que hayas escrito tú.
Cuando una skill o un subagente de agents/ revisa algo, la primera línea es el resultado, una sola palabra (Puede ser la que queramos):
PASS: no hay problemas. No lleva nada más.FAIL: hay problemas, y debajo va una línea por problema.Ahora lo normal es que el agente nos retorne la lista de problemas que nos ha encontrado. Esa lista obviamente debe ser texto, así que podría ser un JSON , un XML, etc. Pero pensar que esos formatos son demasiado estrictos, por lo que se gastarán tokens en que tenga alguno de esos formato y además puede cometer errores. Por ello es mejor un formato sencillo y facil de leer.
Mi recomendación es simplemente columnas separadas por ":" con un formato libre al final.
Ejemplos de ellos podrían ser:
| Formato | Cuándo |
|---|---|
fichero:linea:descripcion | El problema está en una línea |
fichero:inicio-fin:descripcion | Abarca varias líneas: un método, un bloque |
fichero:descripcion | Afecta al fichero entero |
fichero:linea:tipo:descripcion | En una línea, con su tipo |
fichero:inicio-fin:tipo:descripcion | En varias líneas, con su tipo |
fichero:tipo:descripcion | En el fichero entero, con su tipo |
paquete.Clase.metodo:descripcion | Es de un método: com.tienda.PedidoService.crear |
paquete.Clase:descripcion | Es de la clase entera |
paquete.Clase.metodo:tipo:descripcion | De un método, con su tipo |
requisito:descripcion | Es de un requisito de specs/: R-12 |
Según lo que haga cada agente debes elegir el formato que más se acople a tu problema.
Lo mismo pasa con el tipo. A modo de ejemplo te indico posibles valores:
| Agente | Valores | Qué miden |
|---|---|---|
Codex (codex review) | P0, P1, P2, P3 | Prioridad: P0 bloquea el despliegue, P1 es urgente |
pr-review-toolkit (plugin de Claude Code) | Critical, Important | Gravedad: arreglar antes del merge o conviene arreglarlo |
skill-reviewer (plugin de Claude Code) | critical, major, minor | Gravedad |
claude-security (plugin de Claude Code) | CRITICAL, HIGH, MEDIUM, LOW | Gravedad de una vulnerabilidad |
| CodeRabbit | Critical, Major, Minor, Trivial, Info | Gravedad |
Potential issue, Refactor suggestion, Nitpick | Clase de comentario: fallo, mejora o detalle sin importancia | |
code-reviewer (plugin de Claude Code) | Un número de 0 a 100 | Confianza en que el problema es real: solo informa de los que pasan de 80 |
Ahora que hemos visto el formato, veamos como decirselo al agente para que retorne ese formato.Hay que tener una sección titulada "Formato de Salida" con el siguiente formato
## Formato de Salida La primera línea es `PASS` o `FAIL`. Con `PASS` no se escribe nada más. Con `FAIL`, debajo, una línea por problema con el formato `fichero:linea:tipo:descripcion`: - `fichero` es donde se ha encontrado el problema. La ruta es relativa al proyecto. - `linea` es un número (`42`) o un rango (`50-71`). Si el problema es del fichero entero, no lleva `linea`: `fichero:tipo:descripcion`. - `tipo` es `CRITICAL`, `MAJOR` o `MINOR`. - `descripcion`es la descripción del problema que ha encontrado. Es texto libre pero si hay retornos de carro se deben escapar para que solo sea una línea. **MUST NOT** escribir nada más antes ni después.
Una revisión sin problemas:
PASS
do-revisar-pr, con tipo (fichero:linea:tipo:descripcion, fichero:inicio-fin:tipo:descripcion y fichero:tipo:descripcion):
FAIL src/main/java/com/tienda/PedidoService.java:42:CRITICAL:no comprueba que el cliente exista src/main/java/com/tienda/PedidoService.java:50-71:MINOR:crear() valida, calcula el total y guarda specs/pedidos.md:MAJOR:R-12 no tiene ningún test
Una skill que revisa los tests, sin tipo (fichero:linea:descripcion, fichero:inicio-fin:descripcion y fichero:descripcion):
FAIL src/test/java/com/tienda/PedidoServiceTest.java:28:el nombre del test no cita el requisito src/test/java/com/tienda/PedidoServiceTest.java:30-45:escribe 21 en vez de leer el IVA del código de producción src/test/java/com/tienda/ClienteServiceTest.java:no prueba ningún caso de error
Una skill que revisa el diseño de las clases, por método (paquete.Clase.metodo:descripcion, paquete.Clase:descripcion y requisito:descripcion):
FAIL com.tienda.domain.PedidoService.crear:valida, calcula el total y guarda: son tres métodos com.tienda.domain.PedidoService:depende de ClienteRepository, que es de otro agregado R-12:ningún método lo implementa
Esta skill tiene cinco fallos de estructura. Encuéntralos y di cómo se arregla cada uno.
.claude/skills/K_Controladores/
├── skill.md
├── validacion/
│ └── reglas.md
├── agents/
│ └── revisor-agent.md
├── templates/
│ └── controller-template.md
└── examples/
└── pedido-controller.md
Escribe la skill de conocimiento k-tests con las convenciones de los tests de tu proyecto: frontmatter, frase de entrada, tabla índice y las cinco secciones. Pon en templates/ el esqueleto de una clase de test.
Escribe la skill de procedimiento do-crear-test, que recibe un identificador de requisito y escribe su test cargando k-tests. Tiene que tener Formato de entrada, Outline con sus STOP conditions, una sección por fase y Quick Guidelines. Pruébala con /do-crear-test R-3.