RL RanceLee Tutorials
← Volver a tutoriales

Skills: qué son y cómo usarlas

De mecanógrafo a superasistente

Anteriormente aprendimos a usar Claude Code para proyectos, y quizás hayas experimentado el poder de la programación con IA. Pero ¿has notado un problema:

Cada vez que haces algo similar, tienes que describir los requisitos desde cero.

Por ejemplo, quieres que la IA te ayude a:

  • Escribir mensajes de commit de Git
  • Revisar código
  • Generar documentación del proyecto
  • Sincronizar archivos

Puede que hagas estas tareas varias veces al día, pero cada vez tienes que escribir un párrafo largo diciéndole a la IA qué hacer. ¡Es agotador!

Es como si cada vez que pidieras comida a domicilio tuvieras que decirle al restaurante:

“Quiero un plato de fideos de carne estofada, sin cilantro, con extra de chile, los fideos deben estar firmes, menos caldo…”

¿Hay alguna forma de convertir estas operaciones comunes en comandos de un solo clic?

Sí, de eso vamos a hablar hoy: Skill.


¿Qué es Skill?

Explicación en una frase

Skill = comando abreviado de la IA

Igual que la app de Atajos en tu teléfono, Skill encapsula operaciones complejas en un comando simple.

Definición oficial

Skill se refiere a un “módulo de capacidad” reutilizable que encapsula herramientas/APIs/scripts y prompts en una interfaz estándar, permitiendo que la IA los llame bajo demanda para completar tareas específicas.

Enfatiza:

  • Entrada y salida claras
  • Gestión de dependencias y versiones
  • Comprobable y actualizable
  • Convertir una IA general en un asistente profesional orientado a los negocios

Comprensión intuitiva

Sin Skill:

You: Please review this code and check the following:
1. Are there any performance issues?
2. Are there any security vulnerabilities?
3. Does the code style follow the conventions?
4. Is there any duplicate code?
5. Are variable names clear?
6. Are comments complete?
……(continue describing for 10 more lines)

Con Skill:

You: /review

La IA revisa automáticamente el código según estándares predefinidos y proporciona un informe detallado.

¿Ves la diferencia? De cientos de palabras a un solo comando: ese es el poder de Skill.


Diferencias entre Skill, Prompt y MCP

Mucha gente pregunta: ¿Cuáles son las diferencias entre Skill, Prompt y MCP?

Comparación de conceptos

Aspecto Prompt Skill MCP
Esencia Instrucción de texto Módulo de capacidad encapsulado Protocolo para conectar herramientas externas
Reutilización Baja, hay que volver a introducir cada vez Alta, definir una vez y reutilizar Alta, configurar una vez y usar continuamente
Complejidad Simple Media Compleja
Alcance de capacidad Solo procesamiento de texto Texto + scripts simples Texto + interacción con sistemas externos
Curva de aprendizaje Mínima Media Relativamente alta

Usando analogías

Prompt = Instrucción verbal

  • Tienes que decirle verbalmente a la IA qué hacer cada vez
  • Adecuado para tareas únicas y puntuales
  • Por ejemplo: “Traduce este párrafo”

Skill = Flujo de trabajo

  • Solidifica instrucciones comunes en un flujo de trabajo estándar
  • Adecuado para tareas repetitivas y estandarizadas
  • Por ejemplo: /commit genera automáticamente mensajes de commit de Git

MCP = Sistema externo

  • Permite que la IA se conecte a herramientas y fuentes de datos externas
  • Adecuado para tareas que necesitan acceder a sistemas externos
  • Por ejemplo: conectar con Obsidian para leer/escribir notas, conectar con base de datos para consultar datos

Relación entre los tres

Prompt → The most basic interaction method
    ↓
Skill → Encapsulates prompt + simple logic
    ↓
MCP → Skill + external system capabilities

