
Un skill es una carpeta que contiene un SKILL.md: un frontmatter YAML (name, description) e instrucciones en Markdown, más scripts y referencias que se cargan bajo demanda. Solo la descripción permanece en el contexto todo el tiempo, y se recorta, lo que la convierte en el único activador que importa. La misma carpeta funciona en Claude Code, Codex, Copilot y OpenCode, siempre que se coloque en el directorio correcto.
Un skill es una carpeta que contiene un archivo SKILL.md. Escribirlo es la parte fácil. El resto exige saber dónde colocarlo para que el agente lo encuentre, comprobar que se activa de verdad, y medir lo que cuesta el resto del tiempo. Esta guía hace las tres cosas, sobre un skill construido y ejecutado para la ocasión.
¿Qué es exactamente un skill?
El formato Agent Skills lo creó Anthropic y luego se publicó como estándar abierto, la especificación vive hoy en agentskills.io. Se resume en poco: una carpeta, un SKILL.md obligatorio, y lo que quieras al lado.
regex-verifiee/
├── SKILL.md # obligatorio: frontmatter YAML + instrucciones en Markdown
├── scripts/ # opcional: código que ejecuta el agente
├── references/ # opcional: documentación que se carga bajo demanda
└── examples/ # opcional: plantillas, conjuntos de datos
├── scripts/ # para todos tus proyectos
cp -R regex-verifiee mon-projet/.claude/skills/ # versionado con el repositorio
├── references/ # optionnel : de la documentation chargée à la demande
└── examples/ # optionnel : gabarits, jeux de donnéesEl frontmatter es corto y está limitado. name: 64 caracteres como máximo, solo minúsculas, cifras y guiones, sin guion al principio ni al final, sin guion doble, y debe ser idéntico al nombre de la carpeta que lo contiene. description: obligatorio, 1.024 caracteres como máximo, dice qué hace el skill y cuándo usarlo. Tres campos opcionales completan el conjunto: license, compatibility (500 caracteres) y metadata. Un sexto, allowed-tools, está marcado como experimental en la especificación.
El mecanismo que hace interesante todo esto se llama divulgación progresiva, en tres niveles. Al arrancar, el agente solo carga el name y la description de cada skill, la especificación apunta a un centenar de tokens. Cuando una tarea encaja, lee el cuerpo del SKILL.md (menos de 5.000 tokens recomendados, 500 líneas como máximo). Solo entonces, si lo necesita, abre los archivos de scripts/, references/ o assets/. La entrada de ingeniería de Anthropic del 16 de octubre de 2025 lo formula al revés: cuida el name y la description, porque es en base a eso, y solo a eso, como el agente decide activar el skill.
Un skill que nunca se activa cuesta por tanto igualmente su descripción, en cada sesión, en todas las ventanas de contexto. Es exactamente lo que mide el comando /skill-doctor de Claude Code, y es la primera partida de gasto que se examina en la experiencia de Spotify con la factura de tokens.
¿Dónde busca cada agente los skills?
Es la parte que nadie describe bien, porque cambia de una herramienta a otra. Aquí están las rutas tal como figuran en la documentación de cada editor, consultada el 7 de septiembre de 2026.
| Herramienta | Proyecto | Usuario |
|---|---|---|
| Claude Code | .claude/skills/<nom>/SKILL.md | ~/.claude/skills/<nom>/SKILL.md |
| Codex | .agents/skills/ (y .codex/skills/, ver más abajo) | $CODEX_HOME/skills, ~/.agents/skills |
| GitHub Copilot | .github/skills, .claude/skills, .agents/skills | ~/.copilot/skills, ~/.agents/skills |
| OpenCode | .opencode/skills, .claude/skills, .agents/skills | ~/.config/opencode/skills, ~/.claude/skills, ~/.agents/skills |
De ahí se derivan dos cosas. .agents/skills se está convirtiendo en la ruta neutra común, Codex, Copilot y OpenCode la leen los tres. Y tanto Copilot como OpenCode leen también .claude/skills, la carpeta de Claude Code funciona de facto como formato de intercambio. Una misma carpeta de skill puede así servir a varios agentes sin duplicarse. En cuanto a superficies, GitHub anuncia los skills para el agente en la nube, la revisión de código, Copilot CLI, la aplicación GitHub Copilot y el modo agente de VS Code y de los IDE de JetBrains.
El 7 de septiembre de 2026, el escaparate de agentskills.io registra 46 productos compatibles, desde Cursor hasta Goose, pasando por Junie, Kiro, Roo Code, Laravel Boost, OpenCode y OpenClaw.
Construir un skill que sirva: regex-verifiee
Un buen skill codifica un procedimiento que repites y que el agente se salta cuando no se lo impones. El caso elegido aquí: las expresiones regulares. Un agente te suelta una regex en tres segundos, sin ejecutarla nunca sobre un contraejemplo. El skill regex-verifiee prohíbe esa respuesta.
El SKILL.md, completo en el frontmatter y en el comienzo del cuerpo:
---
name: regex-verifiee
description: Écrire une expression régulière et la prouver avant de la livrer. À utiliser dès qu'une demande porte sur une regex, une expression régulière, une validation de format (code postal, SIRET, IBAN, e-mail, téléphone, slug, plaque), un preg_match, un preg_replace ou un RegExp. Impose un fichier de cas valides et invalides, son exécution dans le moteur cible (Node et PHP), puis la livraison regex + tableau de cas + limites.
---
# Regex vérifiée
Une regex qui n'a jamais tourné sur ses contre-exemples n'est pas une regex, c'est une intuition.
Suivez ces cinq étapes dans l'ordre. Ne sautez pas l'étape 4.
## Procédure
1. **Cadrer.** Demandez, ou décidez explicitement : le moteur (JavaScript, PCRE/PHP, POSIX), la
chaîne testée (déjà nettoyée ou brute), et si la valeur peut être vide.
2. **Proposer.** Écrivez la regex ancrée et, en une phrase par groupe, ce que chaque partie accepte.
3. **Écrire les cas.** Créez un fichier JSON : au moins six valides et six invalides. Les invalides
doivent inclure les pièges de `references/cas-types.md` pour le type de donnée concerné.
4. **Exécuter.** Lancez le script sur les deux moteurs et collez la sortie brute dans la réponse.
5. **Livrer.** Réponse finale = la regex + le tableau de cas produit par le script + les limites.La descripción es deliberadamente charlatana en vocabulario de activación: «regex», «expresión regular», «código postal», «SIRET», «preg_match», «RegExp». Son las palabras que teclea quien lee. Escríbela en la lengua en la que te hablan, no en la de la documentación.
La carpeta contiene además un archivo de casos en formato JSON, dos ejecutores (uno en Node, otro en PHP) que leen el mismo archivo, y una referencia references/cas-types.md que enumera los contraejemplos por tipo de dato. El archivo de casos tiene este aspecto:
{
"name": "code postal français",
"engine": "both",
"pattern": "^(?:0[1-9]|[1-8]\\d|9[0-8])\\d{3}$",
"flags": "",
"valid": ["01000", "20000", "62500", "75001", "97400", "98000"],
"invalid": ["", "00000", "99999", "7500", "750011", "75 001", "2A000", " 75001", "75001\n"]
}Los dos ejecutores muestran la misma tabla y devuelven un código de salida distinto de cero en cuanto falla un caso. Es ese código de salida el que hace el trabajo: el agente no puede darse por satisfecho con un comando en error.
Primera sorpresa, obtenida al lanzar yo mismo el arnés de pruebas antes incluso de enchufar un agente: la misma regex no da el mismo veredicto en los dos motores.
$ node scripts/verifier.mjs examples/code-postal-fr.json
moteur : node v22.23.2
regex : /^(?:0[1-9]|[1-8]\d|9[0-8])\d{3}$/
...
"75001\n" false false ok
15 cas, 0 échec(s)
$ php scripts/verifier.php examples/code-postal-fr.json
moteur : PHP 8.4.19, PCRE 10.47 2025-10-21
regex : /^(?:0[1-9]|[1-8]\d|9[0-8])\d{3}$/
...
"75001\n" false true ECHEC
15 cas, 1 échec(s)En PCRE, $ acepta un salto de línea final, en JavaScript, no. Un campo de formulario que llega con un \n pegado al final pasa entonces la validación de PHP y falla la de JavaScript, con la misma expresión escrita en los dos archivos. Las dos correcciones, ambas verificadas aquí: el modificador D en PHP (preg_match('/^\d{5}$/D', "75001\n") devuelve 0), o un anclaje portable (?![\s\S]) en lugar de $, que pasa los quince casos en los dos motores.
Probarlo con Codex sin tocar ~/.codex
La documentación de Codex describe una pila de raíces: $CWD/.agents/skills, las carpetas superiores, $REPO_ROOT/.agents/skills, luego $HOME/.agents/skills, /etc/codex/skills y los skills que vienen con la CLI. Dicho de otro modo, existe un skill de proyecto: no hace falta escribir en ~/.codex/skills ni en ~/.codex/config.toml para probarlo.
Queda comprobar lo que hace realmente el binario. Para eso, Codex expone un comando de depuración que muestra el prompt tal como lo recibe el modelo, sin llamar al modelo:
$ mkdir -p demo-projet/.codex/skills
$ cp -R regex-verifiee demo-projet/.codex/skills/
$ cd demo-projet && codex debug prompt-input "test"
### Skill roots
- `r0` = `/…/demo-projet/.codex/skills`
- `r1` = `/Users/gekkode/.codex/skills`
- `r2` = `/Users/gekkode/.agents/skills`
- `r3` = `/Users/gekkode/.codex/skills/.system`
- `r4` … `r10` = caches de plugins
### Available skills
- regex-verifiee: Écrire une expression régulière et la prouver avant de la livrer. À utiliser dès qu'une deman (file: r0/regex-verifiee/SKILL.md)El skill se ve, desde <projet>/.codex/skills, un camino que la documentación no menciona, pero que el binario sí escanea, en primera posición. Al colocar un segundo skill de prueba en <projet>/.agents/skills, apareció una raíz r11 con esa ruta: las dos funcionan, y la carpeta .codex/ va primero.
Llega la prueba real. Mismo prompt, mismo modelo, misma máquina, con pocos minutos de diferencia: una vez en el proyecto que contiene el skill, otra en una carpeta vacía.
codex exec -m gpt-6-astra -s workspace-write --skip-git-repo-check \
"Dans un formulaire PHP, je dois valider le code postal saisi par le visiteur. Donne-moi l'expression reguliere a utiliser."Sin el skill: 19 segundos, cero comandos ejecutados, y esta respuesta, preg_match('/\A[0-9]{5}\z/', $codePostal), con una frase diciendo que la expresión comprueba el formato y no la existencia del código postal. Pasada por el arnés, esta regex falla en dos casos de quince: acepta 00000 y 99999.
Con el skill: 106 segundos, diez comandos ejecutados. Codex leyó el SKILL.md, luego los dos scripts, luego references/cas-types.md, la divulgación progresiva completa, nivel por nivel. Después escribió su propio archivo de casos (dieciocho casos, entre ellos "75001\n00000" y "2a000", tomados de la referencia), lanzó los dos ejecutores, y entregó esto:
$codePostal = $_POST['code_postal'] ?? '';
$valide = is_string($codePostal)
&& preg_match('/\A(?:0[1-9]|[1-8][0-9]|9[0-8])[0-9]{3}\z/', $codePostal) === 1;Con, debajo, las dos tablas de dieciocho casos y una sección «límites». Fíjate en que no usó la misma expresión en los dos motores. \A … \z para PCRE, ^ … (?![\s\S]) para JavaScript. El skill nunca le dijo que hiciera eso, lo dedujo al ejecutar los casos.
Un skill de unas sesenta líneas ha transformado así una respuesta de tres segundos, equivocada en dos casos, en un procedimiento de dos minutos cuyo resultado es verificable. La activación se produjo sola, a partir de la descripción: el prompt no contiene ni la palabra «skill», ni el nombre regex-verifiee. En Codex también se puede forzar con $regex-verifiee en el prompt, en Claude Code, con /regex-verifiee.
Cuánto cuesta una descripción, y por qué se recorta
Durante la ejecución, Codex emitió una advertencia que no esperaba:
Skill descriptions were shortened to fit the skills context budget. Codex can still see every skill, but some descriptions are shorter. Disable unused skills or plugins to leave more room for the rest.
Comprobación hecha con un skill de prueba cuya descripción es una tira de trescientos caracteres conocidos: en esta máquina, con 146 skills instalados, cada descripción se recorta a 94 caracteres. Mi descripción de 422 caracteres le llega entonces al modelo amputada en dos tercios, en mitad de la palabra «demande». Todo lo que viene después, «SIRET», «IBAN», «preg_match», «RegExp», no sirve de nada para la activación.
El presupuesto se puede ajustar. Codex acepta una clave skills.max_context_tokens, que se puede pasar como sobrecarga sin escribir en el archivo de configuración:
codex debug prompt-input -c skills.max_context_tokens=16000 "test"| Presupuesto | Longitud de descripción conservada | Tamaño del bloque de skills |
|---|---|---|
| 2.000 | 40 caracteres | 8.202 caracteres |
| 4.000 | 54 caracteres | 16.492 caracteres |
| 5.000 | 82 caracteres | 20.482 caracteres |
| predeterminado | 94 caracteres | 22.230 caracteres |
| 8.000 | 198 caracteres | 32.295 caracteres |
| 16.000 | 300 caracteres (sin recorte) | 40.201 caracteres |
De ahí salen dos reglas. Pon las palabras de activación en los noventa primeros caracteres de la descripción, el resto es un extra. Y ten presente que cuantos más skills instalas, más recortas la descripción de todos los demás. El catálogo ocupaba aquí 22.230 caracteres de contexto, en cada sesión, para 146 skills de los que solo uso un puñado. Desinstalar es mejor que aumentar el presupuesto.
Claude Code aplica el mismo principio con cifras publicadas. Su presupuesto de listado equivale al 1 % de la ventana de contexto del modelo, ajustable con skillListingBudgetFraction o con la variable de entorno SLASH_COMMAND_TOOL_CHAR_BUDGET. Cada entrada está en cualquier caso limitada: description y when_to_use concatenados se cortan a 1.536 caracteres, límite ajustable con skillListingMaxDescChars. Y cuando el listado se desborda, la documentación es explícita sobre el orden de sacrificio: Claude Code elimina primero las descripciones de los skills que menos invocas. El nombre, en cambio, se queda siempre en el listado.
Las dos herramientas ofrecen la misma escapatoria: desactivar en vez de inflar el presupuesto. En Claude Code, el ajuste skillOverrides acepta cuatro estados por skill, on, name-only (el nombre sin la descripción), user-invocable-only y off, y el comando /skills los escribe por ti en .claude/settings.local.json. En Codex, un bloque en ~/.codex/config.toml:
[[skills.config]]
path = "/chemin/vers/le/skill/SKILL.md"
enabled = falseCargar y distribuir el mismo skill en Claude Code
La carpeta no cambia. Dos ubicaciones, según que el skill te siga a todas partes o pertenezca al repositorio:
cp -R regex-verifiee ~/.claude/skills/ # pour tous vos projets
cp -R regex-verifiee mon-projet/.claude/skills/ # versionné avec le dépôtLa documentación de Claude Code añade campos de frontmatter que no están en la especificación. disable-model-invocation: true impide la activación automática y reserva el skill a una llamada manual con /nom, el ajuste adecuado para todo lo que hace push, despliega o borra. allowed-tools concede permisos de herramientas solo para el turno de conversación que invoca el skill, y el permiso decae en el mensaje siguiente. user-invocable: false reserva el skill al modelo.
Para distribuir el skill a un equipo, el empaquetado es un plugin: un manifiesto .claude-plugin/plugin.json en la raíz, el skill en la carpeta skills/, y un archivo .claude-plugin/marketplace.json que declara la marketplace. La instalación se hace después con /plugin marketplace add compte/depot y luego /plugin install mon-plugin@ma-marketplace, y /reload-plugins recarga sin salir de la sesión.
Queda la pregunta incómoda. ¿Tu skill se activa, y sirve para algo? Claude Code responde a las dos mitades. /skill-doctor, que requiere la versión 2.1.252 o más reciente, lista los skills cargados, su número de invocaciones y su último uso, y señala los que nunca han servido, el informe se abre en la pestaña Stats del gestor de plugins, y se imprime en texto plano en modo -p. Y claude plugin eval, en acceso anticipado, automatiza exactamente la comparación que hice a mano más arriba. La ayuda del comando, en esta máquina, no deja lugar a dudas:
$ claude plugin eval --help
Run eval cases (evals/**/case.yaml or evals/**/prompt.md + graders/*.md) against
a plugin and report scored results.
--ablation <mode> Run a no-plugin baseline arm and report the score delta
(none | with-without; default: with-without …)
--runs <n> Override per-case runs (default: case.runs ?? 3)
--threshold <0..1> Exit 1 if any case score is below this threshold
--json Emit aggregate-result.json to stdout (for CI)Un caso de evaluación es una carpeta evals/<cas>/ que contiene un prompt.md, un prompt realista que sobre todo no nombra el skill, y correctores en graders/. La opción --ablation with-without repite cada caso con y sin el plugin y muestra la diferencia de puntuación: es la única forma honesta de demostrar que un skill aporta algo.
Compartir un skill, y comprobar los de los demás
Conviven tres circuitos de distribución. Un repositorio Git desnudo, que se clona en la carpeta correcta, el más simple y el más auditable. Un plugin, tanto para Claude Code como para Codex: en Codex, cada plugin vive bajo plugins/<nom>/ con un manifiesto .codex-plugin/plugin.json obligatorio y carpetas opcionales skills/, .app.json, .mcp.json. Y las marketplaces públicas: ClawHub, Skills.sh, SkillsMP.
Fíjate de paso en que el catálogo github.com/openai/skills, todavía citado por todas partes, está marcado como obsoleto y remite a github.com/openai/plugins. El skill de sistema $skill-installer, por su parte, sigue instalando en $CODEX_HOME/skills/<nom>.
El tercer circuito exige desconfianza. La auditoría ToxicSkills publicada por Snyk el 5 de febrero de 2026 pasó por el tamiz 3.984 skills de ClawHub y de skills.sh: 1.467 de ellos (36,82 %) presentan al menos un fallo de seguridad, y 534, el 13,4 % del total, al menos un fallo crítico. Se confirmaron setenta y seis cargas maliciosas mediante revisión humana: robo de credenciales, instalación de puertas traseras, exfiltración de datos, ocho de esos skills seguían en línea el día de la publicación. Todas las cargas confirmadas contienen código malicioso, y el 91 % añade además inyección de prompt.
Un skill es texto que tu agente va a seguir, más scripts que ejecutará con tus permisos. Antes de instalar uno, lee entero el SKILL.md, lee cada archivo de scripts/, busca llamadas de red y cadenas codificadas en base64, y rechaza cualquier skill que pida una clave de API o un token. Los mismos reflejos que para el sandbox y los permisos de un agente de código.
¿Skills o MCP?
Los skills y MCP no responden a la misma necesidad. Un skill aporta un procedimiento y un saber hacer, en Markdown, sin proceso, sin red, sin autenticación. Un servidor MCP aporta herramientas y datos: habla con una base de datos, con una API, con un sistema de archivos remoto, con las credenciales correspondientes.
La prueba más rápida cabe en una frase. Si tu necesidad se escribe «procede así», es un skill. Si se escribe «ve a buscar esto» o «escribe esto en algún sitio», es un servidor MCP. La diferencia de coste sigue la misma línea: un skill inactivo cuesta su descripción, unas pocas decenas de tokens, mientras que un servidor MCP conectado cuesta la definición de todas sus herramientas, permanentemente, en cada sesión.
Los dos combinan muy bien: un skill que indica en qué orden llamar a las herramientas de un servidor MCP suele ser lo mejor de los dos mundos. Es, además, la dirección que toma el propio protocolo, la revisión 2026-07-28 de la especificación MCP incluye un grupo de trabajo «Skills over MCP», cuyo objetivo es descubrir y consumir instrucciones estructuradas mediante MCP. Para la parte de servidor, la guía del servidor MCP en PHP toma el relevo.
Los cuatro errores que se repiten
Una descripción que describe el skill en lugar de decir cuándo usarlo. «Ayuda con las regex» no se activa nunca. Escribe las palabras que teclea el usuario, en su idioma, y ponlas al principio, por culpa del recorte medido más arriba.
Un SKILL.md de dos mil líneas. El cuerpo entero entra en el contexto al activarse. La especificación recomienda quedarse por debajo de 500 líneas y remitir el detalle a references/, que solo se carga si hace falta. En la prueba de arriba, Codex solo abrió cas-types.md en el momento de escribir sus casos.
Secretos dentro del skill. Un skill se comparte, se versiona, se publica. Una clave de API que se quede ahí olvidada acaba en un repositorio público. El skill lee una variable de entorno, no la contiene.
Amontonar skills «por si acaso». Cada skill instalado acorta la descripción de todos los demás y va royendo la ventana de contexto. Haz inventario de lo que nunca se ha activado y bórralo.
Lo que hay que recordar
- Un skill = una carpeta + un
SKILL.md(namede 64 caracteres como máximo,descriptionde 1.024 como máximo) + lo que quieras al lado. - Solo la descripción se carga de forma permanente, y se recorta: las palabras de activación van en los 90 primeros caracteres.
.agents/skillsen el proyecto, más.claude/skills, leído por Copilot y OpenCode: una misma carpeta sirve para varios agentes.- Un skill de proyecto se prueba sin instalar nada en casa:
<projet>/.codex/skills/para Codex,<projet>/.claude/skills/para Claude Code. - El buen skill impone un procedimiento verificable y un código de salida, no una instrucción de estilo.
- Lee de principio a fin cualquier skill instalado desde una marketplace: el 13,4 % de los auditados por Snyk tiene un fallo crítico.
Errores frecuentes
references/, que el agente solo abre si lo necesita.scripts/ código que va a ejecutar con tus permisos. Léelo todo antes, incluidos los scripts.

