Los custom commands se fusionaron con Skills. Cuándo migrar a `.claude/skills/` y qué ganas al hacerlo.
Los tres posts anteriores cubrieron el uso completo de los slash commands: desde un archivo Markdown, pasando por la inyección !command, hasta la orquestación de subagents y MCP. Nada de eso queda obsoleto, pero Anthropic hizo una fusión silenciosa por detrás: los custom commands se integraron en Skills.
Tu .claude/commands/review.md sigue funcionando, /review sigue disponible, no hay que cambiar nada. Pero si quieres que un comando adquiera más capacidades (múltiples archivos, ejecución en fork, auto-activación por ruta), el nuevo lugar es .claude/skills/review/SKILL.md. Este post deja claras dos cosas: cómo migrar y si vale la pena hacerlo.
La promesa oficial de compatibilidad es explícita: .claude/commands/deploy.md y .claude/skills/deploy/SKILL.md se registran ambos como /deploy, con comportamiento idéntico. Si hay colisión de nombres, gana skills.
Pasos mínimos:
cd .claude/commands
mkdir -p ../skills/review
mv review.md ../skills/review/SKILL.md
No hace falta cambiar ni una línea del contenido. YAML frontmatter, !`command`, @file, $ARGUMENTS: todo es compatible.
Pero si solo haces eso, surge la pregunta obvia: ¿entonces para qué migrarlo? La respuesta está en que un directorio de skill puede contener varios archivos, mientras que un command está limitado a uno solo.
SKILL.md es el punto de entrada, y el mismo directorio puede alojar cualquier archivo auxiliar. Imagínate esta estructura:
.claude/skills/review/
├── SKILL.md # entrada: instrucciones breves + referencias
├── checklist.md # el largo checklist de code review
├── examples/
│ └── good-diff.md # ejemplo positivo
└── scripts/
└── lint.sh # script que SKILL.md puede invocar
Se referencian desde SKILL.md con rutas relativas:
Revisa el diff actual siguiendo los estándares de [checklist.md](checklist.md).
Consulta [examples/good-diff.md](examples/good-diff.md) para el formato de salida esperado.
Estos archivos auxiliares no entran automáticamente al context: Claude los lee bajo demanda. La recomendación oficial es mantener SKILL.md por debajo de 500 líneas y empujar el resto a los archivos de soporte.
disable-model-invocation: qué skills solo puedes disparar tú a manoPor defecto, Claude invoca cualquier skill cuando detecta un momento oportuno. Eso es peligroso para comandos con efectos secundarios como /deploy, /commit o /send-email: no quieres que "el código se vea bien y decida desplegar".
---
name: deploy
description: Desplegar a producción
disable-model-invocation: true
allowed-tools: Bash(kamal deploy:*), Bash(git push:*)
---
Con esa línea, /deploy solo se dispara cuando lo tecleas tú. Claude no lo va a invocar por su cuenta en mitad de la conversación.
El inverso es user-invocable: false: "solo Claude puede invocarlo y no aparece en el menú /". Viene bien para skills de conocimiento de fondo (por ejemplo legacy-system-context: Claude lo carga automáticamente cuando corresponde, pero no tiene sentido que lo dispares tú a mano).
context: fork: ejecutar el skill en un subagentEsta es la mejora más grande. En el post anterior vimos que un command puede usar allowed-tools: Task para que el modelo lance un subagent, pero tenías que describir dentro del prompt "lanza un subagent Explore que haga...".
Un skill lo resuelve con una sola línea de frontmatter:
---
name: deep-research
description: Investigación profunda sobre un símbolo
context: fork
agent: Explore
---
Investiga todos los usos de $ARGUMENTS:
- todos los puntos de llamada
- escenarios de negocio
- implementaciones alternativas
Devuelve un resumen de ≤300 palabras.
Al disparar /deep-research SomeClass: todo el SKILL.md se convierte en el prompt de un subagent independiente, se ejecuta con el agent type Explore y, cuando termina, solo devuelve la conclusión. El context de la conversación principal queda totalmente limpio.
Esto equivale a convertir "lanzar un subagent" de una descripción dentro del prompt en un atributo declarativo del skill.
paths: auto-activación por tipo de archivo---
name: rails-conventions
description: Convenciones de código del proyecto Rails
paths: ["app/**/*.rb", "config/**/*.rb"]
---
Sigue las convenciones Rails de este proyecto:
- usa service objects en vez de fat controllers
- los scopes de ActiveRecord deben tener nombre
...
Mientras editas app/models/user.rb, este skill entra al context automáticamente; al editar package.json, no. Más preciso que el fondo global de CLAUDE.md: piénsalo como "un CLAUDE.md por capas según la ruta".
/plan a skillEl ejemplo /plan del post anterior era originalmente un command de un solo archivo:
.claude/commands/plan.md
Convertido a skill:
.claude/skills/plan/
├── SKILL.md
├── research-prompt.md # instrucciones del subagent 1
└── risk-prompt.md # instrucciones del subagent 2
SKILL.md:
---
name: plan
description: Generar un plan de implementación a partir de un ticket de Linear
disable-model-invocation: true
allowed-tools: mcp__linear__*, Task, Read, Grep, Bash(git log:*)
---
## Contexto
@.claude/context/architecture.md
## Estado
!`git log --oneline -10`
## Tarea
Trae la descripción y los comentarios del ticket de Linear $ARGUMENTS.
Usa Task para lanzar dos subagents en paralelo:
1. Investigación de código: prompt en [research-prompt.md](research-prompt.md)
2. Evaluación de riesgos: prompt en [risk-prompt.md](risk-prompt.md)
Combina los dos resultados y produce los pasos de implementación + lista de riesgos + sugerencia de granularidad de commit.
Los prompts de los dos subagents viven en archivos separados, así que al mantenerlos modificas uno sin tocar SKILL.md. El skill en sí queda limpio en menos de 30 líneas, mientras los archivos auxiliares pueden extenderse en cientos de líneas de detalle cada uno.
Si no quieres orquestar tú los subagents, puedes ir más lejos: meter todo el skill en un fork y dejar que un agent Explore lo ejecute de una pasada:
---
name: plan
context: fork
agent: Explore
allowed-tools: mcp__linear__*
---
Disparas /plan ENG-4213 → un agent Explore en su propio context recibe todo el contenido de SKILL.md como tarea → solo devuelve el plan final. La conversación principal queda intacta.
No todos los commands merecen un ascenso. Quedarse en .claude/commands/ es más apropiado cuando:
Un /commit o /pr-desc sencillo es frontmatter + unas líneas de prompt: ponerlo en .claude/commands/ es incluso más directo. La postura oficial es clara: las dos formas conviven y ninguna será deprecada.
La organización más limpia hoy dentro de .claude/:
.claude/
├── commands/ # ligero: un archivo + prompt simple
│ ├── commit.md
│ └── pr-desc.md
├── skills/ # pesado: multi-archivo / fork / control de permisos
│ ├── plan/
│ │ ├── SKILL.md
│ │ ├── research-prompt.md
│ │ └── risk-prompt.md
│ ├── deploy/
│ │ └── SKILL.md # disable-model-invocation
│ └── rails-conventions/
│ └── SKILL.md # auto-activación por glob de paths
└── context/
└── coding-standards.md
No migres todo de golpe. El disparador de la migración es "este command empezó a engordar": el cuerpo pasa de las 200 líneas, hay que separar documentos, quieres que lo ejecute un subagent. Cuando llegue ese día, cambiar la ruta son unos minutos.
| Capacidad deseada | commands/ |
skills/ |
|---|---|---|
| Atajo de prompt en un solo archivo | sí | sí |
!`command` / @file / $ARGUMENTS |
sí | sí |
Control de permisos allowed-tools |
sí | sí |
| Archivos de soporte (references, scripts) | no | sí |
disable-model-invocation contra disparos accidentales |
no | sí |
Ejecución aislada con context: fork + agent: |
no | sí |
Auto-activación por glob en paths: |
no | sí |
En las tres primeras, commands y skills son equivalentes; las últimas cuatro son exclusivas de skills. Usa la forma que te haga falta.
La dirección oficial se inclina hacia skills, pero la promesa de compatibilidad para commands/ es explícita: no se trata de "migra ya o quedas fuera", sino de "nuevas capacidades disponibles, pero sin imposición". Entiende la diferencia, migra cuando lo necesites y no persigas una prolijidad cosmética.