En sentido figurado:

  • Prompt = Cocinas tú mismo
  • Skill = Calientas comida precocinada en el microondas
  • MCP = Pides comida a domicilio

¿Cuándo usar cada uno?

Usa Prompt si:

  • La tarea es simple y única
  • Los requisitos son flexibles y cambiantes
  • No necesitas reutilización

Usa Skill si:

  • La tarea es muy repetitiva
  • Tiene un flujo de trabajo estandarizado
  • Quieres mejorar la eficiencia

Usa MCP si:

  • Necesitas acceder a datos externos (base de datos, API, sistema de archivos, etc.)
  • Necesitas interactuar con otro software (Obsidian, navegador, etc.)
  • Necesitas obtener información en tiempo real

Comparación de casos prácticos:

Escenario 1: Traducir un párrafo

  • Usa Prompt: “Traduce este párrafo” (lo más simple)

Escenario 2: Traducir muchos documentos a diario

  • Usa Skill: /translate (flujo de trabajo de traducción estandarizado)

Escenario 3: Traducir automáticamente notas de Obsidian y guardarlas

  • Usa MCP: Conectar con Obsidian, leer, traducir y guardar automáticamente (el más potente)

Uso básico de Skill

¿Cómo ver los Skills existentes?

En Claude Code o Codex, introduce:

/skill

Listará todos los Skills disponibles.

¿Cómo usar Skill?

Método 1: Ejecución directa

Introduce /skill, luego usa Tab para seleccionar el Skill deseado y pulsa Enter para ejecutarlo.

Método 2: Ejecutar con parámetros

Después de seleccionar un Skill, continúa escribiendo tu petición específica:

/translate translate the comments in this code to English

Skills integrados comunes

La mayoría de las herramientas de programación con IA vienen con algunos Skills integrados de uso común:

Skill Función Ejemplo
/commit Generar automáticamente mensaje de commit de Git /commit
/review Revisar calidad del código /review
/fix Corregir errores de código /fix
/test Generar casos de prueba /test
/doc Generar documentación /doc
/refactor Refactorizar código /refactor

Estos Skills integrados ya pueden resolver el 80% de las necesidades diarias.


Crear tu propio Skill

Si los Skills integrados no son suficientes, puedes crear tu propio Skill.

Dos métodos de creación

Método 1: Deja que la IA lo cree por ti (recomendado)

Codex viene con un Skill para crear Skills (suena confuso, pero es potente).

Pasos:

  1. Introduce /skill
  2. Encuentra la opción relacionada con “Crear Skill”
  3. Después de seleccionarla, dile a la IA qué Skill quieres

Ejemplo:

/create-skill

I want a translation Skill with the following features:
1. Automatically detect Chinese comments in code
2. Translate them into English
3. Keep the code format unchanged

La IA creará automáticamente el archivo del Skill y lo colocará en la ubicación correcta.

Método 2: Creación manual

Si quieres entender más a fondo la estructura de Skill, puedes crearlo manualmente.

Estructura del archivo de Skill:

Cada Skill es una carpeta que debe contener un archivo SKILL.md:

my-skill/
  ├── SKILL.md          # Skill description and configuration
  └── scripts/          # Optional: helper scripts
      └── helper.py

Formato básico de SKILL.md:

---
name: Skill name
description: Skill description
---

# Detailed description

Write detailed usage instructions and implementation logic here.

## Parameters

- `--param1`: Description of parameter 1
- `--param2`: Description of parameter 2

## Example

Example usage code

La sección “Caso práctico” más adelante en este capítulo detallará cómo crear un Skill completo.


Instalar Skills de otros

Hay muchos Skills ya preparados en GitHub que puedes descargar y usar directamente.

Encontrar la carpeta de Skills

Ubicación de Skills en Codex:

  • Mac/Linux: ~/.codex/skills/
  • Windows: %USERPROFILE%\.codex\skills\

Ubicación de Skills en Claude Code:

  • Mac/Linux: ~/.claude/skills/
  • Windows: %USERPROFILE%\.claude\skills\

