DevOps
IA - Fundamentos y buenas prácticas en la creación de Skills
Dailos Rafael Díaz Lara DEV Community
2 views
Vamos a hablar de skills para agentes de IA y lo vamos a hacer a raíz de haber asistido hace unos días al taller online impartido por @mouredev sobre skills.
🎥 Vídeo completo en YouTube
El taller estuvo muy interesante, tanto que me quedé con ganas de más, así que me puse a investigar un poco, no tanto en lo que hacen y para qué sirven las skills, sino en las buenas prácticas a la hora de definirlas.
El resultado es este post donde trato de organizar las principales ideas que he ido reuniendo y ordenando. Espero que te sean tan útiles como lo ha sido para mi.
Sin más... empecemos.
🤓 Introducción
Las skills se emplean para automatizar los procesos repetitivos cuyo procedimiento puede ser descrito con un alto grado de definición.
La información dentro de una skill ha de estar perfectamente estructurada y afinada para que el modelo no pueda tener la más mínima posibilidad de inventarse resultados.
El contenido de una skill puede tener:
Prompt
Reglas
Herramientas
MCPs
Otras skills
etc.
Cuando arrancamos un agente, éste conoce las skills disponibles; ahora bien, las skills pueden ser invocadas manualmente por el desarrollador (invocación explícita), o de manera automática por parte del propio agente (invocación implícita), cuando le hemos informado de la disponibilidad de las mismas.
Cada skill que usemos, queda cargada en el contexto de la sesión en curso, por lo que es importante controlar su uso en exceso cuando no son necesarias.
💻 Creación de Skills
📍 Ubicación de las skills
Las skills las crearemos dentro del directorio ./.agents/skills (si son únicamente para el proyecto actual), o en ~/.agents/skills (si son globales para todos los agentes que se ejecuten en el equipo).
🔎 NOTA
Éste es el estándar entre la gran mayoría de los agentes pero por si acaso, siempre es interesante revisar cómo un agente en concreto trata las skills.
Por ejemplo, en Claude Code CLI, cuando creamos una skill manualmente en nuestro repo, aunque reiniciemos el agente, no la detectará. ¿Por qué? Pues porque para este agente hay que crearlas en ./.claude/skills. No es un problema con la skill o su definición, sino con dónde la busca Claude Code.
Cada skill deberá crearse dentro de un directorio específico para dicha skill. Por lo tanto, es imperativo que el nombre del directorio de la skill coincida con el nombre que le demos a la misma, ya que será el nombre por el cual dicha skill será invocada por el agente.
Además de esto, dentro de dicho directorio siempre debe existir el archivo SKILL.md, que contiene la definición de la skill en cuestión.
🎩 Encabezado de una skill
Toda skill ha de poseer un encabezado que la describirá. Este encabezado se identifica por el uso de los caracteres --- de apertura y cierre propios de Yaml.
⚠️ IMPORTANTE
A pesar de que la skill se define usando Markdown, el contenido de la cabecera de la skill ha de escribirse en Yaml.
El contenido de dicho encabezado ha de albergar los siguientes campos:
name (🔥 obligatorio)
Debe tener entre 1 y 64 caracteres alfanuméricos, en minúsculas y en formato kebab-case.
No puede empezar ni terminar con guión medio y en nigún caso puede contener dos o más guiones medios consecutivos (--)
Finalmente, ha de coincidir con el nombre del directorio donde se está definiendo la skill ya que será éste el que se emplee para invocar a la skill (/skill-name)
La RegEx de dicho nombre es la siguiente: ^[a-z0-9]+(-[a-z0-9]+)*$.
description (🔥 obligatorio)
Debe tener entre 1 y 1024 caracteres.
Ha de ser lo suficientemente específico como para que el agente sea capaz leer su contenido y determinar si es lo que el usuario está buscando.
Para ello, la descripción debe contener frases específicas, verbos o casos de uso concreto, por ejemplo: Use when the user asks to review code or optimize database queries.
license (opcional)
Se emplea para definir el contexto legal de uso de la skill o los permisos de uso de la misma.
A la hora de definir su valor, se considera buena práctica seguir el estándar de identificadores SPDX (Short-form License Identifiers).
Los valores más usuales suelen ser: MIT, Apache-2.0, GLP-3.0 y Proprietary o Commercial
version (opcional)
Contiene la cadena de caracteres que define el seguimiento semántico de las versiones de la skill, por ejemplo: 1.0.0.
Suele emplearse para configurar pipelines, actualizaciones de despliegues o el seguimiento en determinados ecosistemas.
context (opcional) inline | fork
Nos permite definir cómo se ejecuta la skill en relación al hilo de conversación principal del agente.
Este aspecto es importante a nivel de configuración de orquestación de memoria y el aislamiento de entornos por parte del agente cuando la skill es invocada.
Por defecto, si este campo no es definido, la skill se ejecuta en linea con la conversación en curso, sin embargo, existen valores que le podemos dar al campo para modificar este comportamiento:
inline (valor por defecto)
La skill se ejecuta directamente dentro de la ventana conversacional actual.
Las instrucciones, ejemplos y herramientas definidas dentro de SKILL.md son añadidas directamente al contexto actual y el modelo las retiene en su totalidad para ser usadas en posteriores conversaciones.
Se recomienda usar esta configuración cuando al arrancar múltiples tareas que han de trabajar de manera colaborativa, la skill deba conocer todo el historial, tono y referencias específicas que el usuario haya hecho para operar correctamente.
Con todo esto, si elegimos esta opción, hemos de establecer guardarraíles a nivel de descripción para que la skill sepa exactamente cuándo debe dar un paso atrás para recopilar información y luego volver a donde estaba.
fork (modo sub-agente o sandbox aislado)
En este modo, podríamos entender que se crea un "proceso hijo" metafórico donde el agente pausa temporalmente el hilo de conversación principal, copia la información relevante del estado actual y arranca un sub-agente aislado para procesar exclusivamente la tarea encomendada por la skill.
A nivel de memoria, el subagente creado no lee toda la memoria ni el historial de la conversación principal sino que previene que el modelo se distraiga de dicha conversación evitando desviaciones por mezcla de otras consultas.
A nivel de consumo de tokens, como no se coge el historial principal de conversación, sino una pequeña sección muy concreta, podemos reducir el volumen de tokens de entrada y obtener una ejecución más barata y rápida.
Una vez que la skill ha completado su tarea, ésta recopila, limpia y destila un resumen del resultado y lo inyecta en el hilo de la conversación principal antes de cerrar el "proceso hijo" donde ha estado operando.
Con todo esto, si elegimos esta opción, hemos de ser conscientes de que las instrucciones han de ser completamente auto-contenidas ya que la skill no tendrá acceso al historial completo de conversación.
Tabla comparativa
Funcionalidad / Comportamiento
context: inline (Default)
context: fork
Área de trabajo
Ventana de conversación principal
Subagente aislado
Visibilidad del historial
Historial completo preservado
Oculto (o fuertemente restringido)
Consumo de tokens
Alto (Crece con la longitud de la conversación)
Bajo (Optimizado para datos específicos de la skill)
Resultado obtenido
Continuo a medida que la conversación continua
Un resumen sencillo y estructurado
Caso de uso principal
Asistente interactivo (p.e., Copywriting)
Trabajos pesados en background (p.e., Code review)
compatibility (opcional)
Este campo actúa como una validación de entorno, asegurándose de que el equipo donde se está ejecutando la skill o el motor de ejecución, tiene las capacidades de hardware, paquetes de software o requisitos de motor LLM requeridos para ejecutar las instrucciones definidas dentro de la skill. Por ejemplo, podemos definir los requisitos de razonamiento mínimos del LLM, así como las restricciones del sistema operativo, los paquetes para la CLI o los binarios requeridos.
En caso de que el sistema escanee la skill y detecte un problema de compatibilidad, la skill se desactiva o es ocultada para prevenir errores en tiempo de ejecución.
Por ejemplo:
compatibility:
model: ">=gpt-4o"
os: "linux, darwin"
dependencies:
- "python>=3.10"
- "ffmpeg"
allowed-tools (opcional) (también conocido por allow-tools)
Este campo está definido por un listado de valores que permiten establecer o acotar estrictamente aquellas herramientas que están permitidas al agente para ser utilizadas cuando se ejecute la skill.
A la hora de definir el contenido de esta propiedad se ha de tener en mente el Principio del Mínimo Privilegio de manera que, si una skill necesita leer documentación local, no se le debe permitir ejecutar comandos de terminal.
Cuando una skill que posee esta propiedad definida se ejecuta, el agente automáticamente suspende/desactiva cualquier herramienta no especificada en el listado, de manera que incluso si el modelo alucinara e invocase alguna de las herramientas no permitidas, el orquestador del modelo la bloquearía.
Una de las principales ventajas de este campo es que previene el consumo excesivo a raíz del uso innecesario de herramientas caras o la ejecución de operaciones peligrosas (archivos, bases de datos, infraestructura, etc.), que no estén claramente autorizadas.
Por ejemplo:
allowed-tools:
- internet_browse
- read_local_file
- parse_json
disable-model-invocation (opcional) true | false
Este campo se emplea para configurar el nivel de "conciencia" que el modelo tiene sobre la existencia o no de la skill en cuestión.
Cuando este campo no se define o se pone a su valor por defecto (false), cuando el agente arranque la tendrá en su listado de skills disponibles y si el usuario dice Revisar los registros de mi servidor, el modelo analizará la descripción de la skill y si coincide con el objetivo de la petición, comenzará a ejecutar la skill.
En el caso de que esta opción se defina como true, el modelo ignorará por completo esta skill, independientemente del uso que se esté haciendo del agente. La única manera que hay de poder usarla es a través de la invocación explícita de dicha skill, es decir /skill-name.
Esta configuración es realmente interesante para flujos de trabajo destructivos, que apliquen cambios irreversibles o que conlleven un alto riesgo para el sistema, donde una interpretación errónea por parte del modelo puede acarrear la pérdida accidental de datos valiosos o modificaciones no autorizadas del sistema.
Por ejemplo:
name: wipe-database-cache
disable-model-invocation: true
metadata (opcional)
Este campo es un diccionario no estructurado diseñado para tareas específicas de desarrollo, donde podemos añadir información adicional referente a la skill.
Sirve como puente de comunicación entre diferentes plataformas, editores de código y frameworks, que necesitan una manera de definir información adicional relevante para cada cual, sin romper el estándar abierto de la definición de skills.
Uno de los principales usos que se le suele dar a este campo es para mostrar información de la skill en formato human-friendly en aplicaciones o herramientas que gestionan skills.
Por otro lado, cuando las skills no son públicas, este campo se puede usar para la trazabilidad de su desarrollo a nivel corporativo.
Por ejemplo:
metadata:
author: "Platform Security Team"
category: "DevOps / SRE"
icon: "shield-alert"
cost_center: "fintech-ops-99"
Algunos ejemplos completos de cabeceras de skill podrían ser los siguientes:
# Este ejemplo usa 'context: fork' para que se ejecute en un hilo seguro, con bajo consumo de tokens para realizar
# la validación pesada a nivel de backend. Además, como se ejecuta de manera autónoma, puede ser invocada de manera
# automática por parte del modelo he incluir las herramientas CLI necesarias para poder llevar a cabo su tarea.
---
name: kubernetes-manifest-validator
description: Use this skill when the user provides Kubernetes YAML files, Helm charts, or K8s deployment manifests and requests syntax validation, security linting, or API deprecation checks.
license: Apache-2.0
version: 2.4.1
context: fork
compatibility:
model: ">=gpt-4o"
os: "linux"
dependencies:
- "kubeconform>=0.6.0"
- "trivy>=0.45.0"
allowed-tools:
- read_local_file
- execute_terminal_command
- write_local_file
disable-model-invocation: false
metadata:
team: "SRE-Core"
environment: "staging-validation"
severity-tier: "medium"
---
---
# Este ejemplo usa 'context: inline' para que se ejecute dentro de la ventana de contexto del agente, dado que
# necesita acceso al historial de conversación completo. La restricción de herramientas permiten al modelo
# ejecutar la skill durante la conversación.
name: market-competitor-analyzer
description: Use this skill when the user asks for competitive intelligence, financial market trends, stock ticker comparisons, or landscape analysis regarding corporate competitors.
license: MIT
version: 1.0.3
context: inline
compatibility:
model: ">=gpt-4-mini"
os: "any"
dependencies:
- "python-yfinance>=0.2.0"
allowed-tools:
- web_search
- fetch_url_content
- render_data_chart
disable-model-invocation: false
metadata:
department: "Product-Strategy"
billing-code: "mkt-res-2026"
ux-icon: "trending-up"
---
# Esta skill conlleva la eliminación irrevocable de datos por lo que contiene la configuración
# 'disable-model-invocation: true', haciendo que sólo pueda ser invocada por una persona. Además,
# con el campo 'compatibility' le estamos limitando la base de datos específica sobre la que puede
# operar.
---
name: production-database-purger
description: Mandatorily hidden from automatic routing. This skill safely drops stale tables, truncates high-volume log schemas, and runs database vacuuming routines on production clusters during maintenance windows.
license: Proprietary
version: 4.0.0-rc1
context: fork
compatibility:
model: ">=o1-preview"
os: "linux, darwin"
dependencies:
- "postgresql-client-16"
- "aws-cli-v2"
allowed-tools:
- execute_sql_query
- fetch_vault_secret
disable-model-invocation: true
metadata:
compliance-required: "SOC2-Type-II"
requires-human-approval: true
criticality: "high"
slack-alert-channel: "#prod-ops-logs"
---
Llegados a este punto, es importante remarcar que, aunque estos campos puedan pertenecer a un estándar, no todos los agentes los entienden o usan nomenclaturas diferentes para alcanzar el mismo objetivo. En la siguiente tabla se muestra qué agente acepta qué campo de cabecera:
Campos de cabecera para SKILL.md soportados según agente
Header Field
Claude Code CLI
Claude.ai (Web)
Claude API
AutoGen Studio
CrewAI Core
LangGraph Engine
OpenCode CLI
Aider CLI
CodeRabbit CLI
name
✅
✅
✅
✅
✅
✅
✅
✅
✅
description
✅
✅
✅
✅
✅
✅
✅
✅
✅
version
✅
❌
✅
❌
✅
✅
✅
❌
✅
license
✅
❌
✅
❌
❌
❌
❌
❌
✅
context
✅
❌
✅
❌
❌
❌
✅ (mode)
❌
✅
allowed-tools
✅
❌
✅
✅
✅
✅
✅ (perms)
✅
✅
disable-model-invocation
✅
❌
✅
❌
❌
❌
✅ (disable)
❌
✅
compatibility
✅
❌
✅
❌
❌
❌
✅ (deps)
❌
❌
metadata
✅
✅
✅
✅
✅
✅
✅
✅
✅
🛢 Cuerpo de una skill (patrón T-I-P-O)
Una vez hemos completado la definición de la cabecera de la skill, ahora le toca el turno al cuerpo.
⚠️ IMPORTANTE
A diferencia de lo que sucede en la sección de cabecera, el cuerpo de una skill sí se define usando Markdown.
Lo que definamos aquí será un compendio de directivas semánticas, estructuradas de una determinada manera, que el modelo es capaz de asimilar como instrucciones operativas.
Este bloque es determinante para que el agente se comporte lo más determinista posible o que empiece a tener alucinaciones críticas durante la ejecución.
A pesar de la importancia de este bloque, al tratarse de open source, no existe una estructura única y estricta que de manera universal nos obligue a definir el cuerpo de una skill de una determinada manera. No obstante, en entornos empresariales se está convergiendo a usar el patrón denominado T-I-P-O (Targets, Inputs, Procedure y Outputs), siendo el mínimo indispensable aceptado de facto para garantizar un mínimo de determinismo en el modelo.
# Target (u # Objective)
Define qué se está buscando con la ejecución de esta skill y cuál es el objetivo final esperado.
Cuando un agente se pierde en un bucle de llamadas a herramientas, reevalua su progreso comparándolo con lo definido en este apartado.
Ejemplo:
# Target
The absolute objective of this skill is to locate deprecated API endpoints inside the repository, upgrade them to the current SDK version, and ensure the test suite passes with zero errors.
# Inputs (o # Prerequisites)
Define las variables, archivos o formatos de datos exactos que el agente debe recibir antes de empezar a trabajar.
Este apartado es importante porque evita que el agente empiece a "adivinar" o inventar datos; de modo que, si el contexto actual no contiene estos elementos, el agente sabe que debe detenerse y pedirlos.
Por ejemplo:
# Inputs
This skill requires two primary artifacts from the active workspace context:
1. `legacy_endpoints.json` - A manifest listing the raw endpoints.
2. `current_sdk_spec.yaml` - The up-to-date OpenAPI schema reference.
# Procedure (o # Execution Steps)
Define una lista numerada y secuencial que el agente debe seguir estrictamente y paso por paso.
Con esto conseguimos segmentar el razonamiento del modelo en subtareas manejables (Chain-of-Thought) al tiempo que forzamos al agente a seguir pasos numerados, reduciendo las posibles alucinaciones en flujos donde se empleen múltiples herramientas.
Por ejemplo:
# Procedure
1. Parse the `legacy_endpoints.json` file using the `read_file` tool.
2. For each endpoint listed, locate its definition in the codebase using `grep_search`.
3. Replace the deprecated syntax with the new methods specified in `current_sdk_spec.yaml`.
4. Run the local testing pipeline using `execute_terminal_command(command="npm test")`.
# Outputs (o # Expected Output Format)
Define el contrato de salida al finalizar la ejecución de la skill.
Aquí indicamos si queremos obtener un JSON, un Markdown, un Markdown Code Block, etc., así como la estructura exacta de la respuesta final.
De este modo, las salidas del agente serán fácilmente legibles por otros scripts automatizados o por el usuario, sin que contenga texto de relleno.
Por ejemplo:
# Outputs
Return exclusively a valid JSON block containing the compilation summary. Do not include conversational preambles.
Ejemplo completo de una skill definida:
---
name: api-migration-tool
description: Use when the user requests an automated upgrade of legacy API endpoints.
version: 1.0.0
context: fork
allowed-tools:
- read_file
- write_file
- grep_search
- execute_terminal_command
disable-model-invocation: false
---
# Target
Migrate deprecated microservice API routing schemas to the v2 standard.
# Inputs
- Workspace variable: `target_directory`
- Source config file: `api_routing.conf`
# Procedure
1. Scan the `target_directory` for any `.conf` files.
2. Cross-reference keys against the official version 2 documentation wrapper.
3. Apply the structural rewrites into a new temporary branch.
4. Validate the syntax integrity.
# Outputs
Provide a markdown table summarizing:
- The file paths modified.
- The original lines of code.
- The rewritten replacement chunks.
🔎 NOTA
Como nota final relativa al cuerpo de una skill, cuando estamos en una sección donde implementamos un listado no ordenado, en ocasiones podemos encontrar que se usa tanto el guión medio (-) como el asterisco (*) para indicar un elemento de dicha lista.
Si bien es verdad que a nivel computacional, al modelo le da exactamente igual, aquí prima la limpieza y el orden a nivel de DevEx, por lo que se promueve el uso de guión medio (-) para los elementos de una lista no ordenada, frente a cualquier otro carácter.
Estas son las secciones básicas que debería tener una skill. A parte de estas, si las necesidades de nuestra aplicación requieren de la definición de más secciones, tenemos total libertad para hacerlo siempre que ello permita afinar más el uso de la skill.
Algunas secciones adicionales a los propuestos por el patrón T-I-P-O son las siguientes:
# Guardrails & Safety Constraints
Define restricciones críticas mediante el listado de límites absolutos, comportamientos prohibidos y zonas donde el agente jamás debe interactuar.
Esta es la principal línea de defensa contra destrucciones de datos o brechas de seguridad.
Por ejemplo:
# Guardrails & Safety Constraints
- **NEVER** pass raw string variables directly into bash command lines without character escaping.
- Do not modify or read any files inside the hidden `.git/` or `.vault/` internal directories.
# User Verification Gates
Establece los puntos de aprobación humana, definiendo explícitamente qué acciones específicas detienen de forma obligatoria el flujo autónomo del agente para requerir un "Ok" visual o confirmación manual por parte del usuario, en el chat.
Por ejemplo:
# User Verification Gates
- **Trigger:** Prior to executing any database truncation or dropping an index.
- **Action:** Halt the script, render the specific SQL payload to the user, and ask: "Do you confirm the execution of this database migration? (y/n)".
# Escalation Protocols
Esta sección evita que el agente se quede atrapado intentando resolver problemas que superan sus capacidades de permisos, instruyéndolo sobre cuándo rendirse y derivar el caso a un usuario humano.
Por ejemplo:
# Escalation Protocols
- If a connection timeout error occurs more than 3 consecutive times on port 5432, halt automation.
- Do not attempt to guess credentials. Output: `[CRITICAL] Network isolation detected. Escalating ticket to SRE team.`
# State Tracking & Memory Logging
Con esta sección forzamos al modelo a estructurar su proceso de pensamiento e internalizar los cambios de estado en variables locales antes de llamar a la siguiente herramienta, solucionando la pérdida de memoria en flujos de trabajo muy largos.
Por ejemplo:
# State Tracking & Memory Logging
- Before modifying a file, open a `<state>` block to log the original file hash and line count.
- Maintain a rolling list of modified assets in your tool call parameters to avoid circular file edits.
# Chain-of-Thought Auditing
Aquí lo que hacemos es obliga al agente a justificar cada acción utilizando etiquetas XML específicas (como ) antes de invocar comandos terminales, lo que facilita enormemente la depuración y auditoría del comportamiento del agente.
Por ejemplo:
# Chain-of-Thought Auditing
- Every tool call must be preceded by a `<reasoning>` block containing:
1. Why this tool is necessary now.
2. The expected outcome of the invocation.
# Performance & Cost Optimization
Aquí podemos prevenir que el agente consuma de forma descontrolada el presupuesto de la API (o agote la ventana de contexto) ,regulando la cantidad de texto que puede leer o escribir en una sola iteración.
Por ejemplo:
# Performance & Cost Optimization
- When parsing log files, use range parameters to inspect a maximum of 150 lines per tool call.
- Avoid re-reading large context files if the content was already logged in the active scratchpad.
# Compliance & Regulatory Standards
Este apartado es importante cuando operamos con determinados datos, ya que nos asegura que los entregables generados por el agente (como código fuente o reportes de datos), cumplan con normativas legales u organizacionales estrictas del sector (SOC2, GDPR, ISO), o de la propia empresa.
Por ejemplo:
# Compliance & Regulatory Standards
- All telemetry methods designed by this skill must completely sanitize PII (Personally Identifiable Information).
- Ensure encryption-in-transit configurations use TLS 1.3 as a baseline.
# Workspace Clean-up & Idempotency
Con esta propiedad podemos garantiza la higiene del sistema local, asegurando que el agente borre sus archivos temporales de ejecución y que, si la skill se ejecuta dos veces seguidas, el resultado sea idéntico sin duplicar datos.
Por ejemplo:
# Workspace Clean-up & Idempotency
- Upon task completion or premature failure, execute an explicit cleanup step to delete `/tmp/cache_*.json`.
- Design every code refactor to be completely idempotent; running the skill twice must yield zero changes on the second run.
# Corporate Style & Terminology Glossaries
Aquí podemos unificar los términos de negocio y la voz del agente cuando genera documentación técnica, reportes o respuestas textuales dirigidas a clientes finales o a la directiva de la empresa.
Por ejemplo:
# Corporate Style & Terminology Glossaries
- Use the term "Client Workspace" instead of "Tenant Folder" across all markdown outputs.
- Keep tone formal and highly concise; eliminate words like "obviously", "simply", or conversational expressions.
# Diagnostic & Telemetry Footprints
Esta propiedad inyecta firmas digitales y logs estandarizados en los commits de Git o cabeceras de archivos creados por el agente para identificar de forma unívoca qué cambios fueron hechos por la IA y qué versión de la skill se utilizó.
Por ejemplo:
# Diagnostic & Telemetry Footprints
- Append this precise signature at the end of every modified file header:
`/* Automated optimization applied via agent-skill: db-optimizer (v2.4.1) */`
🗃 Skills más complejas
A medida que desarrollamos una skill, ésta puede volverse cada vez más compleja lo que hace que nuestro archivo SKILL.md se vuelva prácticamente inoperativo por la cantidad de información, instrucciones, ejemplos o similares que puede contener. El resultado más probable es:
😰 cargar todo este contenido en un agente,
🤯 saturación temprana del contexto,
🔥 incrementando del consumo innecesario de tokens y,
💀 degradando la respuesta del modelo.
La solución a esto está en un proceso llamado Atomización de la skill mediante el cual, se extrae de la misma lógica pesada, recursos externos y ejemplos referenciales que permiten transforma a la skill en un orquestador declarativo, manteniendo el contenido del archivo por debajo de las 50 o 100 líneas de texto. Esto hace que la velocidad de inicialización de la skill en el agente sea muy alta e incrementa la escalabilidad del sistema a través de la actualización independiente de referencias.
Este proceso de atomización se lleva a cabo realizando estas dos acciones: Estructuración rigurosa y Enlazado técnico.
Estructuración rigurosa
Dentro del directorio donde hemos definido el archivo SKILL.md, comenzaremos a crear directorios con nombres semánticamente razonables.
En cada uno de esos directorios, crearemos los archivos correspondientes que contendrán la información que deseamos extraer de la skill original.
La estructura de directorios depende únicamente del equipo de desarrollo pero sí es verdad que hay cierta tendencia a contar con determinados directorios ya establecidos, que no es necesario implementar si nuestra skill no los requiere, pero de hacerlo, se recomienda mantener el nombrado de los mismos.
Un ejemplo de estructuración rigurosa podría ser éste:
my-complex-agent-skill/
├── SKILL.md # (Obligatorio) Archivo principal (Orquestador y Frontmatter)
├── scripts/ # (Opcional ) Código ejecutable que delega lógica pesada fuera del LLM
│ └── optimize_matrix.py # Script de cómputo numérico/análisis complejo
├── assets/ # (Opcional ) Datos estáticos y esquemas de validación
│ └── database_schema.json # Estructura de la base de datos de referencia
├── references/ # (Opcional ) Guías de estilo, manuales o documentación densa
│ └── code_style_guide.md # Reglas de formato que el LLM solo lee si es necesario
└── examples/ # (Opcional ) Biblioteca de Few-Shot Examples (historias de usuario)
├── standard_case.md
└── edge_case_timeout.md
Enlazado técnico
Ahora que ya hemos extraído el exceso de información de nuestra skill a secciones independientes de nuestra estructura de directorios, necesitamos enlazar dicho contenido dentro del archivo que ha quedado.
Para ello emplearemos rutas relativas explícitas al contenido que queramos hacer referencia. Los agentes son capaces de leer estas rutas y mediante el uso de herramientas internas, pueden acceder a los archivos bajo demanda, únicamente cuando la sección del procedimiento lo exige.
Con esto:
✅ evitamos cargar todo este contenido en un agente de primeras,
✅ evitamos la saturación temprana del contexto,
✅ reducimos el consumo innecesario de tokens y,
✅ evitamos la degradación temprana de la respuesta del modelo.
Para hacer esto, hay dos patrones que se usan habitualmente: Enlace relativo directo y Enlace de referencia al pie.
Enlace relativo directo
Se usa para dependencias inmediatas que el agente siempre debe inspeccionar antes de ejecutar un procedimiento.
Por ejemplo:
# Inputs
This skill requires the project context infrastructure to match the configuration rules specified in the core [Database Architectural Reference Schema](./assets/database_schema.json).
Enlace de referencia al pie
Se usa para dependencias que es interesante tener enlazadas pero cuya carga se lleva a cabo en situaciones muy concretas, es decir, el agente no cargará estas referencias en el contexto salvo extrema necesidad.
Además de esto, también suelen ser usados en procedimientos muy largos, relegando las referencias al final del archivo y evitando ruido en el texto.
Por ejemplo:
# Procedure
1. Pull the latest Docker manifest using the environment variables.
2. Build the staging container and verify the cluster health check endpoints.
3. In case the build triggers a pipeline schema violation, fetch the resolution steps immediately.
# Error Handling & Edge Cases
* If the server returns a 503 error, verify if your service mesh matches the internal corporate architecture layout.
---
# Resource Footnotes / Lazy-Load References: ./assets/health_check_spec.json: ./references/pipeline_troubleshooting_guide.md: ./references/corporate_network_mesh_v2.md
Ahora bien, ¿cómo podemos empezar a externalizar una skill? Pues podemos empezar por plantear los siguientes pasos:
1. Mover scripts fuera del contexto de prompt (/scripts)
Dado que explicarle naturalmente a un agente las operaciones que debe llevar a cabo un script es complejo y consume tokens sin necesidad, podemos crear un archivo de scripting en un lenguaje de nuestra elección, que realice dicha operación.
En la cabecera de la skill, dentro del apartado allowed-tools daremos permisos de ejecución al comando execute_terminal_command e invocaremos nuestros script desde el texto de la skill.
Por ejemplo:
---
name: my-custom-skill
description: ...
allowed-tools:
- execute_terminal_command
---
# Procedure
1. Do not compute matrix variances manually. Instead, trigger the native optimization script:
`execute_terminal_command(command="python3 ./scripts/optimize_matrix.py --path=.")`
2. Externalizar la biblioteca de ejemplos (/examples)
Hay que tener mucho cuidado con el uso que hagamos de los archivos enlazados de esta sección, dado que por lo general, al contener ejemplos extensos y concretos, pueden ocupar mucho, elevando el consumo de tokens, tanto de entrada como de salida, si hacemos un mal uso de los ejemplos.
Lo ideal aquí es que cada ejemplo sea un archivo independiente, de manera que su enlazado permita cargar uno u otro dependiendo de las necesidades del agente.
Por ejemplo:
# Expected Workflows
Before formatting your final response, read and analyze the corresponding execution logs inside the example library based on the current workload:
- For standard microservice queries, read [Standard Flow Case](./examples/standard_case.md).
- For database connection timeouts, read [Timeout Recovery Case](./examples/edge_case_timeout.md).
3. Cargar documentación bajo demanda (/references)
La documentación de APIs, procedimientos, etc., puede saturar el contexto de un agente de manera muy rápida, además de que su continua actualización requeriría modificar también el contenido de la skill.
Si extraemos dicha documentación a archivos independientes y aislados, podemos realizar una carga selectiva de los mismos únicamente cuando sea necesario.
Por ejemplo:
# Error Handling & Edge Cases
If a compilation error occurs due to typing differences, do not attempt to guess the syntax. Read the internal reference document [Type Definition Manual](./references/code_style_guide.md) before attempting a second patch rewrite.
🧐 Buenas (✅) y malas (❌) prácticas a seguir a la hora de definir una skill
A nivel de cabecera
✅ Sincronizar el nombre y la carpeta: Mantén el campo name escrito en kebab-case (minúsculas con guiones) y asegúrate de que coincida exactamente con el nombre de la carpeta contenedora para evitar fallos de indexación.
✅ Acotar las descripciones semánticas: Redacta el campo description utilizando verbos de acción y palabras clave de activación específicas (ej. "Use when the user requests an API optimization"). Esto optimiza el enrutado y evita activaciones accidentales.
✅ Aplicar el Principio de Menor Privilegio: Declara exclusivamente en allowed-tools las herramientas que la skill necesita estrictamente para cumplir su objetivo, bloqueando el acceso a comandos peligrosos del sistema si no son requeridos.
✅ Forzar la aprobación humana en tareas críticas: Configura disable-model-invocation: true en skills destructivos o de producción (como despliegues o purgas de bases de datos) para obligar a que la skill sólo se active mediante un comando de barra (/) escrito por una persona.
✅ Especificar las dependencias del entorno: Utiliza el campo compatibility para listar las versiones mínimas de los binarios del sistema (ej. python>=3.10, docker), para que el framework detenga la ejecución antes de generar un error de terminal.
✅ Aprovechar los metadatos para la gobernanza: Utiliza el bloque metadata de forma sistemática en entornos corporativos para registrar el equipo propietario, el centro de costos y los identificadores de cumplimiento (ej. compliance: SOC2).
❌ Duplicar nombres de skills: Usar el mismo campo name en diferentes archivos SKILL.md dentro del repositorio, lo que provoca colisiones y hace que el orquestador ignore componentes de forma aleatoria.
❌ Crear descripciones genéricas o ambiguas: Escribir descripciones del tipo description: "An AI assistant to help you write code". Esto causa que el LLM active la skill constantemente para tareas comunes, saturando la ventana de contexto.
❌ Otorgar permisos universales por pereza: Declarar comodines en las herramientas o incluir herramientas de ejecución de terminal (execute_terminal_command) en skills que sólo requieren lectura de datos.
❌ Ignorar el control de versiones: Dejar el campo version estático en 1.0.0 indefinidamente, impidiendo que las canalizaciones de CI/CD verifiquen si los agentes en producción ejecutan el comportamiento validado más reciente.
❌ Confundir el rol de context: fork: Configurar un skill como context: inline cuando requiere procesar miles de líneas de registros de servidores, provocando que el chat principal se llene de ruido y se agote el presupuesto de tokens.
❌ Omitir el campo license en skills compartidos: Dejar el campo de licencia vacío en repositorios internos compartidos, lo que expone a los equipos de desarrollo a problemas de cumplimiento de propiedad intelectual.
A nivel de cuerpo
✅ Adoptar la estructura estándar T-I-P-O: Organiza siempre el cuerpo del documento utilizando los bloques # Target, # Inputs, # Procedure y # Outputs para guiar al modelo a través de un flujo determinista.
✅ Escribir procedimientos imperativos y numerados: Utiliza listas numeradas (1., 2., 3.) en la sección del procedimiento para forzar un razonamiento secuencial paso a paso (Chain-of-Thought).
✅ Estandarizar las viñetas no ordenadas con guiones: Utiliza exclusivamente guiones (-) para listas de restricciones, entradas o herramientas. Deja los asteriscos (*) únicamente para negritas (**) o itálicas (*), facilitando la lectura de los analizadores de sintaxis.
✅ Externalizar los manuales densos mediante notas al pie: Aplica la carga perezosa (lazy loading) moviendo las rutas de manuales o guías secundarias al pie de la página ([Reference 1]: ./references/guide.md), manteniendo el flujo principal limpio de texto de relleno.
✅ Definir contratos de salida estrictos: En la sección # Outputs, especifica el formato exacto de respuesta (ej. un esquema JSON válido o una tabla Markdown), y prohíbe explícitamente los preámbulos conversacionales como "Sure, here is your summary".
✅ Declarar restricciones negativas de forma asertiva: Dedica una sección independiente a las restricciones de seguridad (# Guardrails & Safety Constraints) y redacta las prohibiciones en mayúsculas e imperativo (ej. "NEVER run recursive deletes").
❌ Mezclar estilos de viñetas en un mismo bloque: Combinar guiones (-) y asteriscos (*) de forma aleatoria dentro de una misma lista, lo que puede romper la segmentación del contexto en ciertos motores de análisis.
❌ Escribir instrucciones en prosa narrativa de formato libre: Redactar el procedimiento como un párrafo largo en lugar de una lista estructurada. Los modelos tienden a omitir instrucciones secundarias cuando están ocultas en bloques densos de texto.
❌ Incrustar código fuente extenso dentro de las instrucciones: Pegar scripts completos de Python o Bash en el cuerpo del prompt. Esto degrada drásticamente la atención del modelo y dispara los costos de ejecución.
❌ Asumir que el agente conoce el entorno actual: Escribir procedimientos sin definir previamente la sección # Inputs, causando que el agente intente adivinar rutas de archivos, nombres de variables o entornos de bases de datos.
❌ Utilizar lenguaje ambiguo o condicional: Usar frases como "Please try to optimize the query if you think it is a good idea". Los agentes de producción requieren instrucciones directas y deterministas (ej. "Analyze query latency using the EXPLAIN tool").
❌ Saturar la skill con demasiados objetivos secundarios: Intentar que un solo archivo SKILL.md realice análisis de código, despliegues en la nube y optimización de bases de datos simultáneamente. Si el alcance crece, divídelo en skills independientes.
A nivel de robustez, manejo de errores y escalabilidad
✅ Diseñar rutas de escape claras para errores de herramientas: Dedica una sección a # Error Handling donde indiques detalladamente qué debe hacer el agente si una herramienta devuelve un error, se agota el tiempo de espera (timeout) o devuelve datos vacíos.
✅ Delegar el procesamiento numérico y algorítmico a scripts: En lugar de pedirle al modelo que analice una matriz o un JSON gigante mediante prompts, escribe un script nativo en /scripts y haz que el agente lo ejecute y procese únicamente el resumen de salida.
✅ Implementar Few-Shot Examples modulares: Almacena los ejemplos complejos de interacciones en archivos independientes dentro de un directorio /examples y enlázalos bajo demanda, evitando saturar el contexto inicial del agente.
✅ Verificar la integridad de los enlaces relativos mediante CI/CD: Implementa un script automatizado en tu flujo de integración que valide que todas las referencias a ./assets/, ./scripts/ o ./references/ dentro de tus skills existan físicamente y no estén rotas.
✅ Establecer límites de detención (Halt Conditions): Instruye explícitamente al agente para que detenga la ejecución de inmediato y solicite la intervención de un supervisor humano si encuentra problemas de permisos críticos (p.e.: 403 Unauthorized), o fallos de red persistentes.
✅ Mantener el core de la skill por debajo de los 100 tokens de configuración: Diseña el SKILL.md principal como un director de orquesta ligero y minimalista que delega en recursos externos, garantizando arranques ultra rápidos y un consumo óptimo de memoria.
✅ Definir skills a nivel de proyecto según las necesidades de éste: Cuando una skill es usada en proyectos de manera aislada, no es recomendable extraerlas para que sean consumidas de manera global, dado que cualquier agente la cargará independientemente de que la necesite para el repositorio en cuestión, o no. Sólo crearemos skills globales o promocionaremos una skill local a global, cuando tengamos un 100% de certeza de que dicha skill va a ser empleada por todos los proyectos.
❌ Permitir bucles infinitos de reintentos: Omitir instrucciones de contingencia ante fallos, lo que causa que el agente intente ejecutar la misma herramienta defectuosa una y otra vez en un ciclo infinito que consume tu presupuesto de API.
❌ Ocultar mensajes de error del sistema: Instruir al modelo para que ignore los fallos del terminal (p.e.: 2> /dev/null). Si el agente enmascara los errores, diagnosticar comportamientos anómalos en entornos de producción se vuelve imposible.
❌ Hardcodear credenciales, rutas absolutas o secretos: Escribir contraseñas, tokens de API o rutas absolutas como /Users/username/project en el cuerpo de la skill. Esto rompe la portabilidad del agente entre diferentes sistemas y genera una vulnerabilidad crítica de seguridad.
❌ Confiar ciegamente en la memoria de contexto a largo plazo: Diseñar un procedimiento que dependa de que el agente recuerde un dato proporcionado al inicio del chat general, especialmente cuando opera en configuraciones context: inline.
❌ Validar cambios utilizando el propio entorno de producción: Permitir que una skill de refactorización de código aplique modificaciones directas sobre la rama principal (main) sin forzar la ejecución previa de la suite de pruebas unitarias locales en una rama aislada.
❌ Actualizar scripts externos sin actualizar el manual de la skill: Modificar los parámetros de entrada de un script de automatización en ./scripts/ pero olvidar actualizar las reglas de llamada a herramientas correspondientes en el cuerpo del archivo SKILL.md, provocando que el agente invoque comandos con sintaxis obsoleta.
👋 Conclusiones finales
Está claro que si hay algo que no ha cambiado con la llegada de la IA al mundo del desarrollo, es que las buenas prácticas son más necesarias ahora que nunca y como muestra de ello, es el especial mimo que debemos poner a la hora de definir nuestras skills.
Espero que este contenido te haya sido útil. Si tienes cualquier pregunta, siéntete totalmente libre de contactar conmigo. Aquí están mis perfiles de X, LinkedIn y Github.
🙏 Reconocimientos y agradecimientos
Por supuesto a @mouredev por destinar tiempo a preparar y difundir el taller que ha sido el origen de todo el texto que, si has llegado hasta aquí, has leído.
Read original: https://dev.to/ddialar/ia-fundamentos-y-buenas-practicas-en-la-creacion-de-skills-3ed3
← Previous
Anthropic CEO Dario Amodei Says AI Industry Needs to Give Safety Measures Time to Catch Up
Next →
Integrating Machine Learning Models into Android Apps
Related
AI - Foundations and good practices creating skills
DevOps
3
DEV Community
From VibeConnect to CrowdWide: Building My Own Social Platform
DevOps
5
Dev.to (EN Zone)
Building Self-Hosted Developer Tools with TrueCharts: Deploying Private Services Like AdGuard and V2Ray on Kubernetes
DevOps
7
Dev.to (EN Zone)
You Installed Git. Here Are the Next Ten Minutes.
DevOps
6
DEV Community
Comments0
No comments yet — be the first