Pasos de instalación

  1. Abre la carpeta de Skills

Si la carpeta no existe, puedes crearla manualmente:

# Mac/Linux
mkdir -p ~/.codex/skills

# Windows (PowerShell)
New-Item -Path "$env:USERPROFILE\.codex\skills" -ItemType Directory -Force

  1. Descarga el archivo del Skill

Descarga la carpeta del Skill desde GitHub u otras fuentes.

  1. Copia al directorio de Skills

Copia toda la carpeta del Skill al directorio de skills correspondiente.

  1. Reinicia la herramienta

Nota: Codex actualmente no soporta recarga en caliente; necesitas salir y reiniciar para ver el nuevo Skill. Claude Code normalmente lo reconoce automáticamente.

Verificar la instalación

Después de reiniciar, introduce /skill para ver la lista y confirmar que el nuevo Skill ha aparecido.


Caso práctico: Crear un Skill de sincronización

Escenario del problema

Si usas tanto Codex como Claude Code (mucha gente lo hace), te encontrarás con un problema:

Los Skills de las dos herramientas deben gestionarse por separado, lo cual es muy incómodo.

  • Los Skills de Codex están en ~/.codex/skills/
  • Los Skills de Claude Code están en ~/.claude/skills/

Cada vez que creas un Skill útil en Codex, tienes que copiarlo manualmente a la carpeta de Claude. ¡Demasiado tedioso!

En este punto, podemos crear un Skill para sincronizar automáticamente los contenidos de las dos carpetas: usar un Skill para gestionar Skills.

Este Skill:

  1. Comprobará las diferencias entre las dos carpetas de Skills
  2. Informará qué Skills necesitan sincronizarse
  3. Después de tu confirmación, sincronizará automáticamente

Solo tenemos que decirle los requisitos a la IA.

A continuación se muestra lo que la IA hace por ti. Ten en cuenta que estos pasos son automáticos; ¡no necesitas hacer nada! Se muestra aquí solo con fines de demostración.

Paso 1: Crear la carpeta del Skill

En el directorio de skills de Codex o Claude Code, crea una nueva carpeta:

mkdir ~/.codex/skills/codex-claude-skill-sync

Paso 2: Crear SKILL.md

Crea un archivo SKILL.md en la carpeta:

name: codex-claude-skill-sync
description: Sync Codex and Claude Skills
---

# Codex/Claude Skill Sync

## Overview

Used to check and sync the Skill directories of Codex and Claude, keeping both sides consistent. By default, only reports differences; executes sync after user confirmation.

## Workflow

1. Run difference report (no modification):

   `python3 scripts/sync_skills.py`

2. Report differences to the user in English and wait for explicit consent before proceeding.
3. After consent, execute sync:

   `python3 scripts/sync_skills.py --apply`

4. When encountering a conflict (same modification time but different content), pause and ask the user which side to keep.

## Rules

- Default directories:
  - Codex: `/Users/yourusername/.codex/skills`
  - Claude: `/Users/yourusername/.claude/skills`
- Only process top-level directories that contain `SKILL.md`, skip hidden directories and `.system`
- Determine which side is newer based on the latest modification time in the directory
- When syncing, delete the target Skill directory first, then copy the entire source directory

## Parameters

- `--apply` Execute sync (default is report only)
- `--codex <path>` Override Codex directory
- `--claude <path>` Override Claude directory
- `--prefer codex|claude` When modification time is the same but content differs, use the specified side to overwrite (requires explicit user authorization)

Importante: ¡Cambia las rutas anteriores por tus rutas reales!

Paso 3: Crear el archivo de script

Crea un directorio scripts dentro de la carpeta del Skill, luego crea sync_skills.py:

mkdir ~/.codex/skills/codex-claude-skill-sync/scripts

Código completo de sync_skills.py:

#!/usr/bin/env python3
"""
Compare and sync skill folders between Codex and Claude.

Default behavior is report-only. Use --apply to perform sync.
"""

from __future__ import annotations

import argparse
import hashlib
import os
from datetime import datetime
from pathlib import Path
import shutil
import sys

DEFAULT_CODEX = Path("/Users/yourusername/.codex/skills")
DEFAULT_CLAUDE = Path("/Users/yourusername/.claude/skills")

IGNORE_DIR_NAMES = {".git", ".idea", ".vscode", "__pycache__", ".pytest_cache", ".mypy_cache"}
IGNORE_FILE_NAMES = {".DS_Store"}
TIME_EPSILON = 1.0


def format_time(timestamp: float) -> str:
    return datetime.fromtimestamp(timestamp).strftime("%Y-%m-%d %H:%M:%S")


def list_skill_dirs(root: Path) -> tuple[dict[str, Path], list[str]]:
    if not root.exists():
        raise FileNotFoundError(f"Root path does not exist: {root}")
    if not root.is_dir():
        raise NotADirectoryError(f"Root path is not a directory: {root}")

    skills: dict[str, Path] = {}
    ignored: list[str] = []
    for entry in sorted(root.iterdir(), key=lambda p: p.name):
        if not entry.is_dir():
            continue
        if entry.name.startswith("."):
            ignored.append(entry.name)
            continue
        if not (entry / "SKILL.md").is_file():
            continue
        skills[entry.name] = entry
    return skills, ignored


def dir_state(path: Path) -> tuple[str, float, int]:
    hasher = hashlib.sha256()
    latest_mtime = path.stat().st_mtime
    file_count = 0

    for root, dirs, files in os.walk(path):
        dirs[:] = [d for d in dirs if d not in IGNORE_DIR_NAMES]
        dirs.sort()
        files = sorted(f for f in files if f not in IGNORE_FILE_NAMES)

        rel_dir = os.path.relpath(root, path)
        if rel_dir == ".":
            rel_dir = ""
        hasher.update(f"D|{rel_dir}\n".encode())

        try:
            latest_mtime = max(latest_mtime, os.stat(root).st_mtime)
        except FileNotFoundError:
            continue

        for name in files:
            file_path = Path(root) / name
            rel_path = os.path.relpath(file_path, path)

            if file_path.is_symlink():
                try:
                    target = os.readlink(file_path)
                except OSError:
                    target = ""
                hasher.update(f"L|{rel_path}\n{target}\n".encode())
                try:
                    latest_mtime = max(latest_mtime, file_path.lstat().st_mtime)
                except FileNotFoundError:
                    pass
                continue

            if not file_path.is_file():
                continue

            stat = file_path.stat()
            latest_mtime = max(latest_mtime, stat.st_mtime)
            file_count += 1
            hasher.update(f"F|{rel_path}\n{stat.st_size}\n".encode())

            with open(file_path, "rb") as handle:
                for chunk in iter(lambda: handle.read(1024 * 1024), b""):
                    hasher.update(chunk)

    return hasher.hexdigest(), latest_mtime, file_count


def build_plan(
    codex_skills: dict[str, Path],
    claude_skills: dict[str, Path],
    codex_root: Path,
    claude_root: Path,
    prefer: str | None,
) -> tuple[list[dict], list[str], list[dict]]:
    actions: list[dict] = []
    identical: list[str] = []
    conflicts: list[dict] = []

    all_names = sorted(set(codex_skills) | set(claude_skills))
    for name in all_names:
        codex_path = codex_skills.get(name)
        claude_path = claude_skills.get(name)

        if codex_path and not claude_path:
            actions.append(
                {
                    "name": name,
                    "src": codex_path,
                    "dst": claude_root / name,
                    "reason": "only in codex",
                    "direction": "codex -> claude",
                }
            )
            continue
        if claude_path and not codex_path:
            actions.append(
                {
                    "name": name,
                    "src": claude_path,
                    "dst": codex_root / name,
                    "reason": "only in claude",
                    "direction": "claude -> codex",
                }
            )
            continue

        if not codex_path or not claude_path:
            continue

        codex_hash, codex_mtime, _ = dir_state(codex_path)
        claude_hash, claude_mtime, _ = dir_state(claude_path)

        if codex_hash == claude_hash:
            identical.append(name)
            continue

        time_delta = codex_mtime - claude_mtime
        if abs(time_delta) <= TIME_EPSILON:
            if prefer == "codex":
                actions.append(
                    {
                        "name": name,
                        "src": codex_path,
                        "dst": claude_path,
                        "reason": "same mtime, prefer codex",
                        "direction": "codex -> claude",
                        "codex_mtime": codex_mtime,
                        "claude_mtime": claude_mtime,
                    }
                )
            elif prefer == "claude":
                actions.append(
                    {
                        "name": name,
                        "src": claude_path,
                        "dst": codex_path,
                        "reason": "same mtime, prefer claude",
                        "direction": "claude -> codex",
                        "codex_mtime": codex_mtime,
                        "claude_mtime": claude_mtime,
                    }
                )
            else:
                conflicts.append(
                    {
                        "name": name,
                        "codex_mtime": codex_mtime,
                        "claude_mtime": claude_mtime,
                    }
                )
            continue

        if time_delta > 0:
            actions.append(
                {
                    "name": name,
                    "src": codex_path,
                    "dst": claude_path,
                    "reason": "codex newer",
                    "direction": "codex -> claude",
                    "codex_mtime": codex_mtime,
                    "claude_mtime": claude_mtime,
                }
            )
        else:
            actions.append(
                {
                    "name": name,
                    "src": claude_path,
                    "dst": codex_path,
                    "reason": "claude newer",
                    "direction": "claude -> codex",
                    "codex_mtime": codex_mtime,
                    "claude_mtime": claude_mtime,
                }
            )

    return actions, identical, conflicts


def print_report(
    actions: list[dict],
    identical: list[str],
    conflicts: list[dict],
    codex_root: Path,
    claude_root: Path,
    apply: bool,
    ignored_codex: list[str],
    ignored_claude: list[str],
) -> None:
    print("Skill sync report")
    print(f"Codex: {codex_root}")
    print(f"Claude: {claude_root}")

    if ignored_codex:
        print(f"Ignored in Codex: {', '.join(sorted(ignored_codex))}")
    if ignored_claude:
        print(f"Ignored in Claude: {', '.join(sorted(ignored_claude))}")

    print("\nPlanned sync actions:")
    if not actions:
        print("- none")
    else:
        for item in actions:
            codex_mtime = item.get("codex_mtime")
            claude_mtime = item.get("claude_mtime")
            details = []
            if codex_mtime is not None:
                details.append(f"codex mtime: {format_time(codex_mtime)}")
            if claude_mtime is not None:
                details.append(f"claude mtime: {format_time(claude_mtime)}")
            detail_text = f" ({', '.join(details)})" if details else ""
            print(f"- {item['name']}: {item['direction']} [{item['reason']}]" + detail_text)

    print("\nConflicts:")
    if not conflicts:
        print("- none")
    else:
        for item in conflicts:
            print(
                f"- {item['name']}: same mtime but different content "
                f"(codex {format_time(item['codex_mtime'])}, claude {format_time(item['claude_mtime'])})"
            )

    print(f"\nUp-to-date skills: {len(identical)}")

    if not apply:
        print("\nDry run only. Re-run with --apply to sync.")


def apply_actions(actions: list[dict]) -> None:
    for item in actions:
        src = Path(item["src"])
        dst = Path(item["dst"])

        if dst.exists():
            if dst.is_dir():
                shutil.rmtree(dst)
            else:
                dst.unlink()

        shutil.copytree(src, dst, symlinks=True)


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(description="Sync Codex and Claude skill folders")
    parser.add_argument("--codex", type=Path, default=DEFAULT_CODEX, help="Codex skill root")
    parser.add_argument("--claude", type=Path, default=DEFAULT_CLAUDE, help="Claude skill root")
    parser.add_argument("--apply", action="store_true", help="Apply sync actions")
    parser.add_argument(
        "--prefer",
        choices=["codex", "claude"],
        help="Break ties when mtimes are equal",
    )
    return parser.parse_args()


def main() -> int:
    args = parse_args()

    try:
        codex_skills, ignored_codex = list_skill_dirs(args.codex)
        claude_skills, ignored_claude = list_skill_dirs(args.claude)
    except (FileNotFoundError, NotADirectoryError) as exc:
        print(str(exc), file=sys.stderr)
        return 2

    actions, identical, conflicts = build_plan(
        codex_skills,
        claude_skills,
        args.codex,
        args.claude,
        args.prefer,
    )
    print_report(
        actions,
        identical,
        conflicts,
        args.codex,
        args.claude,
        args.apply,
        ignored_codex,
        ignored_claude,
    )

    if args.apply and actions:
        apply_actions(actions)
        print("\nSync complete.")
    elif args.apply and not actions:
        print("\nNo changes to apply.")

    if conflicts and not args.prefer:
        return 1
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

Importante: Recuerda modificar las rutas al principio:

DEFAULT_CODEX = Path("/Users/yourusername/.codex/skills")
DEFAULT_CLAUDE = Path("/Users/yourusername/.claude/skills")

Cámbialas por tus rutas reales.

Usar el Skill de sincronización

Paso 1: Ver diferencias

En Claude Code o Codex, introduce:

/codex-claude-skill-sync

La IA ejecutará automáticamente el script e informará de las diferencias entre las dos carpetas de Skills.

Paso 2: Confirmar sincronización

Si estás de acuerdo con la sincronización, dile a la IA:

Agreed, please execute sync.

La IA ejecutará python3 scripts/sync_skills.py --apply para completar la sincronización.

¡Hecho! A partir de ahora, cada vez que crees o modifiques un Skill en un lado, solo ejecuta este Skill de sincronización una vez y ambos lados se mantendrán consistentes.


Consejos avanzados de Skill

Consejo 1: Combinar Skills

Se pueden usar varios Skills en secuencia:

/review then /fix to fix the issues found

La IA primero revisará el código y luego lo corregirá automáticamente según los resultados de la revisión.

Consejo 2: Personalizar parámetros de Skill

Muchos Skills admiten parámetros:

/commit --type feat --scope api

Esto generará un mensaje de commit en un formato específico.

Consejo 3: Plantillas de Skill

Puedes crear plantillas de Skill para generar rápidamente nuevos Skills:

  1. Copia una carpeta de Skill existente
  2. Modifica SKILL.md
  3. Guarda

Consejo 4: Compartir Skills con el equipo

Coloca la carpeta de Skills en un repositorio Git para que los miembros del equipo puedan compartir:

git clone https://github.com/your-team/skills.git ~/.codex/skills/team-skills

Resumen

Lo que aprendimos hoy:

  1. Qué es Skill: Un módulo de capacidad reutilizable que convierte operaciones complejas en comandos simples
  2. Skill vs Prompt vs MCP: Diferencias y escenarios de aplicación
  3. Cómo usar Skill: /skill para ver e invocar
  4. Cómo crear Skill: Dejar que la IA ayude o crearlo manualmente
  5. Cómo instalar Skill: Copiar a la carpeta correspondiente
  6. Caso práctico: Crear un Skill de sincronización para resolver la gestión de múltiples herramientas

Puntos clave:

  • Skill eleva a la IA de “mecanógrafo” a “asistente profesional”
  • Las operaciones comunes deben encapsularse en Skills
  • Un buen Skill puede ahorrar el 90% del tiempo